Skip to content
This repository has been archived by the owner on Sep 13, 2024. It is now read-only.

How to pass parameters to Contract Method? #3

Closed
johanazu7 opened this issue Jan 26, 2018 · 9 comments
Closed

How to pass parameters to Contract Method? #3

johanazu7 opened this issue Jan 26, 2018 · 9 comments

Comments

@johanazu7
Copy link

Hello, I would like to know how to correctly pass parameters to a Contract method:

If I have a Contract method that looks like this (Solidity):

  function transfer(address _to, uint256 _value) public {
    require(_to != 0x0);
    ....
    // Trigger event
    Transfer(msg.sender, _to, _value);
  }

How can I pass the parameters for _to and _value params?

I'm trying something like this:

var options = Web3Options()
let web3 = Web3.InfuraRinkebyWeb3(accessToken: "...")
let contract = web3.contract(contractABI, at: "...")
let parameters = [EthereumAddress(to), String(value)] as [AnyObject] // Is this Correct?
let transaction = contract?.method("transfer", parameters: parameters, options: options)
...
// Code to sign transaction
guard let nonce = web3.eth.getTransactionCount(address: options.from!) else { return }
try! transaction?.setNonce(nonce)
try! transaction?.sign(privateKey) // privateKey is Data hex
// SEND
let result = transaction?.sendSigned()

But apparently there's something wrong, because the Transaction won't go through, and I get error:

["id": 1517001597, "result": 0x25, "jsonrpc": 2.0]

This didn't happen with contract method with no params.
How can I send the params array correctly?

Thank you guys!

@gfarinelli
Copy link

Have the same issue here. Could you please update example and show how to send arguments to contract function w/params that changes state.
Saying hello from Argentina,

@shamatar
Copy link
Contributor

Hello everyone.

I'm preparing a cleanup to simplify and streamline sending transactions to smart contracts, will be committed soon.

In a meantime you should follow the same way as in example, where sending ETH to wallet is done by providing an ABI and calling a contract methond. You should not need to set nonce manually, it's done under the hood.

                let web3Rinkeby = Web3.InfuraRinkebyWeb3()
                web3Rinkeby.addKeystoreManager(keystoreManager)
                let coldWalletABI = "[{\"payable\":true,\"type\":\"fallback\"}]"
                options = Web3Options.defaultOptions()
                options.gas = BigUInt(21000)
                options.value = BigUInt(1000000000000000)
                options.from = sender
                let estimatedGas = web3Rinkeby.contract(coldWalletABI, at: coldWalletAddress)?.method(options: options)?.estimateGas(options: nil)
                options.gas = estimatedGas
                let intermediateSend = web3Rinkeby.contract(coldWalletABI, at: coldWalletAddress)?.method(options: options)
                res = intermediateSend?.send(password: "BANKEXFOUNDATION")

If you attached a keystore manager to the web3 instance you just need to provide a password and sender address, although public methods exist to sign a "transactionIntermediate" or just a plain transaction after it's assembled.

Sincerely, Alex

@jlstr
Copy link

jlstr commented Jan 27, 2018

Hello there!

I'm glad I can join the party. I think that what previous commenters pointed out is correct, I just stumbled upon a very similar problem:

THIS WORKS:

pragma solidity ^0.4.17;

contract Count {
  uint8 counter;

  function getCounter() public constant returns(uint8) {
    return counter;
  }

  function increaseCounter() public {
    counter += 1;
  }
}

Straight forward to call in web3swift:

// Most configuration code omitted to simplify
let contract = web3.contract(contractABI, at: EthereumAddress("..."))
let tx = contract?.method("increaseCounter", parameters: [], options: options)
//
// SEND Tx code Omitted

THIS DOES NOT WORK:

pragma solidity ^0.4.17;

contract Count {
  uint8 counter;
  // Code omitted ...
  
  function increaseCounter(uint8 _value) public { // Now function takes an argument
    counter += _value;
  }
}

Now, using web3swift my first instinct, (like I believe the other commenters did), was to pass the function argument in the parameters: param of the function:

// Most configuration code omitted to simplify
let contract = web3.contract(contractABI, at: EthereumAddress("..."))
let tx = contract?.method("increaseCounter", parameters: [Int(1)] as [AnyObject], options: options)
//
// Sign/Send Tx code Omitted

This returns the error the original commenter posted.
So, I guess there's a bit of confusion in here, (maybe I need to know web3js a bit better), but If in the meantime you could show us what's the easiest way to pass arguments to contract functions that take parameters, I'd deeply appreciate it! (from the sample you posted it's still not very clear... to me, at least...)

How would you call the method above using web3swift? it has this 'piece' of ABI:

{
    "constant": false,
    "inputs": [
      {
        "name": "_value",
        "type": "uint8"
      }
    ],
    "name": "increaseCounter",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },

Regardless, This is fantastic work!
Cheers!

@shamatar
Copy link
Contributor

@jlstr Thank you for a great feedback.

I'll look closer on this issue and provide better example as soon as it's fixed. Hope to be done on Monday.

Sincerely, Alex

@johanazu7
Copy link
Author

johanazu7 commented Jan 28, 2018

@shamatar current version does not allow passing arguments to contract func? is this correct?
I glad this issue is common, I don't see in example posted here how to pass argument to contract function. In my case I would like to pass _to and _value for transfer(address _to, uint256 _value) ERC20 function. How does that look like in current version?

Kindly,
-Johana

@shamatar
Copy link
Contributor

The purpose of this library is to support everything web3js supports.

I've found a problem with uint8, uint16, etc encoding (less than uint256), should be fixed in 0.2.9

Here is an example

                let testABIonRinkeby = "[{\"constant\":true,\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_value\",\"type\":\"uint8\"}],\"name\":\"increaseCounter\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"
                let deployedTestAddress = EthereumAddress("0x1e528b190b6acf2d7c044141df775c7a79d68eba")
                options = Web3Options.defaultOptions()
                options.gas = BigUInt(100000)
                options.value = BigUInt(0)
                options.from = ks?.addresses![0]
                let testParameters = [BigUInt(1)] as [AnyObject]
                estimatedGas = web3Rinkeby.contract(testABIonRinkeby, at: deployedTestAddress)?.method("increaseCounter", parameters: testParameters, options: options)?.estimateGas(options: nil)
                options.gas = estimatedGas
                let testMutationResult = web3Rinkeby.contract(testABIonRinkeby, at: deployedTestAddress)?.method("increaseCounter", parameters: testParameters, options: options)?.send(password: "BANKEXFOUNDATION")
                
                print(testMutationResult)

The contract itself is simple

pragma solidity ^0.4.19;

contract Count {
  uint8 public counter;
  
  function Count() public {
      
  }
  
  function increaseCounter(uint8 _value) public {
    counter += _value;
  }
}

deployed in Rinkeby at

0x1e528b190b6acf2d7c044141df775c7a79d68eba

@johanazu7
Copy link
Author

Much grateful for this Alex. I will test.
In order to test EthereumAddress param, I do:

let testParameters = [EthereumAddress(".....")] as [AnyObject]

will it be correct?
Kindly,
-Johana

@shamatar
Copy link
Contributor

Hello Johana.

Yes, parameters are encoded in order of their appearance in array and it should correspond to their order in Solidity function (no support for named parameters yet), so if you need to pass only one parameter to the function - your way is correct. Please check an example of obtaining ERC20 balance for particular address in Example.

Sincerely, Alex

@johanazu7
Copy link
Author

Much Grateful for this, Alex. It's working as expected! 👌😃 I hope I can continue asking question as you make progress with this cool library.

Kind Regards,
-Johana

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants