calling smart contracts methods using web3 ethereum
Asked Answered
T

5

12

Trying to work around the blockchain using Ethereum, I'm facing problems when trying to interface with a deployed contract. What I would try to achieve is to call a method to display information added to a private blockchain deployed locally using Geth.

I can't call any function from my smart contract and I've been wondering if I'm doing something wrong... Could someone tell me how to achieve a simple call to one of the method from this contract? let say display the existing agencies, or the agency name from which the user is part of.

My contract: agency.sol

pragma solidity ^0.4.18;
// We have to specify what version of compiler this code will compile with

contract Agency {

  event NewAgency(uint agencyId, string name, uint dna);

  uint dnaDigits = 16;
  uint dnaModulus = 10 ** dnaDigits;

  //agency structure
  struct Agency {
    string name;
    uint dna;
  }

  Agency[] public agencies;

  mapping (uint => address) public agencyToOwner;
  mapping (address => uint) ownerAgencyCount;

  function _createAgency(string _name, uint _dna) private {
    uint id = agencies.push(Agency(_name, _dna)) - 1;
    agencyToOwner[id] = msg.sender;
    ownerAgencyCount[msg.sender]++;
    NewAgency(id, _name, _dna);
  } 

  function _generateRandomDna(string _str) private view returns (uint) {
    uint rand = uint(keccak256(_str));
    return rand % dnaModulus;
  }

  function createRandomAgency(string _name) public {
    //make sure contract can only execute if user is not part of an agency
    require(ownerAgencyCount[msg.sender] == 0);
    uint randDna = _generateRandomDna(_name);
    _createAgency(_name, randDna);
  }
}

the abiDefinition

> abiDefinition
[ { constant: true,
    inputs: [ [Object] ],
    name: 'agencies',
    outputs: [ [Object], [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: true,
    inputs: [ [Object] ],
    name: 'agencyToOwner',
    outputs: [ [Object] ],
    payable: false,
    stateMutability: 'view',
    type: 'function' },
  { constant: false,
    inputs: [ [Object] ],
    name: 'createRandomAgency',
    outputs: [],
    payable: false,
    stateMutability: 'nonpayable',
    type: 'function' },
  { anonymous: false,
    inputs: [ [Object], [Object], [Object] ],
    name: 'NewAgency',
    type: 'event' } ]

Successfully deployed:

INFO [01-09|19:09:14] Submitted contract creation              fullhash=0x7c43e896329138a6778938ca30d2f5f17f9a63062b359a4fccbd1a1be439f385 contract=0x65175d22C56E1Bad976A331A8B6B448cd4B3995d

and finally contractInstance:

> contractInstance = AgencyContract.at(0x65175d22C56E1Bad976A331A8B6B448cd4B3995d)
Contract {
  _eth: 
   Eth {
     _requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
     getBalance: { [Function: send] request: [Function: bound ], call: 'eth_getBalance' },
     getStorageAt: { [Function: send] request: [Function: bound ], call: 'eth_getStorageAt' },
     getCode: { [Function: send] request: [Function: bound ], call: 'eth_getCode' },
     getBlock: { [Function: send] request: [Function: bound ], call: [Function: blockCall] },
     getUncle: { [Function: send] request: [Function: bound ], call: [Function: uncleCall] },
     getCompilers: { [Function: send] request: [Function: bound ], call: 'eth_getCompilers' },
     getBlockTransactionCount: 
      { [Function: send]
        request: [Function: bound ],
        call: [Function: getBlockTransactionCountCall] },
     getBlockUncleCount: 
      { [Function: send]
        request: [Function: bound ],
        call: [Function: uncleCountCall] },
     getTransaction: 
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionByHash' },
     getTransactionFromBlock: 
      { [Function: send]
        request: [Function: bound ],
        call: [Function: transactionFromBlockCall] },
     getTransactionReceipt: 
      { [Function: send]
        request: [Function: bound ],
        call: 'eth_getTransactionReceipt' },
     getTransactionCount: { [Function: send] request: [Function: bound ], call: 'eth_getTransactionCount' },
     call: { [Function: send] request: [Function: bound ], call: 'eth_call' },
     estimateGas: { [Function: send] request: [Function: bound ], call: 'eth_estimateGas' },
     sendRawTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendRawTransaction' },
     signTransaction: { [Function: send] request: [Function: bound ], call: 'eth_signTransaction' },
     sendTransaction: { [Function: send] request: [Function: bound ], call: 'eth_sendTransaction' },
     sign: { [Function: send] request: [Function: bound ], call: 'eth_sign' },
     compile: { solidity: [Object], lll: [Object], serpent: [Object] },
     submitWork: { [Function: send] request: [Function: bound ], call: 'eth_submitWork' },
     getWork: { [Function: send] request: [Function: bound ], call: 'eth_getWork' },
     coinbase: [Getter],
     getCoinbase: { [Function: get] request: [Function: bound ] },
     mining: [Getter],
     getMining: { [Function: get] request: [Function: bound ] },
     hashrate: [Getter],
     getHashrate: { [Function: get] request: [Function: bound ] },
     syncing: [Getter],
     getSyncing: { [Function: get] request: [Function: bound ] },
     gasPrice: [Getter],
     getGasPrice: { [Function: get] request: [Function: bound ] },
     accounts: [Getter],
     getAccounts: { [Function: get] request: [Function: bound ] },
     blockNumber: [Getter],
     getBlockNumber: { [Function: get] request: [Function: bound ] },
     protocolVersion: [Getter],
     getProtocolVersion: { [Function: get] request: [Function: bound ] },
     iban: 
      { [Function: Iban]
        fromAddress: [Function],
        fromBban: [Function],
        createIndirect: [Function],
        isValid: [Function] },
     sendIBANTransaction: [Function: bound transfer] },
  transactionHash: null,
  address: 5.771290982673958e+47,
  abi: 
   [ { constant: true,
       inputs: [Array],
       name: 'agencies',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: true,
       inputs: [Array],
       name: 'agencyToOwner',
       outputs: [Array],
       payable: false,
       stateMutability: 'view',
       type: 'function' },
     { constant: false,
       inputs: [Array],
       name: 'createRandomAgency',
       outputs: [],
       payable: false,
       stateMutability: 'nonpayable',
       type: 'function' },
     { anonymous: false,
       inputs: [Array],
       name: 'NewAgency',
       type: 'event' } ],
  agencies: 
   { [Function: bound ]
     request: [Function: bound ],
     call: [Function: bound ],
     sendTransaction: [Function: bound ],
     estimateGas: [Function: bound ],
     getData: [Function: bound ],
     uint256: [Circular] },
  agencyToOwner: 
   { [Function: bound ]
     request: [Function: bound ],
     call: [Function: bound ],
     sendTransaction: [Function: bound ],
     estimateGas: [Function: bound ],
     getData: [Function: bound ],
     uint256: [Circular] },
  createRandomAgency: 
   { [Function: bound ]
     request: [Function: bound ],
     call: [Function: bound ],
     sendTransaction: [Function: bound ],
     estimateGas: [Function: bound ],
     getData: [Function: bound ],
     string: [Circular] },
  allEvents: [Function: bound ],
  NewAgency: { [Function: bound ] 'uint256,string,uint256': [Function: bound ] } }

I've tried:

contractInstance.agencies()
contractInstance.agencies.call()
contractInstance.agencies.call({from:ak})

results in Error: Invalid number of arguments to Solidity function

contractInstance.agencies.call("name" {from:ak})

results in Error: invalid address I also tried calling agencyToOwner and createRandomAgency but nothing works.

Any help would be gladly received! Thanks,

Thumping answered 10/1, 2018 at 10:12 Comment(0)
C
21

You can call contract functions by either using contract.methodName.call(), contract.methodName.sendTransaction(), or contract.methodName() methods. The last version simply delegates to one of the first two depending on the method type (ie, if it's a constant). See the Contract Methods section in the docs.

The parameter list starts with the parameters for the function itself (if any), followed by an optional transaction object, followed by the callback. To call your createRandomAgency() method, you would do this:

const contract = web3.eth.contract(contractAbi);
const contractInstance = contract.at(contractAddress);

const transactionObject = {
  from: fromAccount,
  gas: gasLimit
  gasPrice: gasPriceInWei
};

contractInstance.createRandomAgency.sendTransaction('name', transactionObject, (error, result) => { // do something with error checking/result here });

The list of available options for the transaction object can be found here.

To call your public agencies array, it would look like

contractInstance.agencies.call(0, (error, result) => {
  if (!error) {
    console.log(result.name);
    console.log(result.dna);
  }
}); // transaction object not needed
Crowned answered 10/1, 2018 at 18:7 Comment(1)
Note: This answer applies only before web3 1.0, which has a lot of breaking changes in the Contract object affecting how contract methods are called. web3js.readthedocs.io/en/1.0/web3-eth-contract.htmlHousewife
C
2

I think you should try something like this-:

 var contractAbi= "" //here put your contract abi in json string
 var deployedContract = web3.eth.contract(abi).at("contract address");
 //now you should be able to access contract methods
 deployedContract.agencies.call({from:address}, function(err,data){
 console.log(data);
 });

Test this out once.

Committeewoman answered 10/1, 2018 at 10:59 Comment(2)
still have Error: Invalid number of arguments to Solidity function after doing: var deployedContract = web3.eth.contract(abiDefinition).at("0x65175d22C56E1Bad976A331A8B6B448cd4B3995d"); deployedContract.agencies.call({from:web3.eth.accounts[0]},function(err,data){console.log(data);});Thumping
@Thumping Yes the error is correct. Since you have defined agencies as 'Agency[] public agencies'. The solidity complier will generate a public getter method like this one function agencies(uint256 index)public returns(string, uint); Since agencies is declared as array. The above method actually requires you to send the index as an argument. If you dont want that then you have to define the method and functionality by yourself.Committeewoman
D
2

It's 2022 now, and seems web3/contracts has some changes, so let me leave an answer here.

Assuming you are using truffle.

Step1. create a truffle project , and install a ganache network at your local machine.

Step2. create a contract and make it deployed. get its address and network (e.g. ganache )

truffle deploy --network=ganache

Step3. run the script file below by: truffle exec call.js --network=ganache

// Filename is:  call.js

// you need an address of the contract
const CONTRACT_ADDRESS = "0x7545eCD147210f38EF88142cd94f5Dd0C98E418D"
// you also need the abi of the contract
const contractJson = require('./build/contracts/VeryGoodNftWithMaxSupply.json')


module.exports = async function (callback) {
  // initialize the contract from web3, 
  const contract = new web3.eth.Contract( contractJson.abi, CONTRACT_ADDRESS );

  // get the network
  const network = await web3.eth.net.getNetworkType()

  // call the  `name` method. which is a view method.
  let result = await contract.methods.name().call()
  console.info("name: ", result)  

  // call the `mint` method. which need a TX operation,
  const tx = contract.methods.mint('0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A')

  // send this tx.
  const receipt = await tx
  .send({
    // used first account from your wallet. 
    from: (await web3.eth.getAccounts())[0],
    gas: await tx.estimateGas(),
  })
  .on('transactionHash', (txhash) => {
    console.log(`Mining transaction ... network: ${network}, tx: ${txhash}`)
  })
  .on('error', function(error){
    console.error(`An error happened: ${error}`)
    callback()
  })
  .then(function(receipt){
    // Success, you've minted the NFT. The transaction is now on chain!
    console.log(
        `Success: The NFT has been minted and mined in block ${receipt.blockNumber}`)
    callback()
  })

}

conclusion

for "view" function, you should use "call"

for the function which need an tx, you should use "send" and "once", "on"

for more details, please check this demo: https://github.com/sg552/test_erc721_in_truffle_ganache

also refer to:http://siwei.me/blog/posts/blockchain-web3-contract

Deoxidize answered 8/7, 2022 at 7:28 Comment(0)
Z
1

Try using callbacks or promises. The following code worked for me, when I wanted to get the return value from one of my contract's methods:

const contract = web3.eth.contract(contractABI);
const contractInstance = contract.at(this.contractAddress);

return new Promise((resolve, reject) => {
  contractInstance.**yourMethod**.call(function (error, result) {
    if (error) {
      console.log(error);
    } else {
      resolve(result);
    }
  });
}) as Promise<number>;

Also check out: https://github.com/ethereum/wiki/wiki/JavaScript-API#using-callbacks

Zaporozhye answered 22/7, 2018 at 16:51 Comment(0)
P
1

Currently (as in 2022) you have to execute in javascript.

contact.methods.methodName().call()

but if you want the method call to be executed as a transaction you have to run this command.

contact.methods.methodName(value).send()

Here is the source https://web3js.readthedocs.io/en/v1.7.4/web3-eth-contract.html#methods-mymethod-call

Purchase answered 16/7, 2022 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.