This repository is a part of the On-chain Distributed Random Beacon (DRB) project. We're currently using Pietrzak VDF verifier for EVM. The related technical details are presented in our preprint (Arxiv).
- The next round can only be executed after the previous round has been recovered or refunded.
- git
- You'll know you did it right if you can run
git --version
and you see a response likegit version x.x.x
- You'll know you did it right if you can run
- Nodejs
- You'll know you've installed nodejs right if you can run:
node --version
and get an output like:vx.x.x
- It'll need to be at least
18.16.0
of node
- You'll know you've installed nodejs right if you can run:
- Yarn instead of
npm
- You'll know you've installed yarn right if you can run:
yarn --version
and get an output like:x.x.x
- You might need to install it with
npm
orcorepack
- You'll know you've installed yarn right if you can run:
git clone https://github.com/tokamak-network/VDF-RNG-verifier.git
cd VDF-RNG-verifier
yarn
- Refer to .env.example to set up your .env file
- Get INFURA_API_KEY from infura dashbord
- Need two private keys to test the DRB by scripts.
- Get ETHERSCAN_API_KEY from etherscan myapikey
- Get OP_ETHERSCAN_API_KEY from opetherscan myapikey
- Get COINMARKETCAP_API_KEY from coinmarketcap
npx hardhat node --no-deploy
#Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
npx hardhat deploy --network localhost --tags cancun --reset
## CHANGE in hardhat.config.ts files at network :{} section
npx hardhat deploy --network <NETWORK_NAME> --tags cancun --reset
npx hardhat deploy --network titan --tags paris --reset
npx hardhat test
#It runs test/CommitRevealRecoverRNG.test.ts
npx hardhat node
#Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
npx hardhat test --network localhost
npx hardhat coverage
- Guide(login required) : https://www.notion.so/onther/verify-contract-4b72acaa7e6c4dd0a8ee09fddfa6c539
slither .
- Solc Version: 0.8.24
- We are managing contracts by splitting evmVersion into paris and cancun.
- cancun is for using transient storage.
- paris is for network Titan network (legacy optimism fork).
- Chain(s) to deploy contract to: Ethereum, Sepolia, opSepolia, titan, titansepolia
- Owner: The user who setSettingVariables
- setting variables: disputePeriod, minimumDepositAmount, avgL2GasUsed, avgL1GasUsed, avgL1GasUsedForTitan, premiumPercentage, penaltyPercentage, flatFee
- Decentralizing this Owner is not yet in the scope of this project.
-
DirectFundingPrice
-
The cost of requesting a random number is calculated based on the optimistic case.
- Optimistic case of one round:
- 3 commits, 1 recover, 1 fulfill transaction fees.
- Calculation formula:
((tx.gasPrice * (callbackGasLimit + avgL2GasUsed)) * (premiumPercentage + 100)) / 100) + flatFee + getCurrentTxL1GasFee()
- Definitions:
tx.gasPrice
: Gas price when the current transaction is executed.callbackGasLimit
: Gas limit of thefulfillRandomWord
function set by the Consumer. When the Coordinator contract calls thefulfillRandomWord
function of the Consumer contract, if the gas usage exceeds thecallbackGasLimit
, the random number is stored in the Coordinator contract only, and the random number to the Consumer contract is canceled. (The transaction does not revert).avgL2GasUsed
: Commit 3 average gas used + recover 1 average gas used + fulfillRandomWord 1 average gas used.premiumPercentage
: The cost can be multiplied by a percentage to increase the cost. It is currently set to 0 and not used.flatFee
: Flat fee.getCurrentTxL1GasFee()
: For L2, we need to calculate L1 gas.
- Optimistic case of one round:
-
CurrentTxL1GasFee
- For L2, the size of the calldata determines the L1 gas cost, and different Optimism versions calculate the L1 gas cost differently. (Arbitrum is not considered.)
- Legacy versions (Titan, Titan Sepolia)
- In the Predeploy contract, the
OVM_GasPriceOracle
contract, values likebaseFee
are taken from theOVM_GasPriceOracle
contract and calculated based oncalldata_size
. - Fixed address of
OVM_GasPriceOracle
contract:0x420000000000000000000000000000000000000000000000000F
- In the Predeploy contract, the
- Bedrock version, Ecotone version
- Both Bedrock and Ecotone versions get
baseFee
and blob-related values from a predeploy contract calledL1_Block_Attributes
and calculate them based oncalldata_size
. L1_Block_Attributes
contract at fixed address:0x4200000000000000000000000000000000000000000000000015
- Both Bedrock and Ecotone versions get
- Legacy versions (Titan, Titan Sepolia)
- For L2, the size of the calldata determines the L1 gas cost, and different Optimism versions calculate the L1 gas cost differently. (Arbitrum is not considered.)
-
CalculateDirectFundingPrice example on Titan network
tx.gasPrice
: Fixed to 0.001 Gwei.callbackGasLimit
: Assumed to be 100,000.avgL2GasUsed
:- 3 Commit: 554690 + 539184 + 558154 = 1,652,028
- 1 Recover: 337,913
- 1 FulfillRandomWord: Approx. 118,000
- Total: 2,107,941
flatFee
: Assumed to be 0.001 ETH.getCurrentTxL1GasFee()
:avgL1GasUsed
(proportional to calldata size):- 3 Commit: 10,508 + 10,496 + 10,496
- 1 Recover: 10,484
- 1 FulfillRandomWord: 5,840
- Total: 47,824
l1BaseFee
: 23.433261599 Gwei (fixed).
- Calculation:
0.001 Gwei * (100,000 + 2,107,941) + 0.001 ETH + 23.433261599 Gwei * 47,824
= 2,207,941,000,000 + 1,000,000,000,000,000 + 1,120,672,302,710,576 wei
= 2,122,880,243,710,576 wei
=> 0.002122880243710576 ETH
=> 11,003 KRW
=> 8.03 USD
-
-
EstimateDirectFundingPrice
- How to calculate how much to send when requesting a
requestRandomWord
off-chain:- Get the
gasPrice
of the current network. - Use the
EstimateDirectFundingPrice
view function of the Coordinator contract to get the corresponding cost by providing thegasPrice
andcallbackGasLimit
as parameters. - Add a buffer to the cost and include it as a value when calling
requestRandomWord
.- Reason for buffer: The
gasPrice
can fluctuate (thegasPrice
obtained off-chain and thegasPrice
when the transaction is executed can be very different). - A buffer of 10% is a good rule of thumb.
- What happens to the amount left over after giving a buffer?
- The remaining amount will stay in the Consumer contract. In a single transaction of
requestRandomWord
, thecalculateDirectFundingPrice
function is executed twice (once by the Consumer and once by the Coordinator).- We should provide guidance for Consumer contract developers to implement logic that allows the requestor to withdraw the remaining amount, or handle it differently.
- When implementing the Consumer, we will guide developers to implement it by inheriting from an abstract contract called
RNGConsumerBase
. By declaring an empty function to handle the remaining amount, Consumer developers will be required to implement it to avoid abstract contract errors.
- When implementing the Consumer, we will guide developers to implement it by inheriting from an abstract contract called
- We should provide guidance for Consumer contract developers to implement logic that allows the requestor to withdraw the remaining amount, or handle it differently.
- The remaining amount will stay in the Consumer contract. In a single transaction of
- Reason for buffer: The
- Get the
- How to calculate how much to send when requesting a
-
minimumDepositAmount
- Since the rounds run in some degree of parallel, it is possible to be penalized simultaneously at a given point. Therefore, logic needs to be added to check if the minimumDepositAmount of the operators is appropriate for each round.
- This will be fixed after the RandomDay event.
- Incentive mechanisms (not updated yet):
- What if the leader doesn't recover for 2 minutes?
- Any other operators who committed to this round should recover.
- There should be a recovery gas cost plus some reward. The leader's reward should go to the recoverer (first come, first served).
- What if the leader doesn't recover for 2 minutes?
- Since the rounds run in some degree of parallel, it is possible to be penalized simultaneously at a given point. Therefore, logic needs to be added to check if the minimumDepositAmount of the operators is appropriate for each round.
-
reRequestRandomWordAtRound
- The function may be executed when the commitPhase is over and there are less than 2 commits.
- This function was created to ensure that the specific round to be fulfilled. However, this function requires additional gas to run, which will be addressed in the future.
- Function descriptions
- In a round that is reRequested when there is already a single commit, the existing committed commit and its operator are expected to participate normally in that round. However, the existing commit count is ignored and counted from zero again.
- Reason: We implemented this because if the reRequested round creates one more commit, resulting in a total of two commits to recover, it may not be a safe random number.
- Who runs it?
- Functions can be executed by anyone, but the operator (who wants to participate in the round) will be the one to run it.
- We are aware the Coordinator is owned by a single user who can set fee related variables, aka it is centralized.
- We are missing some zero address checks/input validation intentionally to save gas.