Skip to main content

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.

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

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