3

If I wanted a smart contract to only accept Ether payments in multiples of for example 0.05 Ether (so it will accept only exactly 0.05 Ether, 0.1 Ether, 0.15 Ether etc, and send the value back to the sender for anything else) what is the cleanest way of doing this?

3

For an updated version use the following:

//0.05 ether
uint256 multipleOf = 0.05 ** 18;

modifier isMultiple(){
   require(msg.value % multipleOf == 0);
   _;
}

Then add the modifier to each function requiring this.

function foo() 
public 
isMultiple 
{
 //will only come here if value is a multiple

}
1

Use the modulo operator like this:

uint256 remainder = msg.value % 50000000000000000;
msg.sender.send(remainder);

Haven't tested it but it should work. The modulo operator divides by the amount you want and gives you the remainder.

  • This works good, IMO using transfer instead of send could be a better approach as in case of failure send returns false whereas transfer throws exception thus reverting the changes. – Prashant Prabhakar Singh Sep 28 '17 at 12:19
1

Here is a code snippet to get only multiple of one ether(like 1eth, 2eth,..). You can customize it to suit your purpose:

function participate() payable{ 
    uint256 amount = msg.value/(10**18);
    uint256 decimalPart = msg.value%(10**18);
    // tarnsfer the decimal points back to user
    msg.sender.transfer(decimalPart);
    // use the amount as you want.
 }
1
 function() payable{
        require(msg.value%50000000000000000==0);
    }

Note that since msg.value denotes the amount of ether in wei, therefore you need to take modulo 50000000000000000, since this amount of wei represents 0.05 ether.

  • 1
    The OP is asking about sending the remaining value back to the user. This piece of code will consume all gas if the user does not provide multiple of x (x be any value). Also note, throw is deprecated, use require instead. – Prashant Prabhakar Singh Sep 28 '17 at 12:09
  • 1
    Thanks! Corrected! I interpreted the question in a way, that all the non-compliant amounts should be sent back. – István András Seres Sep 28 '17 at 12:12
1

I noticed most of the answers use require. That will reject any non-conforming amount. The OP wanted to carry on but return the change.

This snippet is aiming for readability so probably isn't optimal for gas. It's important to to do the transfer for returning the change last to avoid creating a re-entrance vulnerability.

pragma solidity 0.5.1;

contract ReturnTheChange {

    uint smallestUnit = 5 * 10 ** 16;

    function sendFunds() public payable {
        uint sentBase;
        uint returnChange;
        (sentBase, returnChange) = calculateAmounts(msg.value);
        // do something with sentBase
        // emit event
        // LAST THING;
        msg.sender.transfer(returnChange);
    }

    function calculateAmounts(uint grossAmount) public view returns(uint base, uint change) {
        uint changeToReturn = grossAmount % smallestUnit;
        uint baseAmount = grossAmount - changeToReturn;
        return(baseAmount, changeToReturn);
    }
}

Hope it helps.

  • 1
    On rereading im less convinced the OP wants to accept noncomforming amounts. That was my interpretation. – Rob Hitchens - B9lab Dec 14 '18 at 21:16

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.