20

I'm trying to create and deploy a smart contract through NodeJS using web3, but it is not working as I get a "web3.eth.contract.new is not a function". Here is my code:

var web3 = require('ethereum.js');

var solc = require('solc');


web3.setProvider(new web3.providers.HttpProvider('http://localhost:8101/'));

var input = 'contract Hello{ string h = "hello"; function g() constant returns(string){ return h; } }';
var output = solc.compile(input, 1);


for (var contractName in output.contracts) {


    var bc = output.contracts[contractName].bytecode;
    var abi =  output.contracts[contractName].interface;


    var contact = web3.eth.contract.new(abi,{from: web3.eth.accounts[0], data: bc});


    if (typeof contact.address !== 'undefined') {
         console.log('Contract mined! address: ' + contact.address + ' transactionHash: ' + contact.transactionHash);
    }

}

Any idea on how to solve this issue? Thanks in advance.

17

Here is my deploy script that also handles waiting until the transaction is included in a block:

// Copyright 2017 https://tokenmarket.net - MIT licensed
//
// Run with Node 7.x as:
//
// node --harmony-async-await  deploy.js
//

let fs = require("fs");
let Web3 = require('web3'); // https://www.npmjs.com/package/web3

// Create a web3 connection to a running geth node over JSON-RPC running at
// http://localhost:8545
// For geth VPS server + SSH tunneling see
// https://gist.github.com/miohtama/ce612b35415e74268ff243af645048f4
let web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

// Read the compiled contract code
// Compile with
// solc SampleContract.sol --combined-json abi,asm,ast,bin,bin-runtime,clone-bin,devdoc,interface,opcodes,srcmap,srcmap-runtime,userdoc > contracts.json
let source = fs.readFileSync("contracts.json");
let contracts = JSON.parse(source)["contracts"];

// ABI description as JSON structure
let abi = JSON.parse(contracts.SampleContract.abi);

// Smart contract EVM bytecode as hex
let code = '0x' + contracts.SampleContract.bin;

// Create Contract proxy class
let SampleContract = web3.eth.contract(abi);

// Unlock the coinbase account to make transactions out of it
console.log("Unlocking coinbase account");
var password = "";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  console.log(e);
  return;
}


console.log("Deploying the contract");
let contract = SampleContract.new({from: web3.eth.coinbase, gas: 1000000, data: code});

// Transaction has entered to geth memory pool
console.log("Your contract is being deployed in transaction at http://testnet.etherscan.io/tx/" + contract.transactionHash);

// http://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// We need to wait until any miner has included the transaction
// in a block to get the address of the contract
async function waitBlock() {
  while (true) {
    let receipt = web3.eth.getTransactionReceipt(contract.transactionHash);
    if (receipt && receipt.contractAddress) {
      console.log("Your contract has been deployed at http://testnet.etherscan.io/address/" + receipt.contractAddress);
      console.log("Note that it might take 30 - 90 sceonds for the block to propagate befor it's visible in etherscan.io");
      break;
    }
    console.log("Waiting a mined block to include your contract... currently in block " + web3.eth.blockNumber);
    await sleep(4000);
  }
}

waitBlock();
  • Full code can be find here ethereum-transaction-toy.tokenmarket.net – Mikko Ohtamaa Jan 5 '17 at 5:31
  • Thank you so much for this! Can you please explain how do you get the file contracts.json from the contract source code? – jeff Mar 8 '17 at 23:13
  • @jeff Compiling with Solidity solc. See the full tutorial link in the blog post. – Mikko Ohtamaa Mar 9 '17 at 13:56
  • This gives me TypeError: web3.eth.contract is not a function – Stepan Yakovenko Jul 28 '17 at 19:58
  • @MikkoOhtamaa In the blog tutorial you create a private key and its corresponding address. I don't see you using it in deploying the contract. How to use that external private key based address to deploy the contract? – Shabahat M. Ayubi Sep 11 '17 at 11:40
6

Before starting: Make sure eth and personal APIs are enabled on your node. For geth you do that with these switches: --rpcapi eth,personal

Here is how I did it with web3.js version 1.0:

const Web3 = require('web3');
const solc = require('solc');

// For localhost
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

let source = 'contract Hello{ string h = "hello"; function g() constant returns(string){ return h; } }';

let helloCompiled = solc.compile(source, 1).contracts[':Hello'];

You may need to unlock the address which is going to deploy the contract (Make sure there is enough funds on this address):

web3.eth.personal.unlockAccount(<address>, <password>).
    then(() => { console.log('Account unlocked.'); }).
    catch(console.error);

let Hello = new web3.eth.Contract(JSON.parse(helloCompiled.interface), null, { 
    data: '0x' + helloCompiled.bytecode 
});

OPTIONAL: Use average gas price to deploy (If you use too low gas price, the transaction may get stuck):

web3.eth.getGasPrice().
   then((averageGasPrice) => {
       console.log("Average gas price: " + averageGasPrice);
       gasPrice = averageGasPrice;
   }).
   catch(console.error);

Estimate gas to deploy:

Hello.deploy().estimateGas().
    then((estimatedGas) => {
        console.log("Estimated gas: " + estimatedGas);
        gas = estimatedGas;
    }).
    catch(console.error);

And finally deploy:

Hello.deploy().send({
    from: <address>,
    gasPrice: gasPrice, 
    gas: gas
}).then((instance) => { 
    console.log("Contract mined at " + instance.options.address);
    helloInstance = instance; 
});
5

See the API documentation for contract.

You're passing the abi variable as a parameter to .new(), whereas you should be passing it to the contract() method itself. In your code, the contract method isn't being passed anything, which is why it's complaining.

var MyContract = web3.eth.contract(abiArray);

var contractInstance = MyContract.new([contructorParam1] [, contructorParam2], {data: '0x12345...', from: myAccount, gas: 1000000});

Related thread: What are the arguments to `new` from a contract object?

  • 1
    Hey, thanks for your reply. However: var MyContract = web3.eth.contract(abi); var contract = MyContract.new({from: web3.eth.accounts[0], data: bc}); returns the same error: MyContract.new is not a function. – Daniel Catita Jul 21 '16 at 8:57
  • Are you following a particular tutorial for this? – Richard Horrocks Jul 21 '16 at 14:17
  • Several, not one in particular as none seemed to work. However, thanks to another user I got rid of that error replacing the var web3 = require('ethereum.js'); with var Web3 = require('web3'); var web3 = new Web3(); A new problem arised: address of the contract stays undefined, even though a transaction is mined. – Daniel Catita Jul 21 '16 at 14:22
  • You should use callback function to check the contract address. Because your next lines of code will not wait for the completion of deployment process.And that's why you are getting undefined every time. – Aniket Sep 14 '16 at 7:35
1

For web3js > 1.0 you can use : myContract.deploy(options)

const contract = new web3.eth.Contract(abi);
    contract.deploy({
      data: code,
    })
    .send({
      from: "0x1234567890123456789012345678901234567891",    gas: 1500000,
        gasPrice: '30000000000000'
    }).then(function(newContractInstance){
        console.log(newContractInstance.options.address) // instance with the new contract address
    });

Where code is the bytecode and the used address should be unlocked

0

Yes, you must use web3.eth.contract(abi) to create an object, and then call new() on it passing the proper data to the transaction. The way you're doing, you're pretending the web3.eth.contract function itself has a new() property, while its the result of that function call which actually is an object with a new() function.

Also, contact is a typo or is the proper name of your contRact? Ill suppose is a typo:

var contract = web3.eth.contract(abi);

var contractInstance = contract.new(parameters , {data : bc , from : anAddress... etc});

That would work, would 'bc' var being the result of

web3.eth.compilers.solidity(input);

However, I never used the solc package, and I don't know if bc var is actually the exact thing you must pass on as data to the new() call. But I'm pretty sure this will help you, as your main problem is trying to call new() directly on web3.eth.contract function and not in its instance.

EDIT:

web3 methods can fail if you're doing

var web3 = require('web3');

or similar stuff. The proper way to instantiate web3 is:

var Web3 = require('web3');
var web3 = new Web3();  

Then, the new() function should work properly.

  • Hey, thanks for your reply. However: var MyContract = web3.eth.contract(abi); var contract = MyContract.new({from: web3.eth.accounts[0], data: bc}); returns the same error: MyContract.new is not a function. – Daniel Catita Jul 21 '16 at 8:58
0

Be aware that the web3 API has changed since version 1~beta

You can use a library that encapsulates the complexity of the whole process: https://github.com/ledfusion/eth-tx

$ npm install eth-tx

On NodeJS:

const ethTx = require("eth-tx");

Compile:

const { compileTo } = ethTx;
const source = __dirname + "/contract-main.sol";
const destination = __dirname + "../build/data.js";

compileTo(source, destination, {})
    .then(() => { /* ... */})
    .catch(err => console.log("Error", err));

Connect:

ethTx.connect("http://localhost:8545").catch(console.log);

Deploy the contract:

const { wrapContract } = ethTx;

const abi = [...];   // from "../build/data.js
const byteCode = "0x12345...";

const MyContract = wrapContract(abi, byteCode);

MyContract.new("parameter-1", "parameter-2")
    .then(myContractInstance => {
        console.log("Deployed on", myContractInstance.$address);

        // ...
    })
    .catch(err => console.log("Error", err));

Send your transactions:

const options = {};
myContractInstance.setHash("param-1", "param-2").send(options)
    .then(transaction => {
        console.log("Transaction", transaction);

        // ...
    })
    .catch(err => console.log("Error", err));

Hope it helps!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.