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:
contract ChildContract {}
contract MomContract {
ChildContract public child;
constructor() {
child = new ChildContract();
}
}
Assembly instructions
Instruction | Explanation |
---|---|
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. |
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.
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)
}
}
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.
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.