Smart contract guidelines
This page provides a list of guidelines for third-party developers looking to deploy smart contracts onto the Ronin chain.
Checklist
The following is a checklist of recommendations that contracts from third parties should meet:
- Contract DOES NOT self-destruct.
- Contract DOES NOT “returnbomb” the callee.
- Contract is compatible with London EVM fork.
- DO NOT use TransparentUpgradeableProxy with OpenZeppelin v5.x.x.
- DO NOT use TransparentUpgradeableProxy with the openzeppelin-upgrades library.
- DO verify the contract's source code after deployment.
The following sections cover these recommendations in detail.
Recommendations
❌ Contract has "selfdestruct" instruction
The self-destruct function in Solidity allows a contract to be removed from the blockchain, freeing up storage and preventing it from consuming gas in the future. This function, however, can be misused by malicious actors to destroy a contract without permission, causing permanent loss of data and assets.
function destroy(address to) {
selfdestruct(to);
}
❌ Contract "returnbombs" the callee
A low-level solidity call will copy any amount of bytes to local memory. When bytes are copied from returndata
to memory, the memory expansion cost is paid. This means that when using a standard solidity call, the callee can "returnbomb" the caller, imposing an arbitrary gas cost. Because this gas is paid by the caller and in the caller's context, it can cause the caller to run out of gas and halt execution.
function exhaustivelyConsumeAllGas() external pure {
assembly {
return(0, 1000000)
}
}
❌ Use of TransparentProxy with OpenZepplin v5.x.x
On the deployment of the TransparentUpgradeableProxy in OpenZepplin v5.x.x, the constructor will auto-create a ProxyAdmin contract, which later becomes the admin of the current proxy. Because the address of the proxy was not added to the allowlist previously, the deployment of the proxy will break.
The deployer has no control to specify another admin address or change this behavior in this pattern.
As a workaround, you can do the following:
- Use a lower version of OpenZepplin’s TransparentUpgradeableProxy (lower than 5.0.0).
- Use OpenZepplin’s UUPS or Beacon Proxy. Note: Adopt these proxy types only when you fully understand their behavior and do so at your own risk.
❌ Use of TransparentProxy with openzeppelin-upgrades library
The behavior of TransparentProxy v5 happens in the openzeppelin-upgrades library as well. In the library’s factory, it invokes the mentioned process when creating the TransparentUpgradeableProxy.
As a workaround, you can do the following:
- Refrain from using the openzeppelin-upgrades library to control deployments, and use the hardhat-deploy library or native Hardhat’s deploy instead.
- Use OpenZepplin’s UUPS or Beacon Proxy. Note: Adopt these proxy types only when you fully understand their behavior and do so at your own risk.
Recommendations
This section introduces some best practices to prevent potential bugs that might happen in Solidity. The potential bugs include (1) out-of-gas transactions, and (2) security bugs.
✅ Follow general best practices
Refer to the well-described collection from Consensys.
✅ Do not allow uncontrolled size of dynamic arrays
Looping over a dynamic array without size restriction is dangerous because it might lead to out-of-gas transactions.
address[] public users;
function getRewardedUsers() external view returns (address[] memory) {
return users;
}
CREATE2 factory
During Ronin's permissioned phase, the CREATE2 factory contract at 0x4e59b44847b379578588920cA78FbF26c0B4956C
was blacklisted to prevent contract deployments through it.
This restriction will be lifted in the next Ronin hard fork.
In the meantime, developers can:
- Deploy their contracts manually
- Deploy their own CREATE2 factory contract
- Use the alternate CREATE2 factory contract at
0x47211409ff98f42834203db289387c71e2275eae
Contract source code verification
Verifying a smart contract is a crucial step to ensure the integrity and security of the Ronin network. The verification involves inspecting the contract's source code to ensure that it is bug-free, secure, and will perform as expected.
For instructions on verifying smart contracts, see Verify a smart contract.