Solidity: usage of code designed on outdated pragma

By akohad Oct30,2022

[ad_1]

Introduction

Solidity is the programming language for implementing smart contracts on EVM-compatible platforms. New versions containing breaking changes regularly appear as it is developed at high speed.

However, solidity publishes breaking changes list and recommendations for pragma migration. It happens that pragma is migrated wrongly, and some functionality becomes broken.

Why is pragma migrated wrongly?

  • developers don’t get insight that the code relies on the old behavior
  • developers don’t understand the logic and provide unconscious fixes until the compiler stop showing warnings

For example, the UniSwap FullMath library is designed for solidity <0.8.0.
What are the common errors during migration to solidity ~0.8.0?

First of all, developers should notice lines 91–96:

inv *= 2 — denominator * inv; // inv and denominator are uint256

Wanted math underflow often happens there. However, in the solidity ~0.8.0, math overflows and underflows are prevented, and developers often miss it, so the code may return an unwanted exception.

Second, there is an uncompilable moment at line 64:

// Factor powers of two out of the denominator
// Compute the largest power of two divisors of the denominator
uint256 twos = -denominator & denominator;

It returns compilation exception with solidity ~0.8.0 compiler as unary operator “-” cannot be applied to type uint256. It is proposed developer to make the number signed integer. So the final migrated code may look so:

uint256 twos = uint256(-int256(denominator) & int256(denominator));
// is equal to
uint256 twos = uint256(-int256(denominator)) & denominator;

But both modifications are broken for denominator = 2**255. It happens so as MAX_INT256 = 2**255-1 and int256(2**255) = -2**255, so applying of unary operator “-” to int256(2**255) overflows int256 type.

Third, lines 80, 87, and 104:

It is not apparent if an overflow should be prevented there as math proof of the algorithm is not provided. So the actions may also be forgotten to be wrapped to unchecked block.

However, it is possible to check if an error is thrown at the lines via brief testing. And according to the examples below, overflow is expected there, so wrapping to unchecked block is needed.

mulDiv(2**253, 2**254, 2**255) causes overflow on line 104
mulDiv(2**253–2, 2**254–3, 2**255n-4) causes overflow on lines 80, 91–96
mulDiv(2**253–2, 2**254–3, 2**255n-4) causes overflow on lines 87, 91–96

Although all the points may be fixed properly, modification of Gas-efficient code is considered a bad idea.

The solution is separating code designed on outdated pragma to a separate library and then linking the target contract.

  • Move all hard-updatable logic to a library using an old solidity compiler
pragma solidity outdated;library Lib {
function foo(params) external/public pure? returns (types) {
*logic requires an old compiler version*
...
}
...
}
  • Create a library mockup with the same function signatures using actual pragma
pragma solidity actual;library LibMockup {
function foo(params) external pure? returns (types) {}
...
}
  • Import mockup library to target contract and use it where needed
pragma solidity actual;import "LibMockup";contract Target {
function func(params) public? pure? returns (types) {
...
results = LibMockup.foo(lib_params); ...
}
...
}
  • Configure HardHat to replace the mockup reference in the contract with the deployed library address in the environment configuration file
const LibFactory = await hardhat.ethers.getContractFactory("Lib")
const LibInstance = await LibFactory.deploy()
const ContractFactory = await hardhat.ethers.getContractFactory("Target", {
libraries: {
LibMockup: LibInstance.address,
},
})
const ContractInstance = await ContractFactory.deploy()

See the detailed working code example here.

In case of migrating Gas-efficient code to new pragma:

  • Remember! Force pragma migration may lead to an unexpected result
  • Carefully check each line, comparing it with the Breaking Changes list
  • Test migrated code thoroughly!

If you are unsure about what you are doing, use the guide above to avoid code modification.

Migrated code is not safe until a trusted audit company checks it!

New to trading? Try crypto trading bots or copy trading

[ad_2]

Source link

By akohad

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *