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?
5 Answers
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
}
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 ofsend
could be a better approach as in case of failuresend
returns false whereastransfer
throws exception thus reverting the changes. Commented Sep 28, 2017 at 12:19
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.
}
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.
-
1The 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, userequire
instead. Commented Sep 28, 2017 at 12:09 -
1Thanks! Corrected! I interpreted the question in a way, that all the non-compliant amounts should be sent back. Commented Sep 28, 2017 at 12:12
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.
-
1On rereading im less convinced the OP wants to accept noncomforming amounts. That was my interpretation. Commented Dec 14, 2018 at 21:16