diff --git a/contracts/.env.example b/contracts/.env.example index 96ca657bba..27b72a352f 100755 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -87,3 +87,7 @@ export PRECOMMIT_DELAY_BLOCKS=21600 # Owner of the Random contract # For this example, we are using test account 0 as the owner export RANDOM_OWNER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +# Owner of the AdressBook contract +# For this example, we are using test account 0 as the owner +export ADDRESS_BOOK_OWNER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \ No newline at end of file diff --git a/contracts/deployments/anvil/random/abiMap.json b/contracts/deployments/anvil/random/abiMap.json index 3c0b222951..c3fd43ef8c 100644 --- a/contracts/deployments/anvil/random/abiMap.json +++ b/contracts/deployments/anvil/random/abiMap.json @@ -1,3 +1,4 @@ { + "AddressBook": "AddressBook", "Random": "Random" } \ No newline at end of file diff --git a/contracts/deployments/anvil/random/abis.json b/contracts/deployments/anvil/random/abis.json index 9b66bad5fb..a34674bf51 100644 --- a/contracts/deployments/anvil/random/abis.json +++ b/contracts/deployments/anvil/random/abis.json @@ -1,4 +1,122 @@ { + "AddressBook": [ + { + "type": "constructor", + "inputs": [ + { + "name": "_owner", + "type": "address", + "internalType": "address" + }, + { + "name": "_random", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "random", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setRandom", + "inputs": [ + { + "name": "_random", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + } + ], "Random": [ { "type": "constructor", @@ -72,20 +190,20 @@ }, { "type": "function", - "name": "DST", + "name": "DRAND_PK_0", "inputs": [], "outputs": [ { "name": "", - "type": "bytes", - "internalType": "bytes" + "type": "uint256", + "internalType": "uint256" } ], "stateMutability": "view" }, { "type": "function", - "name": "MIN_PRECOMMIT_TIME_SECONDS", + "name": "DRAND_PK_1", "inputs": [], "outputs": [ { @@ -98,7 +216,7 @@ }, { "type": "function", - "name": "PRECOMMIT_DELAY_BLOCKS", + "name": "DRAND_PK_2", "inputs": [], "outputs": [ { @@ -111,10 +229,9 @@ }, { "type": "function", - "name": "drandPK0", + "name": "DRAND_PK_3", "inputs": [], "outputs": [ - { "name": "", "type": "uint256", @@ -125,20 +242,20 @@ }, { "type": "function", - "name": "drandPK1", + "name": "DST", "inputs": [], "outputs": [ { "name": "", - "type": "uint256", - "internalType": "uint256" + "type": "bytes", + "internalType": "bytes" } ], "stateMutability": "view" }, { "type": "function", - "name": "drandPK2", + "name": "MIN_PRECOMMIT_TIME_SECONDS", "inputs": [], "outputs": [ { @@ -151,7 +268,7 @@ }, { "type": "function", - "name": "drandPK3", + "name": "PRECOMMIT_DELAY_BLOCKS", "inputs": [], "outputs": [ { diff --git a/contracts/deployments/anvil/random/abis.ts b/contracts/deployments/anvil/random/abis.ts index f60248c523..b1453b4a7c 100644 --- a/contracts/deployments/anvil/random/abis.ts +++ b/contracts/deployments/anvil/random/abis.ts @@ -4,6 +4,124 @@ import type { Address } from "viem" const contractToAbi = ({ + "AddressBook": [ + { + "type": "constructor", + "inputs": [ + { + "name": "_owner", + "type": "address", + "internalType": "address" + }, + { + "name": "_random", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "random", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setRandom", + "inputs": [ + { + "name": "_random", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { + "name": "newOwner", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "previousOwner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newOwner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ] + } + ], "Random": [ { "type": "constructor", @@ -77,20 +195,20 @@ const contractToAbi = ({ }, { "type": "function", - "name": "DST", + "name": "DRAND_PK_0", "inputs": [], "outputs": [ { "name": "", - "type": "bytes", - "internalType": "bytes" + "type": "uint256", + "internalType": "uint256" } ], "stateMutability": "view" }, { "type": "function", - "name": "MIN_PRECOMMIT_TIME_SECONDS", + "name": "DRAND_PK_1", "inputs": [], "outputs": [ { @@ -103,7 +221,7 @@ const contractToAbi = ({ }, { "type": "function", - "name": "PRECOMMIT_DELAY_BLOCKS", + "name": "DRAND_PK_2", "inputs": [], "outputs": [ { @@ -116,7 +234,7 @@ const contractToAbi = ({ }, { "type": "function", - "name": "drandPK0", + "name": "DRAND_PK_3", "inputs": [], "outputs": [ { @@ -129,20 +247,20 @@ const contractToAbi = ({ }, { "type": "function", - "name": "drandPK1", + "name": "DST", "inputs": [], "outputs": [ { "name": "", - "type": "uint256", - "internalType": "uint256" + "type": "bytes", + "internalType": "bytes" } ], "stateMutability": "view" }, { "type": "function", - "name": "drandPK2", + "name": "MIN_PRECOMMIT_TIME_SECONDS", "inputs": [], "outputs": [ { @@ -155,7 +273,7 @@ const contractToAbi = ({ }, { "type": "function", - "name": "drandPK3", + "name": "PRECOMMIT_DELAY_BLOCKS", "inputs": [], "outputs": [ { @@ -640,11 +758,13 @@ const contractToAbi = ({ ) as const const aliasToContract = ({ + "AddressBook": "AddressBook", "Random": "Random" }) as const export const deployment = ({ - "Random": "0xEF648561456FEEa23B993747eB7B68d3B7332b6a" + "AddressBook": "0x67f1f982515895d5186013E5035e3fd38B6eC446", + "Random": "0xC68804dfc148A221330fac653c01D9f254aDf39C" }) as const export type ContractToAbi = typeof contractToAbi diff --git a/contracts/deployments/anvil/random/deployment.json b/contracts/deployments/anvil/random/deployment.json index 08333469ff..92d10fdb1e 100644 --- a/contracts/deployments/anvil/random/deployment.json +++ b/contracts/deployments/anvil/random/deployment.json @@ -1,3 +1,4 @@ { - "Random": "0xEF648561456FEEa23B993747eB7B68d3B7332b6a" + "AddressBook": "0x67f1f982515895d5186013E5035e3fd38B6eC446", + "Random": "0xC68804dfc148A221330fac653c01D9f254aDf39C" } \ No newline at end of file diff --git a/contracts/deployments/happy-sepolia/random/deployment.json b/contracts/deployments/happy-sepolia/random/deployment.json index 0f0559d594..200266a52a 100644 --- a/contracts/deployments/happy-sepolia/random/deployment.json +++ b/contracts/deployments/happy-sepolia/random/deployment.json @@ -1,3 +1,3 @@ { - "Random": "0x02d41cE77B17f499300eD97C6AD19905c36ba556" + "Random": "0xF13b26BD65d4026818698d243195C0b2D09883c2" } \ No newline at end of file diff --git a/contracts/src/AddressBook.sol b/contracts/src/AddressBook.sol new file mode 100644 index 0000000000..f7306fbeb9 --- /dev/null +++ b/contracts/src/AddressBook.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.20; + +import {Ownable} from "openzeppelin/access/Ownable.sol"; + +/** + * This contract is used to retrieve the random contract address from the sequencer while constructing a new block, + * in order to prioritize the transaction originating from the randomness owner and ensure that the reveal transaction + * is included as the first transaction of the block, thereby making the randomness available for all transactions. + */ +contract AddressBook is Ownable { + /** + * It is very important that if we add new variables, we must maintain the `random` variable in the same storage slot. + * Currently, it is stored at 0x01 and that is the slot that the sequencer uses to retrieve the address of the random contract. + */ + address public random; + + constructor(address _owner, address _random) Ownable(_owner) { + random = _random; + } + + function setRandom(address _random) external onlyOwner { + random = _random; + } +} diff --git a/contracts/src/deploy/DeployRandom.s.sol b/contracts/src/deploy/DeployRandom.s.sol index dfbe8fbc5f..a552c67007 100644 --- a/contracts/src/deploy/DeployRandom.s.sol +++ b/contracts/src/deploy/DeployRandom.s.sol @@ -3,14 +3,16 @@ pragma solidity ^0.8.20; import {BaseDeployScript} from "./BaseDeployScript.sol"; import {Random} from "../randomness/Random.sol"; - +import {AddressBook} from "../AddressBook.sol"; /** * @dev Deploys the Randomness contract. */ + contract DeployRandom is BaseDeployScript { - bytes32 public constant DEPLOYMENT_SALT = bytes32(uint256(0)); + bytes32 public constant RANDOM_DEPLOYMENT_SALT = bytes32(uint256(0)); + bytes32 public constant CONFIG_DEPLOYMENT_SALT = bytes32(uint256(1)); Random public random; - + AddressBook public addressBook; /* * To understand these values. Please refer to the following link: * https://docs.anyrand.com/diy/quickstart @@ -33,16 +35,24 @@ contract DeployRandom is BaseDeployScript { function deploy() internal override { uint256 precommitDelayBlocks = vm.envUint("PRECOMMIT_DELAY_BLOCKS"); - address owner = vm.envAddress("RANDOM_OWNER"); + address randomOwner = vm.envAddress("RANDOM_OWNER"); (address _random,) = deployDeterministic( "Random", type(Random).creationCode, abi.encode( - owner, drandPublicKey, DRAND_GENESIS_TIMESTAMP_SECONDS, DRAND_PERIOD_SECONDS, precommitDelayBlocks + randomOwner, drandPublicKey, DRAND_GENESIS_TIMESTAMP_SECONDS, DRAND_PERIOD_SECONDS, precommitDelayBlocks ), - DEPLOYMENT_SALT + RANDOM_DEPLOYMENT_SALT ); random = Random(_random); deployed("Random", address(random)); + + address addressBookOwner = vm.envAddress("ADDRESS_BOOK_OWNER"); + (address _addressBook,) = deployDeterministic( + "AddressBook", type(AddressBook).creationCode, abi.encode(addressBookOwner, _random), CONFIG_DEPLOYMENT_SALT + ); + addressBook = AddressBook(_addressBook); + + deployed("AddressBook", address(addressBook)); } } diff --git a/contracts/src/randomness/Random.sol b/contracts/src/randomness/Random.sol index 24375fff92..7c4f9b0eb4 100644 --- a/contracts/src/randomness/Random.sol +++ b/contracts/src/randomness/Random.sol @@ -4,6 +4,12 @@ pragma solidity ^0.8.20; import {RandomCommitment} from "./RandomCommitment.sol"; import {Drand} from "./Drand.sol"; +/** + * This contract is checked by the sequencer to obtain its owner and to prioritize the owner's transaction, + * ensuring that it is included as the first transaction of the block. This ordering makes the randomness available + * for all transactions in the block. It is very important that if we add new variables, the `owner` variable remains + * in the same storage slot (currently 0x00), because that is the slot used by the sequencer to retrieve the owner's address. + */ contract Random is RandomCommitment, Drand { /* * The amount of time in seconds by which we delay reading the values from the Drand network.