I am trying to write a simple smart contract that accepts a small constant fee of eth. I am using the _addr.transfer(fee) function and the 'fee' is set in the contract at time of construction. I am finding that, at least in the test suite, if no 'value: somewei' is included in the js function call, the transfer fails with a revert error. If I do include 'value: somewei', it overrides the 'fee' argument passed to the transfer() function. Why is this?

For example, the contract is set up as below:

address payable public wallet;
uint fee;
function collectFee() public payable {

If I make the call from the js test case with no value property as below, the transfer fails with a generic revert reason:

let result = await myContract.collectFee( { from: fromAccount } );

If I instead make the call with a value property, the transfer succeeds, but ignores the value set for 'fee' in the contract:

let result = await myContract.collectFee( { from: fromAccount, value: web3.utils.toWei('10', 'ether') } );

So, for instance, if I instantiate the contract with a value of 1 ether for 'fee', and make the call from js with a value of 10 ether, 10 ether are deducted from the callers account.

1 Answer 1


The 10 ether being sent from the caller is being stored within the contract its-self. It does not get sent to wallet until after you make the transfer call. This is why you are seeing 10 ether being deducted from the caller.

So, using your example, the caller sends 10 ether with the collectFee function call. The contract then has 10 ether. the transfer method is then called sending 1 ether to the wallet from the contract. Now the contract has 9 ether and the wallet has 1 ether.

If you want to limit the caller to only sending 1 ether you need to add a require statement. require(msg.value == 1 ether, "Value sent was greater than or less than one ether")

Also, you should not be using the transfer method. Instead you should be using (bool success, ) = wallet.call{value: fee}("")

More information about sending ether from within a contract here https://medium.com/coinmonks/solidity-transfer-vs-send-vs-call-function-64c92cfc878a

  • So I guess what you are saying is that when you invoke a payable function on a smart contract using web3; a.) You can't submit the request with no or 0 ether. b.) The ether submitted is then stored with the contract. ?
    – broadbear
    Commented Mar 1, 2022 at 17:07

Your Answer

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

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