There’s a variety of reasons you might want to know the maximum possible integer in solidity.
One common use case is to approve a contract to transfer your tokens on your behalf:
tokenContract.approve(exchangeContract, MAX_INT, { from: me })
Here I tell the token contract that the exchange contract is allowed to transfer all my tokens.
Another common use case is to use the maximum number to flag a certain state - though in cases like this you should be careful of ‘semantic overloading’.
Whatever the situation you’re trying, how do you actually get the maximum integer in solidity? I can think of 4 main ways:
1) Just type in the number!
uint256 MAX_INT = 115792089237316195423570985008687907853269984665640564039457584007913129639935
I think we can all agree doing that looks somewhat ridiculous and comes with significant risk that you’ll get the number wrong. As someone reading the contract it would be quite hard to understand what the number really is either.
2) Use the hex version of the number
uint256 MAX_INT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
This method has the advantage that its pretty clear what you’re achieving - it’s commonly known that a string of Fs tends to be the maximum possible number in some number of bits. However it’s hard to be sure with this method you’ve actually got all 64 Fs, and is fairly common to see people using a string with too few.
3) Casting -1
uint256 MAX_INT = uint256(-1)
This method is short to write, and unlike the previous 2 methods its easy to check you’ve got it correct. However the fundamental reason this method works is due to underflowing a calculation, which is generally looked upon as a negative thing to do and to me feels a bit hacky.
One thing to beware of with this method is a new proposal to build SafeMath into Ethereum by default, meaning that underflows and overflows would become impossible. Although this isn’t fully designed yet, it’s likely that uint256(-1)
could throw an error.
4) Using exponentiation
uint256 MAX_INT = 2**256 - 1
This is my personal favourite due to the clarity of what it is you’re calculating. It’s a more expensive calculation than uint256(-1), however if you store MAX_INT
as a constant, it will only need be calculated once during compilation.
This method can easily be mistaken for an overflow - after all it first calculates 2**256 which would need 257 bits to store (larger than can be stored in solidity). However because this is just an intermediate result that does not get stored in a variable, the value does not overflow and - 1
is calculated safely bringing the value back into 256 bits.
This post certainly doesn’t cover everything, so I’d love to hear if people have other pros/cons of the methods above or new methods entirely! Which is your preferred method? Should we add this constant to OpenZeppelin contracts to try to standardize it?