Does SafeMath library need a Safe power function?

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.

2 Likes

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) }
        }
    }
}
1 Like

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?

1 Like

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().

2 Likes

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.

1 Like

Hey, I’m sorry but I’ve never did this kind of stuff on-chain

1 Like

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;
        }
    }
2 Likes

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.

2 Likes

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).

1 Like

@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));
1 Like

Hi @drbullock,

You would need to check for overflows with this calculation. I would recommend appropriate testing and auditing of this.

1 Like