8

I understand that you can send ethereum to a smart contract, although when you do this with sendTransaction it doesn't seem that you specify a function on the smart contract when you do this. I don't quite understand how this is useful. However what I can't find out how to do, is to send ethereum to a function that is set as payable. I'm using ethers.js and can create a contract, and call functions that are viewable (read only) no problem, but I cant work out how to send ethereum with the transaction to a specific function

export const testContract = async (address, abi) => {
  const wei = Utils.parseEther("0.1")
  const url = "http://localhost:8545"
  const provider = new Providers.JsonRpcProvider(url)
    // Load the wallet to deploy the contract with
  const privateKey =
    "0x123"
  const wallet = new Wallet(privateKey, provider)

  var contract = new Contract(address, abi, wallet)

  const price = await contract.retrievePrice()
  console.log("price " + price) //logs the price set in the constructor when the contract was made (WORKS)
  const testAddress = await contract.isUser(
    "0x456"
  )
  console.log("testAddress ", testAddress) //checks if the given address is a user on the contract (WORKS)

  const gasPrice = await provider.getGasPrice()
  console.log("gas price: ", gasPrice.toString()) //returns the price of gas from the network (WORKS)
  try {
    const addToUsers = await contract.requestAccess({ //call function to request access, from the current wallet (REVERTS)
      value: wei
    })
    console.log("result of sending transaction ", addToUsers)
  } catch (error) {
    console.log("error.... ", error) //fires as the contract reverted the payment
  }
}

Any help as to why calling contract.requestAccess is reverting on me? I can't quite work out how to call a specific function and send Ether. Thanks!

Response to comment

Ok right, so the function in the solidity contract looks like:

  function requestAccess() payable {
    require(msg.value == price, "Incorrect sum sent to contract");
    _addUser(msg.sender);
  }

I commented out the require, to try that but still reverts. _addUser is from a contract mine inherits from, and looks like

  function _addUser(address account) internal {
    users.add(account);
    emit UserAdded(account);
  }

users is Roles.Role private users; and sits in the parent contract

contract Users {
  using Roles for Roles.Role;

which imports from openzeppelin "openzeppelin-solidity/contracts/access/Roles.sol"

5
  • 1
    Since it is the EVM code that is reverting, it means you are able to interact with the contract and so the problem is partly due to the contract code. Could you share with us the code of the requestAccess function ? Oct 29, 2018 at 20:20
  • Hi, thanks for responding, i have edited the question to answer yours!
    – amlwwalker
    Oct 29, 2018 at 20:34
  • After testing, i added an anonymous function to the contract and tried sending 0.1 ether from metamask (same account as the one the code is using) and it worked fine. So its' something to do with my ethers syntax.....
    – amlwwalker
    Oct 29, 2018 at 20:57
  • Could you try to also comment out the users.add(account) and keep only the emit event ? This way we'll know for sure that the issue is not related to Solidity but to ethers.js Oct 29, 2018 at 21:50
  • right, your implicit suggestion that it was the solidity code made me keep looking. I actually cant be sure what fixed it right now, but the transaction is going through now. I don't know why. It probably was as a result of changing both the solidity and the ethers code since i posted the question. If I work out why I won't leave you hanging! THANKS
    – amlwwalker
    Oct 29, 2018 at 22:21

3 Answers 3

8

You may notice in the comments, I was unable to work out what wasn't working for me, but not a fan of "it works, thanks" answers which don't help others. So I have put a working example up on gists for anyone who is looking for this. Just need to make some changes to be specific to your situation, but should be relatively straight forward. https://gist.github.com/amlwwalker/89bc2c5a2b631527bb7def922b4c8306

5

Quote from https://github.com/ethers-io/ethers.js/issues/563

let overrides = {
    // To convert Ether to Wei:
    value: ethers.utils.parseEther("1.0")     // ether in this case MUST be a string

    // Or you can use Wei directly if you have that:
    // value: someBigNumber
    // value: 1234   // Note that using JavaScript numbers requires they are less than Number.MAX_SAFE_INTEGER
    // value: "1234567890"
    // value: "0x1234"

    // Or, promises are also supported:
    // value: provider.getBalance(addr)
};

// Pass in the overrides as the 3rd parameter to your 2-parameter function:
let tx = await exchangeContract.ethToTokenSwapOutput(tokens_bought, deadline, overrides);
2

I Haven't tried the code but anytime you want send ether along with a method, you need to "override" it

Const overrides = {
      value: ethers.utils.parseEther("1.0"), //sending one ether  
      gasLimit: 30000 //optional

}

//call your payable method using and use the override as a parameter
await contract.requestAccess( overrides )

In the overrides object you can insert several things such as gasLimit

overrides.from - the msg.sender (or CALLER) to use during the execution of the code

overrides.value - the msg.value (or CALLVALUE) to use during the exectuiont of the code

overrides.gasPrice - the price to pay per gas (theoretically); since there is no transaction, there is not going to be any fee charged, but the EVM still requires a value to report to tx.gasprice (or GASPRICE); most developers will not require this

overrides.gasLimit - the amount of gas (theoretically) to allow a node to use during the execution of the code; since there is no transaction, there is not going to be any fee charged, but the EVM still processes gas metering so calls like gasleft (or GAS) report meaningful values

overrides.blockTag - a block tag to simulate the execution at, which can be used for hypothetical historic analysis; note that many backends do not support this, or may require paid plans to access as the node database storage and processing requirements are much higher

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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