Skip to main content

Smart contract guidelines

Overview

This page provides a list of guidelines for third-party developers looking to deploy smart contracts onto the Ronin chain.

Disclaimer

These guidelines are provided to assure that the contracts developed by third parties will not abuse the system nor the Ronin chain. An approval granted by Ronin’s reviewers only states that the approved contract will not abuse the chain. The approval does not state that the contract is error-free or doesn't contain any logical or security flaws. The author of the contract is responsible for the contract's' behavior and is recommended to have their contract audited by themselves. Ronin hereby disclaims all liability to the maintainers or any third party related to any such contracts that may be included in or accompany the contracts.

Checklist

The following is a checklist of essential requirements for third-party developers' contracts:

  • Contract MUST NOT create new contracts.
  • Contract MUST NOT self-destruct.
  • Contract MUST NOT “returnbomb” the callee.
  • Contract MUST BE verified after deployment.

The following sections cover these and other requirements and guidelines in detail.

Restrictions

The following items MUST NOT exist in any contracts from third parties to prevent unauthorized contract deployment onto the Ronin chain.

Contract creates other new contracts

In general, the deployment of new contracts onto the Ronin network is restricted and approved by an allowlist mechanism which allows certain specified addresses to deploy new contracts. This prevents the network from being abused and containing many spam contracts.

Therefore, a contract on Ronin MUST NOT be able to create other contracts. The following sections demonstrate some examples of this behavior.

If creation of other contracts within a contract is required due to the design or requirement of the product, such contract is reviewed by Sky Mavis manually with proper explanations from the requester.

Solidity keywords

new keyword

The new keyword in Solidity is used to create a new instance of a smart contract.

Example:

Example
contract ChildContract {}

contract MomContract {
ChildContract public child;

constructor() {
child = new ChildContract();
}
}

Assembly instructions

InstructionExplanation
create(v, p, s)Create a new contract with code mem[p..(p+s)), send v wei, and return the new address.
create2(v, n, p, s)Create a new contract with code mem[p..(p+s)) at address keccak256(<address> . n . keccak256(mem[p..(p+s))), send v wei, and return the new address.
Example
contract Factory {
event Deployed(address addr, uint256 salt);

function getCreationBytecode(address _owner, uint _foo) public pure returns (bytes memory) {
bytes memory bytecode = type(Wallet).creationCode;
return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
}

// Note: Call this function with bytecode from getCreationByteCode and a random salt
function deploy(bytes memory bytecode, uint _salt) public {
address addr;
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), _salt)
if iszero(extcodesize(addr)) {
revert(0, 0)
}
}
emit Deployed(addr, _salt);
}
}

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.

Example
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)
}
}

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.

General best practices

Refer to the well-described collection from Consensys.

Ronin's best practices

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

Keep your Solidity version up to date

If your projects are newly developed and are not based on existing code, we recommend using the latest version of Solidity to for a fresh start. There are bugs found in both Solidity and EVM, some are considered critical. The new patches in Solidity help cover these flaws.

Contract source code verification

This is a crucial step to ensure the integrity and security of the Ronin network. Verifying a smart contract involves inspecting its code to ensure that it is bug-free, secure, and will perform as expected.

We encourage the contract deployers to verify their contract with our internal Sourcify service.

For specific instructions, see Verify source code with Sourcify.

Was this helpful?
Happy React is loading...