From ab10b9f5fa2fe00062042c6e7f48ebe0e3bd8fa9 Mon Sep 17 00:00:00 2001 From: Dev Kalra Date: Tue, 23 Jan 2024 01:53:19 +0530 Subject: [PATCH] [fortuna] script to setup a provider for all chains (#1229) * auto register script * renaming * add comments * update abi file path * pre commit * pre commit * resolved some * better comment * resolve comments * fix bug * pre commit * fix * update version --- fortuna/.gitignore | 1 + fortuna/Cargo.lock | 2 +- fortuna/Cargo.toml | 2 +- fortuna/Dockerfile | 1 + fortuna/src/abi.json | 1020 ---------------------- fortuna/src/chain/ethereum.rs | 5 +- fortuna/src/command.rs | 2 + fortuna/src/command/register_provider.rs | 9 +- fortuna/src/command/setup_provider.rs | 117 +++ fortuna/src/config.rs | 6 + fortuna/src/config/setup_provider.rs | 43 + fortuna/src/main.rs | 1 + 12 files changed, 180 insertions(+), 1029 deletions(-) delete mode 100644 fortuna/src/abi.json create mode 100644 fortuna/src/command/setup_provider.rs create mode 100644 fortuna/src/config/setup_provider.rs diff --git a/fortuna/.gitignore b/fortuna/.gitignore index b7258ec739..7bb7d7a607 100644 --- a/fortuna/.gitignore +++ b/fortuna/.gitignore @@ -1,3 +1,4 @@ /target config.yaml *secret* +*private-key* diff --git a/fortuna/Cargo.lock b/fortuna/Cargo.lock index f421cf6028..902bf35492 100644 --- a/fortuna/Cargo.lock +++ b/fortuna/Cargo.lock @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "fortuna" -version = "3.2.0" +version = "3.2.1" dependencies = [ "anyhow", "axum", diff --git a/fortuna/Cargo.toml b/fortuna/Cargo.toml index e9fa84c05e..ba1049c0c5 100644 --- a/fortuna/Cargo.toml +++ b/fortuna/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fortuna" -version = "3.2.0" +version = "3.2.1" edition = "2021" [dependencies] diff --git a/fortuna/Dockerfile b/fortuna/Dockerfile index 07abfd90cb..d2e1f6192a 100644 --- a/fortuna/Dockerfile +++ b/fortuna/Dockerfile @@ -9,6 +9,7 @@ RUN rustup default nightly-2023-07-23 WORKDIR /src COPY fortuna fortuna COPY pythnet pythnet +COPY target_chains/ethereum/entropy_sdk/solidity/abis target_chains/ethereum/entropy_sdk/solidity/abis WORKDIR /src/fortuna diff --git a/fortuna/src/abi.json b/fortuna/src/abi.json deleted file mode 100644 index e373e7f6c4..0000000000 --- a/fortuna/src/abi.json +++ /dev/null @@ -1,1020 +0,0 @@ -[ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "AssertionFailure", - "type": "error" - }, - { - "inputs": [], - "name": "BlockhashUnavailable", - "type": "error" - }, - { - "inputs": [], - "name": "IncorrectRevelation", - "type": "error" - }, - { - "inputs": [], - "name": "InsufficientFee", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidUpgradeMagic", - "type": "error" - }, - { - "inputs": [], - "name": "NoSuchProvider", - "type": "error" - }, - { - "inputs": [], - "name": "NoSuchRequest", - "type": "error" - }, - { - "inputs": [], - "name": "OutOfRandomness", - "type": "error" - }, - { - "inputs": [], - "name": "Unauthorized", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldImplementation", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "ContractUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldDefaultProvider", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newDefaultProvider", - "type": "address" - } - ], - "name": "DefaultProviderSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "NewAdminAccepted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "oldAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "NewAdminProposed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "oldPythFee", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "newPythFee", - "type": "uint256" - } - ], - "name": "PythFeeSet", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "uint128", - "name": "feeInWei", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "accruedFeesInWei", - "type": "uint128" - }, - { - "internalType": "bytes32", - "name": "originalCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "originalCommitmentSequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "commitmentMetadata", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "uri", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "endSequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "currentCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "currentCommitmentSequenceNumber", - "type": "uint64" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.ProviderInfo", - "name": "provider", - "type": "tuple" - } - ], - "name": "Registered", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint32", - "name": "numHashes", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "bool", - "name": "useBlockhash", - "type": "bool" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.Request", - "name": "request", - "type": "tuple" - } - ], - "name": "Requested", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint32", - "name": "numHashes", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "bool", - "name": "useBlockhash", - "type": "bool" - } - ], - "indexed": false, - "internalType": "struct EntropyStructs.Request", - "name": "request", - "type": "tuple" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "userRevelation", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "providerRevelation", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "randomNumber", - "type": "bytes32" - } - ], - "name": "Revealed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "inputs": [], - "name": "NUM_REQUESTS", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "NUM_REQUESTS_MASK", - "outputs": [ - { - "internalType": "bytes1", - "name": "", - "type": "bytes1" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "acceptAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "userRandomness", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "providerRandomness", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - } - ], - "name": "combineRandomValues", - "outputs": [ - { - "internalType": "bytes32", - "name": "combinedRandomness", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "userRandomness", - "type": "bytes32" - } - ], - "name": "constructUserCommitment", - "outputs": [ - { - "internalType": "bytes32", - "name": "userCommitment", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "getAccruedPythFees", - "outputs": [ - { - "internalType": "uint128", - "name": "accruedPythFeesInWei", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getDefaultProvider", - "outputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - } - ], - "name": "getFee", - "outputs": [ - { - "internalType": "uint128", - "name": "feeAmount", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - } - ], - "name": "getProviderInfo", - "outputs": [ - { - "components": [ - { - "internalType": "uint128", - "name": "feeInWei", - "type": "uint128" - }, - { - "internalType": "uint128", - "name": "accruedFeesInWei", - "type": "uint128" - }, - { - "internalType": "bytes32", - "name": "originalCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "originalCommitmentSequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "commitmentMetadata", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "uri", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "endSequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "currentCommitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "currentCommitmentSequenceNumber", - "type": "uint64" - } - ], - "internalType": "struct EntropyStructs.ProviderInfo", - "name": "info", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPythFee", - "outputs": [ - { - "internalType": "uint128", - "name": "feeAmount", - "type": "uint128" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - } - ], - "name": "getRequest", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "uint32", - "name": "numHashes", - "type": "uint32" - }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "address", - "name": "requester", - "type": "address" - }, - { - "internalType": "bool", - "name": "useBlockhash", - "type": "bool" - } - ], - "internalType": "struct EntropyStructs.Request", - "name": "req", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "proposeAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "proposedAdmin", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxiableUUID", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "feeInWei", - "type": "uint128" - }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "commitmentMetadata", - "type": "bytes" - }, - { - "internalType": "uint64", - "name": "chainLength", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "uri", - "type": "bytes" - } - ], - "name": "register", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "userCommitment", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "useBlockHash", - "type": "bool" - } - ], - "name": "request", - "outputs": [ - { - "internalType": "uint64", - "name": "assignedSequenceNumber", - "type": "uint64" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "provider", - "type": "address" - }, - { - "internalType": "uint64", - "name": "sequenceNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "userRandomness", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "providerRevelation", - "type": "bytes32" - } - ], - "name": "reveal", - "outputs": [ - { - "internalType": "bytes32", - "name": "randomNumber", - "type": "bytes32" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newDefaultProvider", - "type": "address" - } - ], - "name": "setDefaultProvider", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "newPythFee", - "type": "uint128" - } - ], - "name": "setPythFee", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - } - ], - "name": "withdraw", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "admin", - "type": "address" - }, - { - "internalType": "uint128", - "name": "pythFeeInWei", - "type": "uint128" - }, - { - "internalType": "address", - "name": "defaultProvider", - "type": "address" - }, - { - "internalType": "bool", - "name": "prefillRequestStorage", - "type": "bool" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "upgradeTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "entropyUpgradableMagic", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "pure", - "type": "function" - } -] diff --git a/fortuna/src/chain/ethereum.rs b/fortuna/src/chain/ethereum.rs index 183758db21..38e05cb099 100644 --- a/fortuna/src/chain/ethereum.rs +++ b/fortuna/src/chain/ethereum.rs @@ -50,7 +50,10 @@ use { // TODO: Programmatically generate this so we don't have to keep committed ABI in sync with the // contract in the same repo. -abigen!(PythRandom, "src/abi.json"); +abigen!( + PythRandom, + "../target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json" +); pub type SignablePythContract = PythRandom< TransformerMiddleware, LocalWallet>, LegacyTxTransformer>, diff --git a/fortuna/src/command.rs b/fortuna/src/command.rs index 97ccf6026c..a5170a8a52 100644 --- a/fortuna/src/command.rs +++ b/fortuna/src/command.rs @@ -3,6 +3,7 @@ mod get_request; mod register_provider; mod request_randomness; mod run; +mod setup_provider; pub use { generate::generate, @@ -10,4 +11,5 @@ pub use { register_provider::register_provider, request_randomness::request_randomness, run::run, + setup_provider::setup_provider, }; diff --git a/fortuna/src/command/register_provider.rs b/fortuna/src/command/register_provider.rs index b59133e53c..8b830b37ee 100644 --- a/fortuna/src/command/register_provider.rs +++ b/fortuna/src/command/register_provider.rs @@ -8,12 +8,9 @@ use { state::PebbleHashChain, }, anyhow::Result, - ethers::{ - signers::{ - LocalWallet, - Signer, - }, - types::Address, + ethers::signers::{ + LocalWallet, + Signer, }, std::sync::Arc, }; diff --git a/fortuna/src/command/setup_provider.rs b/fortuna/src/command/setup_provider.rs new file mode 100644 index 0000000000..b3da8b7374 --- /dev/null +++ b/fortuna/src/command/setup_provider.rs @@ -0,0 +1,117 @@ +use { + crate::{ + chain::ethereum::SignablePythContract, + command::{ + register_provider, + register_provider::CommitmentMetadata, + }, + config::{ + Config, + RegisterProviderOptions, + SetupProviderOptions, + }, + state::{ + HashChainState, + PebbleHashChain, + }, + }, + anyhow::Result, + ethers::signers::{ + LocalWallet, + Signer, + }, + std::sync::Arc, +}; + +/// Setup provider for all the chains. +/// 1. Register if there was no previous registration. +/// 2. Re-register if there are no more random numbers to request on the contract. +/// 3. Re-register if there is a mismatch in generated hash chain. +/// 4. Update provider fee if there is a mismatch with the fee set on contract. +/// 5. Update provider uri if there is a mismatch with the uri set on contract. +pub async fn setup_provider(opts: &SetupProviderOptions) -> Result<()> { + let config = Config::load(&opts.config.config)?; + let private_key = opts.load_private_key()?; + let secret = opts.randomness.load_secret()?; + let provider_address = private_key.clone().parse::()?.address(); + + for (chain_id, chain_config) in &config.chains { + // Initialize a Provider to interface with the EVM contract. + let contract = + Arc::new(SignablePythContract::from_config(&chain_config, &private_key).await?); + let provider_info = contract.get_provider_info(provider_address).call().await?; + tracing::info!("Provider info: {:?}", provider_info); + + let mut register = false; + + // This condition satisfies for both when there is no registration and when there are no + // more random numbers left to request + if provider_info.end_sequence_number <= provider_info.sequence_number { + tracing::info!( + "endSequenceNumber <= sequenceNumber. endSequenceNumber={0}, sequenceNumber={1}", + provider_info.end_sequence_number, + provider_info.sequence_number + ); + tracing::info!("Registering to {}", &chain_id); + register = true; + } else { + let metadata = + bincode::deserialize::(&provider_info.commitment_metadata)?; + + let hash_chain = PebbleHashChain::from_config( + &secret, + &chain_id, + &provider_address, + &chain_config.contract_addr, + &metadata.seed, + metadata.chain_length, + )?; + let chain_state = HashChainState { + offsets: vec![provider_info + .original_commitment_sequence_number + .try_into()?], + hash_chains: vec![hash_chain], + }; + + + if chain_state.reveal(provider_info.original_commitment_sequence_number)? + != provider_info.original_commitment + { + tracing::info!("The root of the generated hash chain for chain id {} does not match the commitment", &chain_id); + tracing::info!("Registering to {}", &chain_id); + register = true; + } + } + + if register { + register_provider(&RegisterProviderOptions { + config: opts.config.clone(), + chain_id: chain_id.clone(), + private_key: private_key.clone(), + randomness: opts.randomness.clone(), + fee: opts.fee, + uri: opts.uri.clone(), + }) + .await?; + } else { + if provider_info.fee_in_wei != opts.fee { + if let Some(r) = contract.set_provider_fee(opts.fee).send().await?.await? { + tracing::info!("Updated provider fee: {:?}", r); + } + } + + if bincode::deserialize::(&provider_info.uri)? != opts.uri { + if let Some(receipt) = contract + .set_provider_uri(bincode::serialize(&opts.uri)?.into()) + .send() + .await? + .log_msg("Pending transfer hash") + .await? + { + tracing::info!("Updated provider uri: {:?}", receipt); + } + } + } + } + Ok(()) +} diff --git a/fortuna/src/config.rs b/fortuna/src/config.rs index 590043c89e..cd0005a7a4 100644 --- a/fortuna/src/config.rs +++ b/fortuna/src/config.rs @@ -27,6 +27,7 @@ pub use { register_provider::RegisterProviderOptions, request_randomness::RequestRandomnessOptions, run::RunOptions, + setup_provider::SetupProviderOptions, }; mod generate; @@ -34,6 +35,7 @@ mod get_request; mod register_provider; mod request_randomness; mod run; +mod setup_provider; const DEFAULT_RPC_ADDR: &str = "127.0.0.1:34000"; const DEFAULT_HTTP_ADDR: &str = "http://127.0.0.1:34000"; @@ -51,6 +53,10 @@ pub enum Options { /// Register a new provider with the Pyth Random oracle. RegisterProvider(RegisterProviderOptions), + /// Set up the provider for all the provided chains. + /// It registers, re-registers, or updates provider config on chain. + SetupProvider(SetupProviderOptions), + /// Request a random number from the contract. RequestRandomness(RequestRandomnessOptions), diff --git a/fortuna/src/config/setup_provider.rs b/fortuna/src/config/setup_provider.rs new file mode 100644 index 0000000000..8371f9406a --- /dev/null +++ b/fortuna/src/config/setup_provider.rs @@ -0,0 +1,43 @@ +use { + crate::config::{ + ConfigOptions, + RandomnessOptions, + }, + anyhow::Result, + clap::Args, + std::fs, +}; + +#[derive(Args, Clone, Debug)] +#[command(next_help_heading = "Setup Provider Options")] +#[group(id = "SetupProviderOptions")] +pub struct SetupProviderOptions { + #[command(flatten)] + pub config: ConfigOptions, + + /// Path to a file containing a 20-byte (40 char) hex encoded Ethereum private key. + /// This key is required to submit transactions (such as registering with the contract). + #[arg(long = "private-key")] + #[arg(env = "PRIVATE_KEY")] + pub private_key_file: String, + + #[command(flatten)] + pub randomness: RandomnessOptions, + + /// The fee to charge (in wei) for each requested random number + #[arg(long = "pyth-contract-fee")] + #[arg(default_value = "100")] + pub fee: u128, + + /// The URI where clients can retrieve random values from this provider, + /// i.e., wherever fortuna for this provider will be hosted. + #[arg(long = "uri")] + #[arg(default_value = "")] + pub uri: String, +} + +impl SetupProviderOptions { + pub fn load_private_key(&self) -> Result { + return Ok((fs::read_to_string(&self.private_key_file))?); + } +} diff --git a/fortuna/src/main.rs b/fortuna/src/main.rs index bf5670f44a..c1f98eeab8 100644 --- a/fortuna/src/main.rs +++ b/fortuna/src/main.rs @@ -39,6 +39,7 @@ async fn main() -> Result<()> { config::Options::Generate(opts) => command::generate(&opts).await, config::Options::Run(opts) => command::run(&opts).await, config::Options::RegisterProvider(opts) => command::register_provider(&opts).await, + config::Options::SetupProvider(opts) => command::setup_provider(&opts).await, config::Options::RequestRandomness(opts) => command::request_randomness(&opts).await, } }