Is it necessary to add a safe pow operation in the SafeMath library? such as pow(2,3)
, that is equal to 2**3
, I remember it has one ever.
It seems like a little complex to assure its safety.
Ohhh, I find it in the solidity doc.
The following example implements the power function by square-and-multiply.
{
function power(base, exponent) -> result {
switch exponent
case 0 { result := 1 }
case 1 { result := base }
default {
result := power(mul(base, base), div(exponent, 2))
switch mod(exponent, 2)
case 1 { result := mul(base, result) }
}
}
}
Hi @Skyge
Given that power can lead to an overflow and the purpose of the SafeMath library is to prevent overflow bugs by reverting transactions on overflow then there is an argument that for completeness it should be included, though this is likely balanced by need.
I had a look through the openzeppelin-solidity Issues and couldn’t see any requests for it, so perhaps there isn’t a current need.
Are you aware of any examples of someone using power in a smart contract?
I was trying to think of an example, the only time I have used power is setting up an initial supply of ERC20 tokens.
Do you think there is a need?
Yeah, before I came here, I have searched on the openzeppelin-solidity Issues, it does not have a similar question, so I come here.
I know a case that may need this operation, do you know the stable currency USDC, as a matter of fact, its decimals is 6
rather than 18
, so if we want to change 1 USDC
to 1 DAI
(or anything else token has 18 decimals), we should use amount.mul(10 ** 12)
, but it is the hard code, if some tokens use some strange decimals, we have to change our contract, so it is better to calculate it. So in this situation, I would like to compare difference decimals to calculate, so I need a function pow()
.
Just to clarify, is this something that you are working on or is it an example of where you think it could be used?
@bugduino is this an issue that you have come across dealing with different lending protocols?
Yeah, I am working on it.
Hey, I’m sorry but I’ve never did this kind of stuff on-chain
I write a function for my case, so should I make a PR to add it into the OpenZeppelin repo
function pow(uint256 base, uint256 exponent) public pure returns (uint256) {
if (exponent == 0) {
return 1;
}
else if (exponent == 1) {
return base;
}
else if (base == 0 && exponent != 0) {
return 0;
}
else {
uint256 z = base;
for (uint256 i = 1; i < exponent; i++)
z = mul(z, base);
return z;
}
}
I find a similar algorithm in DAI contract:
This famous algorithm is called "exponentiation by squaring"
If n is even, then x^n = (x^2)^(n/2).
If n is odd, then x^n = x * x^(n-1),
and applying the equation for even x gives
x^n = x * (x^2)^((n-1) / 2).
It’s O(log n), instead of O(n) for naive repeated multiplication.
but I am not sure whether it is suitable or not.
Exponentiation by squaring looks like a potential way to create a safe power though I don’t know if it would be the most efficient.
Yeah, recently, I found this is a common operation to calculate compound interest rate
in some DeFi projects, such as (base_interest) ** seconds
like in DSR token(wrapped DAI).
@Skyge @abcoathup
There is another case when I am trying to implement pow().
I am currently implementing chainlink, and in the price feed, we have the latest price and the decimals.
Maybe there is another way to calculate it, but currently stands like this to calculate the other pair from the price:
uint256 ten = 10;
uint256 otherPair = _amount.mul(_price).div(ten.pow(_decimals));
Hi @drbullock,
You would need to check for overflows with this calculation. I would recommend appropriate testing and auditing of this.