From 0e766515182b2853b01a0d17571d87e5d0ec378d Mon Sep 17 00:00:00 2001 From: sveitser Date: Mon, 25 Nov 2024 15:16:35 +0100 Subject: [PATCH 01/58] Initial draft for minimal L1 stake table --- contract-bindings/src/lib.rs | 1 + contract-bindings/src/simple_stake_table.rs | 1089 +++++++++++++++++++ contracts/src/SimpleStakeTable.sol | 54 + contracts/test/SimpleStakeTable.t.sol | 97 ++ justfile | 2 +- 5 files changed, 1242 insertions(+), 1 deletion(-) create mode 100644 contract-bindings/src/simple_stake_table.rs create mode 100644 contracts/src/SimpleStakeTable.sol create mode 100644 contracts/test/SimpleStakeTable.t.sol diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index cc6716e894..7a845305a4 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -13,3 +13,4 @@ pub mod light_client_state_update_vk_mock; pub mod plonk_verifier; pub mod plonk_verifier_2; pub mod shared_types; +pub mod simple_stake_table; diff --git a/contract-bindings/src/simple_stake_table.rs b/contract-bindings/src/simple_stake_table.rs new file mode 100644 index 0000000000..c1176ca1d4 --- /dev/null +++ b/contract-bindings/src/simple_stake_table.rs @@ -0,0 +1,1089 @@ +pub use simple_stake_table::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod simple_stake_table { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("initialOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some(::std::borrow::ToOwned::to_owned( + "address" + ),), + },], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("_hashBlsKey"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("_hashBlsKey"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes32"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Pure, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("insert"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("insert"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("newStakers"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point[]"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("isStaker"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isStaker"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("staker"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("remove"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("remove"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("stakersToRemove"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point[]"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("renounceOwnership"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("renounceOwnership"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("transferOwnership"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("transferOwnership"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("newOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ]), + events: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("Added"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("Added"), + inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + indexed: false, + },], + anonymous: false, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("OwnershipTransferred"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("OwnershipTransferred",), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("previousOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + indexed: true, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("newOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + indexed: true, + }, + ], + anonymous: false, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("Removed"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("Removed"), + inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ), + ), + indexed: false, + },], + anonymous: false, + },], + ), + ]), + errors: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("owner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("account"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("StakerAlreadyExists"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("StakerAlreadyExists",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("StakerNotFound"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("StakerNotFound"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + },], + ), + ]), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static SIMPLESTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x07\xA88\x03\x80a\x07\xA8\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x06\xAB\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCE\xD4~f\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c=\x8D\x10@\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05\x1AV[a\x01)V[\0[a\0\x95a\x021V[a\0\xB2a\0\xAD6`\x04a\x05\xCDV[a\x02EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x05\xCDV[a\x02nV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05\x1AV[a\x02\xCAV[a\0\x95a\x01$6`\x04a\x05\xF0V[a\x03\xB2V[a\x011a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x01\xF6W`\0a\x01a\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[` \x02` \x01\x01Qa\x02nV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x01\xD5W\x82\x82\x81Q\x81\x10a\x01\x8DWa\x01\x8Da\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x014V[P\x7Fz\xC3a=\xC3\xB4>q#Y\x94 \xBDXa\x0C\xD6\xFF;\x14\xB6\x0E?%T\xA1\x0E\xC2\xCCM\x1E)\x81`@Qa\x02&\x91\x90a\x06/V[`@Q\x80\x91\x03\x90\xA1PV[a\x029a\x03\xF0V[a\x02C`\0a\x04\x1DV[V[`\0`\x01`\0a\x02T\x84a\x02nV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAD\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD2a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x03\x82W`\0a\x02\xF5\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03cW\x82\x82\x81Q\x81\x10a\x03 Wa\x03 a\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xCCV[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xD5V[P\x7F[L\xFC\x86_\xA8H:\x99<\xD6)\x1F\x0Cg\x18T\xFC\xBFnD\x89\xD8\xD6\x912\\\xF4\xD8\x08\xA6S\x81`@Qa\x02&\x91\x90a\x06/V[a\x03\xBAa\x03\xF0V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xE4W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xCCV[a\x03\xED\x81a\x04\x1DV[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02CW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xCCV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04mV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xC6W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xE9Wa\x04\xE9a\x04mV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05-W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05EW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05YW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05kWa\x05ka\x04mV[a\x05y\x84\x82`\x05\x1B\x01a\x04\x83V[\x81\x81R\x84\x81\x01\x92P`\x07\x91\x90\x91\x1B\x83\x01\x84\x01\x90\x87\x82\x11\x15a\x05\x99W`\0\x80\xFD[\x92\x84\x01\x92[\x81\x84\x10\x15a\x05\xC2Wa\x05\xB0\x88\x85a\x04\xB4V[\x83R\x84\x83\x01\x92P`\x80\x84\x01\x93Pa\x05\x9EV[\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x05\xDFW`\0\x80\xFD[a\x05\xE9\x83\x83a\x04\xB4V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\x02W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05\xE9W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x06\x92Wa\x06\x7F\x83\x85Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x92\x84\x01\x92`\x80\x92\x90\x92\x01\x91`\x01\x01a\x06KV[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + /// The bytecode of the contract. + pub static SIMPLESTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCE\xD4~f\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c=\x8D\x10@\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05\x1AV[a\x01)V[\0[a\0\x95a\x021V[a\0\xB2a\0\xAD6`\x04a\x05\xCDV[a\x02EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x05\xCDV[a\x02nV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05\x1AV[a\x02\xCAV[a\0\x95a\x01$6`\x04a\x05\xF0V[a\x03\xB2V[a\x011a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x01\xF6W`\0a\x01a\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[` \x02` \x01\x01Qa\x02nV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x01\xD5W\x82\x82\x81Q\x81\x10a\x01\x8DWa\x01\x8Da\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x014V[P\x7Fz\xC3a=\xC3\xB4>q#Y\x94 \xBDXa\x0C\xD6\xFF;\x14\xB6\x0E?%T\xA1\x0E\xC2\xCCM\x1E)\x81`@Qa\x02&\x91\x90a\x06/V[`@Q\x80\x91\x03\x90\xA1PV[a\x029a\x03\xF0V[a\x02C`\0a\x04\x1DV[V[`\0`\x01`\0a\x02T\x84a\x02nV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAD\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD2a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x03\x82W`\0a\x02\xF5\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03cW\x82\x82\x81Q\x81\x10a\x03 Wa\x03 a\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xCCV[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xD5V[P\x7F[L\xFC\x86_\xA8H:\x99<\xD6)\x1F\x0Cg\x18T\xFC\xBFnD\x89\xD8\xD6\x912\\\xF4\xD8\x08\xA6S\x81`@Qa\x02&\x91\x90a\x06/V[a\x03\xBAa\x03\xF0V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xE4W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xCCV[a\x03\xED\x81a\x04\x1DV[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02CW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xCCV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04mV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xC6W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xE9Wa\x04\xE9a\x04mV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05-W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05EW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05YW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05kWa\x05ka\x04mV[a\x05y\x84\x82`\x05\x1B\x01a\x04\x83V[\x81\x81R\x84\x81\x01\x92P`\x07\x91\x90\x91\x1B\x83\x01\x84\x01\x90\x87\x82\x11\x15a\x05\x99W`\0\x80\xFD[\x92\x84\x01\x92[\x81\x84\x10\x15a\x05\xC2Wa\x05\xB0\x88\x85a\x04\xB4V[\x83R\x84\x83\x01\x92P`\x80\x84\x01\x93Pa\x05\x9EV[\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x05\xDFW`\0\x80\xFD[a\x05\xE9\x83\x83a\x04\xB4V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\x02W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05\xE9W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x06\x92Wa\x06\x7F\x83\x85Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x92\x84\x01\x92`\x80\x92\x90\x92\x01\x91`\x01\x01a\x06KV[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + /// The deployed bytecode of the contract. + pub static SIMPLESTAKETABLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct SimpleStakeTable(::ethers::contract::Contract); + impl ::core::clone::Clone for SimpleStakeTable { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for SimpleStakeTable { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for SimpleStakeTable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for SimpleStakeTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(SimpleStakeTable)) + .field(&self.address()) + .finish() + } + } + impl SimpleStakeTable { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + SIMPLESTAKETABLE_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + SIMPLESTAKETABLE_ABI.clone(), + SIMPLESTAKETABLE_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `_hashBlsKey` (0x9b30a5e6) function + pub fn hash_bls_key( + &self, + bls_vk: G2Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([155, 48, 165, 230], (bls_vk,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `insert` (0x3d8d1040) function + pub fn insert( + &self, + new_stakers: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([61, 141, 16, 64], new_stakers) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `isStaker` (0x75d705e9) function + pub fn is_staker( + &self, + staker: G2Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([117, 215, 5, 233], (staker,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `remove` (0xced47e66) function + pub fn remove( + &self, + stakers_to_remove: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([206, 212, 126, 102], stakers_to_remove) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `renounceOwnership` (0x715018a6) function + pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([113, 80, 24, 166], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transferOwnership` (0xf2fde38b) function + pub fn transfer_ownership( + &self, + new_owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([242, 253, 227, 139], new_owner) + .expect("method not found (this should never happen)") + } + ///Gets the contract's `Added` event + pub fn added_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, AddedFilter> { + self.0.event() + } + ///Gets the contract's `OwnershipTransferred` event + pub fn ownership_transferred_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> + { + self.0.event() + } + ///Gets the contract's `Removed` event + pub fn removed_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RemovedFilter> { + self.0.event() + } + /// Returns an `Event` builder for all the events of this contract. + pub fn events( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, SimpleStakeTableEvents> + { + self.0 + .event_with_filter(::core::default::Default::default()) + } + } + impl From<::ethers::contract::Contract> + for SimpleStakeTable + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "OwnableInvalidOwner", abi = "OwnableInvalidOwner(address)")] + pub struct OwnableInvalidOwner { + pub owner: ::ethers::core::types::Address, + } + ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "OwnableUnauthorizedAccount", + abi = "OwnableUnauthorizedAccount(address)" + )] + pub struct OwnableUnauthorizedAccount { + pub account: ::ethers::core::types::Address, + } + ///Custom Error type `StakerAlreadyExists` with signature `StakerAlreadyExists((uint256,uint256,uint256,uint256))` and selector `0x360dc282` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "StakerAlreadyExists", + abi = "StakerAlreadyExists((uint256,uint256,uint256,uint256))" + )] + pub struct StakerAlreadyExists(pub G2Point); + ///Custom Error type `StakerNotFound` with signature `StakerNotFound((uint256,uint256,uint256,uint256))` and selector `0x34a7561f` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "StakerNotFound", + abi = "StakerNotFound((uint256,uint256,uint256,uint256))" + )] + pub struct StakerNotFound(pub G2Point); + ///Container type for all of the contract's custom errors + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum SimpleStakeTableErrors { + OwnableInvalidOwner(OwnableInvalidOwner), + OwnableUnauthorizedAccount(OwnableUnauthorizedAccount), + StakerAlreadyExists(StakerAlreadyExists), + StakerNotFound(StakerNotFound), + /// The standard solidity revert string, with selector + /// Error(string) -- 0x08c379a0 + RevertString(::std::string::String), + } + impl ::ethers::core::abi::AbiDecode for SimpleStakeTableErrors { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = + <::std::string::String as ::ethers::core::abi::AbiDecode>::decode(data) + { + return Ok(Self::RevertString(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::OwnableInvalidOwner(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::OwnableUnauthorizedAccount(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::StakerAlreadyExists(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::StakerNotFound(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for SimpleStakeTableErrors { + fn encode(self) -> ::std::vec::Vec { + match self { + Self::OwnableInvalidOwner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::OwnableUnauthorizedAccount(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::StakerAlreadyExists(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::StakerNotFound(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), + } + } + } + impl ::ethers::contract::ContractRevert for SimpleStakeTableErrors { + fn valid_selector(selector: [u8; 4]) -> bool { + match selector { + [0x08, 0xc3, 0x79, 0xa0] => true, + _ if selector + == ::selector() => + { + true + } + _ if selector + == ::selector() => + { + true + } + _ if selector + == ::selector() => + { + true + } + _ if selector == ::selector() => { + true + } + _ => false, + } + } + } + impl ::core::fmt::Display for SimpleStakeTableErrors { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::OwnableInvalidOwner(element) => ::core::fmt::Display::fmt(element, f), + Self::OwnableUnauthorizedAccount(element) => ::core::fmt::Display::fmt(element, f), + Self::StakerAlreadyExists(element) => ::core::fmt::Display::fmt(element, f), + Self::StakerNotFound(element) => ::core::fmt::Display::fmt(element, f), + Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), + } + } + } + impl ::core::convert::From<::std::string::String> for SimpleStakeTableErrors { + fn from(value: String) -> Self { + Self::RevertString(value) + } + } + impl ::core::convert::From for SimpleStakeTableErrors { + fn from(value: OwnableInvalidOwner) -> Self { + Self::OwnableInvalidOwner(value) + } + } + impl ::core::convert::From for SimpleStakeTableErrors { + fn from(value: OwnableUnauthorizedAccount) -> Self { + Self::OwnableUnauthorizedAccount(value) + } + } + impl ::core::convert::From for SimpleStakeTableErrors { + fn from(value: StakerAlreadyExists) -> Self { + Self::StakerAlreadyExists(value) + } + } + impl ::core::convert::From for SimpleStakeTableErrors { + fn from(value: StakerNotFound) -> Self { + Self::StakerNotFound(value) + } + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent(name = "Added", abi = "Added((uint256,uint256,uint256,uint256)[])")] + pub struct AddedFilter(pub ::std::vec::Vec); + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent( + name = "OwnershipTransferred", + abi = "OwnershipTransferred(address,address)" + )] + pub struct OwnershipTransferredFilter { + #[ethevent(indexed)] + pub previous_owner: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub new_owner: ::ethers::core::types::Address, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent(name = "Removed", abi = "Removed((uint256,uint256,uint256,uint256)[])")] + pub struct RemovedFilter(pub ::std::vec::Vec); + ///Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum SimpleStakeTableEvents { + AddedFilter(AddedFilter), + OwnershipTransferredFilter(OwnershipTransferredFilter), + RemovedFilter(RemovedFilter), + } + impl ::ethers::contract::EthLogDecode for SimpleStakeTableEvents { + fn decode_log( + log: &::ethers::core::abi::RawLog, + ) -> ::core::result::Result { + if let Ok(decoded) = AddedFilter::decode_log(log) { + return Ok(SimpleStakeTableEvents::AddedFilter(decoded)); + } + if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { + return Ok(SimpleStakeTableEvents::OwnershipTransferredFilter(decoded)); + } + if let Ok(decoded) = RemovedFilter::decode_log(log) { + return Ok(SimpleStakeTableEvents::RemovedFilter(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData) + } + } + impl ::core::fmt::Display for SimpleStakeTableEvents { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::AddedFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::OwnershipTransferredFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::RemovedFilter(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for SimpleStakeTableEvents { + fn from(value: AddedFilter) -> Self { + Self::AddedFilter(value) + } + } + impl ::core::convert::From for SimpleStakeTableEvents { + fn from(value: OwnershipTransferredFilter) -> Self { + Self::OwnershipTransferredFilter(value) + } + } + impl ::core::convert::From for SimpleStakeTableEvents { + fn from(value: RemovedFilter) -> Self { + Self::RemovedFilter(value) + } + } + ///Container type for all input parameters for the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "_hashBlsKey", + abi = "_hashBlsKey((uint256,uint256,uint256,uint256))" + )] + pub struct HashBlsKeyCall { + pub bls_vk: G2Point, + } + ///Container type for all input parameters for the `insert` function with signature `insert((uint256,uint256,uint256,uint256)[])` and selector `0x3d8d1040` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "insert", abi = "insert((uint256,uint256,uint256,uint256)[])")] + pub struct InsertCall { + pub new_stakers: ::std::vec::Vec, + } + ///Container type for all input parameters for the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "isStaker", abi = "isStaker((uint256,uint256,uint256,uint256))")] + pub struct IsStakerCall { + pub staker: G2Point, + } + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `remove` function with signature `remove((uint256,uint256,uint256,uint256)[])` and selector `0xced47e66` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "remove", abi = "remove((uint256,uint256,uint256,uint256)[])")] + pub struct RemoveCall { + pub stakers_to_remove: ::std::vec::Vec, + } + ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] + pub struct RenounceOwnershipCall; + ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] + pub struct TransferOwnershipCall { + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum SimpleStakeTableCalls { + HashBlsKey(HashBlsKeyCall), + Insert(InsertCall), + IsStaker(IsStakerCall), + Owner(OwnerCall), + Remove(RemoveCall), + RenounceOwnership(RenounceOwnershipCall), + TransferOwnership(TransferOwnershipCall), + } + impl ::ethers::core::abi::AbiDecode for SimpleStakeTableCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = ::decode(data) { + return Ok(Self::HashBlsKey(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Insert(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::IsStaker(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Remove(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::RenounceOwnership(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::TransferOwnership(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for SimpleStakeTableCalls { + fn encode(self) -> Vec { + match self { + Self::HashBlsKey(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Insert(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::IsStaker(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Remove(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RenounceOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TransferOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for SimpleStakeTableCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::HashBlsKey(element) => ::core::fmt::Display::fmt(element, f), + Self::Insert(element) => ::core::fmt::Display::fmt(element, f), + Self::IsStaker(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Remove(element) => ::core::fmt::Display::fmt(element, f), + Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: HashBlsKeyCall) -> Self { + Self::HashBlsKey(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: InsertCall) -> Self { + Self::Insert(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: IsStakerCall) -> Self { + Self::IsStaker(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: RemoveCall) -> Self { + Self::Remove(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: RenounceOwnershipCall) -> Self { + Self::RenounceOwnership(value) + } + } + impl ::core::convert::From for SimpleStakeTableCalls { + fn from(value: TransferOwnershipCall) -> Self { + Self::TransferOwnership(value) + } + } + ///Container type for all return fields from the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct HashBlsKeyReturn(pub [u8; 32]); + ///Container type for all return fields from the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct IsStakerReturn(pub bool); + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///`G2Point(uint256,uint256,uint256,uint256)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct G2Point { + pub x_0: ::ethers::core::types::U256, + pub x_1: ::ethers::core::types::U256, + pub y_0: ::ethers::core::types::U256, + pub y_1: ::ethers::core::types::U256, + } +} diff --git a/contracts/src/SimpleStakeTable.sol b/contracts/src/SimpleStakeTable.sol new file mode 100644 index 0000000000..dd976b8398 --- /dev/null +++ b/contracts/src/SimpleStakeTable.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { BN254 } from "bn254/BN254.sol"; + +/** + * @title SimpleStakeTable + * @dev An stake table mapping with owner-only access control. + */ +contract SimpleStakeTable is Ownable { + event Added(BN254.G2Point[]); + event Removed(BN254.G2Point[]); + + error StakerAlreadyExists(BN254.G2Point); + error StakerNotFound(BN254.G2Point); + + // State mapping from staker IDs to their staking status + mapping(bytes32 => bool) private stakers; + + constructor(address initialOwner) Ownable(initialOwner) { } + + function insert(BN254.G2Point[] memory newStakers) external onlyOwner { + // TODO: revert if array empty + for (uint256 i = 0; i < newStakers.length; i++) { + bytes32 stakerID = _hashBlsKey(newStakers[i]); + if (stakers[stakerID]) { + revert StakerAlreadyExists(newStakers[i]); + } + stakers[stakerID] = true; + } + emit Added(newStakers); + } + + function remove(BN254.G2Point[] memory stakersToRemove) external onlyOwner { + // TODO: revert if array empty + for (uint256 i = 0; i < stakersToRemove.length; i++) { + bytes32 stakerID = _hashBlsKey(stakersToRemove[i]); + if (!stakers[stakerID]) { + revert StakerNotFound(stakersToRemove[i]); + } + stakers[stakerID] = false; + } + emit Removed(stakersToRemove); + } + + function isStaker(BN254.G2Point memory staker) external view returns (bool) { + return stakers[_hashBlsKey(staker)]; + } + + function _hashBlsKey(BN254.G2Point memory blsVK) public pure returns (bytes32) { + return keccak256(abi.encode(blsVK.x0, blsVK.x1, blsVK.y0, blsVK.y1)); + } +} diff --git a/contracts/test/SimpleStakeTable.t.sol b/contracts/test/SimpleStakeTable.t.sol new file mode 100644 index 0000000000..a43799d9bd --- /dev/null +++ b/contracts/test/SimpleStakeTable.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; +import "../src/SimpleStakeTable.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; + +contract SimpleStakeTableTest is Test { + SimpleStakeTable stakeTable; + address owner = address(1); // mock owner address + + function setUp() public { + vm.prank(owner); // impersonate the owner + stakeTable = new SimpleStakeTable(owner); + } + + function points(uint64 num) private returns (BN254.G2Point[] memory) { + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "gen-random-g2-point"; + + BN254.G2Point[] memory ps = new BN254.G2Point[](num); + + for (uint64 i = 0; i < num; i++) { + cmds[2] = vm.toString(i + 1); + bytes memory result = vm.ffi(cmds); + BN254.G2Point memory p = abi.decode(result, (BN254.G2Point)); + ps[i] = p; + } + return ps; + } + + function testInsertAndIsStaker() public { + vm.prank(owner); + BN254.G2Point[] memory stakers = points(1); + stakeTable.insert(stakers); + assertTrue(stakeTable.isStaker(stakers[0])); + } + + function testInsertAndIsStakerMany() public { + vm.prank(owner); + BN254.G2Point[] memory stakers = points(10); + stakeTable.insert(stakers); + assertTrue(stakeTable.isStaker(stakers[0])); + } + + function testInsertRevertsIfStakerExists() public { + vm.prank(owner); + BN254.G2Point[] memory stakers = points(1); + stakeTable.insert(stakers); + + // Try adding the same staker again + vm.expectRevert( + abi.encodeWithSelector(SimpleStakeTable.StakerAlreadyExists.selector, stakers[0]) + ); + vm.prank(owner); + stakeTable.insert(stakers); + } + + function testRemoveAndIsNotStaker() public { + BN254.G2Point[] memory stakers = points(1); + vm.prank(owner); + stakeTable.insert(stakers); + + vm.prank(owner); + stakeTable.remove(stakers); + + assertFalse(stakeTable.isStaker(stakers[0])); + } + + function testRemoveRevertsIfStakerNotFound() public { + vm.prank(owner); + BN254.G2Point[] memory stakers = points(1); + vm.expectRevert(abi.encodeWithSelector(SimpleStakeTable.StakerNotFound.selector, stakers[0])); + // Attempt to remove a non-existent staker + stakeTable.remove(stakers); + } + + function testNonOwnerCannotInsert() public { + vm.prank(address(2)); + vm.expectRevert( + abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) + ); + BN254.G2Point[] memory stakers = points(1); + stakeTable.insert(stakers); + } + + function testNonOwnerCannotRemove() public { + vm.prank(address(2)); + vm.expectRevert( + abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) + ); + BN254.G2Point[] memory stakers = points(1); + stakeTable.remove(stakers); + } +} diff --git a/justfile b/justfile index 1bfd6f3eeb..fd2f6b0e6b 100644 --- a/justfile +++ b/justfile @@ -79,7 +79,7 @@ build-docker-images: scripts/build-docker-images-native # generate rust bindings for contracts -REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$|^PlonkVerifier2$" +REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$|^PlonkVerifier2$|^SimpleStakeTable$" gen-bindings: forge bind --contracts ./contracts/src/ --crate-name contract-bindings --bindings-path contract-bindings --select "{{REGEXP}}" --overwrite --force From 0bb15141b6224ed0a574d76e9de83d3c53e4802b Mon Sep 17 00:00:00 2001 From: sveitser Date: Mon, 25 Nov 2024 16:34:21 +0100 Subject: [PATCH 02/58] Add Schnorr verifying key --- contract-bindings/src/simple_stake_table.rs | 146 +++++++++++++++----- contracts/src/SimpleStakeTable.sol | 22 +-- contracts/test/SimpleStakeTable.t.sol | 37 ++--- 3 files changed, 144 insertions(+), 61 deletions(-) diff --git a/contract-bindings/src/simple_stake_table.rs b/contract-bindings/src/simple_stake_table.rs index c1176ca1d4..d36ca18527 100644 --- a/contract-bindings/src/simple_stake_table.rs +++ b/contract-bindings/src/simple_stake_table.rs @@ -59,15 +59,23 @@ pub mod simple_stake_table { kind: ::ethers::core::abi::ethabi::ParamType::Array( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), ],), ), ), internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point[]"), + ::std::borrow::ToOwned::to_owned( + "struct SimpleStakeTable.NodeInfo[]", + ), ), },], outputs: ::std::vec![], @@ -127,15 +135,23 @@ pub mod simple_stake_table { kind: ::ethers::core::abi::ethabi::ParamType::Array( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), ],), ), ), internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point[]"), + ::std::borrow::ToOwned::to_owned( + "struct SimpleStakeTable.NodeInfo[]", + ), ), },], outputs: ::std::vec![], @@ -180,10 +196,16 @@ pub mod simple_stake_table { kind: ::ethers::core::abi::ethabi::ParamType::Array( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), ],), ), ), @@ -220,10 +242,16 @@ pub mod simple_stake_table { kind: ::ethers::core::abi::ethabi::ParamType::Array( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), ],), ), ), @@ -305,12 +333,12 @@ pub mod simple_stake_table { pub static SIMPLESTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x07\xA88\x03\x80a\x07\xA8\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x06\xAB\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCE\xD4~f\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c=\x8D\x10@\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05\x1AV[a\x01)V[\0[a\0\x95a\x021V[a\0\xB2a\0\xAD6`\x04a\x05\xCDV[a\x02EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x05\xCDV[a\x02nV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05\x1AV[a\x02\xCAV[a\0\x95a\x01$6`\x04a\x05\xF0V[a\x03\xB2V[a\x011a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x01\xF6W`\0a\x01a\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[` \x02` \x01\x01Qa\x02nV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x01\xD5W\x82\x82\x81Q\x81\x10a\x01\x8DWa\x01\x8Da\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x014V[P\x7Fz\xC3a=\xC3\xB4>q#Y\x94 \xBDXa\x0C\xD6\xFF;\x14\xB6\x0E?%T\xA1\x0E\xC2\xCCM\x1E)\x81`@Qa\x02&\x91\x90a\x06/V[`@Q\x80\x91\x03\x90\xA1PV[a\x029a\x03\xF0V[a\x02C`\0a\x04\x1DV[V[`\0`\x01`\0a\x02T\x84a\x02nV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAD\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD2a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x03\x82W`\0a\x02\xF5\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03cW\x82\x82\x81Q\x81\x10a\x03 Wa\x03 a\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xCCV[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xD5V[P\x7F[L\xFC\x86_\xA8H:\x99<\xD6)\x1F\x0Cg\x18T\xFC\xBFnD\x89\xD8\xD6\x912\\\xF4\xD8\x08\xA6S\x81`@Qa\x02&\x91\x90a\x06/V[a\x03\xBAa\x03\xF0V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xE4W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xCCV[a\x03\xED\x81a\x04\x1DV[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02CW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xCCV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04mV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xC6W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xE9Wa\x04\xE9a\x04mV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05-W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05EW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05YW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05kWa\x05ka\x04mV[a\x05y\x84\x82`\x05\x1B\x01a\x04\x83V[\x81\x81R\x84\x81\x01\x92P`\x07\x91\x90\x91\x1B\x83\x01\x84\x01\x90\x87\x82\x11\x15a\x05\x99W`\0\x80\xFD[\x92\x84\x01\x92[\x81\x84\x10\x15a\x05\xC2Wa\x05\xB0\x88\x85a\x04\xB4V[\x83R\x84\x83\x01\x92P`\x80\x84\x01\x93Pa\x05\x9EV[\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x05\xDFW`\0\x80\xFD[a\x05\xE9\x83\x83a\x04\xB4V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\x02W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05\xE9W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x06\x92Wa\x06\x7F\x83\x85Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x92\x84\x01\x92`\x80\x92\x90\x92\x01\x91`\x01\x01a\x06KV[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x0828\x03\x80a\x082\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x075\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80cu\xD7\x05\xE9\x11a\0[W\x80cu\xD7\x05\xE9\x14a\0\xB2W\x80c\x8D\xA5\xCB[\x14a\0\xDAW\x80c\x9B0\xA5\xE6\x14a\0\xF5W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c\x0C\xE3\xA9\xFC\x14a\0\x82W\x80c+D\x1F\xF4\x14a\0\x97W\x80cqP\x18\xA6\x14a\0\xAAW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05IV[a\x01)V[\0[a\0\x95a\0\xA56`\x04a\x05IV[a\x023V[a\0\x95a\x03\x1FV[a\0\xC5a\0\xC06`\x04a\x06DV[a\x033V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xD1V[a\x01\x08a\x01\x036`\x04a\x06DV[a\x03\\V[`@Q\x90\x81R` \x01a\0\xD1V[a\0\x95a\x01$6`\x04a\x06gV[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[` \x02` \x01\x01Q`\0\x01Qa\x03\\V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xF7\xB8\xF5\xF8\xDE\xAC8N\xE1j\xF71\xFBzb\xE1cK\xDA\xA6\x08\x10lX\xC3\xA4\xC0,\xD3\x88\xEF\xFC\x81`@Qa\x02(\x91\x90a\x06\xA6V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x02\xEFW`\0a\x02^\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x02\xCEW\x82\x82\x81Q\x81\x10a\x02\x8AWa\x02\x8Aa\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02>V[P\x7F-\xE9\x19\xC4Rjy\x05\xBEtc\x1B\"#\x1C\x9D\xD2\xA5\xF2\x0F\xEB6\x97\xCF\x0E\xD3\xD8i\xFE\xF8\x07$\x81`@Qa\x02(\x91\x90a\x06\xA6V[a\x03'a\x03\xF6V[a\x031`\0a\x04#V[V[`\0`\x01`\0a\x03B\x84a\x03\\V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x03\x9B\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x031W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xDBWa\x04\xDBa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xF5W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05\x18Wa\x05\x18a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\\W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05tW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\x88W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\x9AWa\x05\x9Aa\x04sV[a\x05\xA8\x84\x82`\x05\x1B\x01a\x04\xB2V[\x81\x81R\x84\x81\x01\x92P`\xC0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xC7W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x068W\x84\x89\x03\x81\x81\x12\x15a\x05\xE5W`\0\x80\x81\xFD[a\x05\xEDa\x04\x89V[a\x05\xF7\x8B\x88a\x04\xE3V[\x81R`@`\x7F\x19\x83\x01\x12\x15a\x06\x0CW`\0\x80\x81\xFD[a\x06\x14a\x04\x89V[`\x80\x88\x015\x81R`\xA0\x88\x015\x89\x82\x01R\x81\x89\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xCCV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06VW`\0\x80\xFD[a\x06`\x83\x83a\x04\xE3V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06yW`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06`W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x07\x1CW\x83Qa\x06\xF8\x84\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x85\x01Q\x80Q`\x80\x85\x01R\x85\x01Q`\xA0\x84\x01R\x92\x84\x01\x92`\xC0\x90\x92\x01\x91`\x01\x01a\x06\xC2V[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; /// The bytecode of the contract. pub static SIMPLESTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCE\xD4~f\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c=\x8D\x10@\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05\x1AV[a\x01)V[\0[a\0\x95a\x021V[a\0\xB2a\0\xAD6`\x04a\x05\xCDV[a\x02EV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x05\xCDV[a\x02nV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05\x1AV[a\x02\xCAV[a\0\x95a\x01$6`\x04a\x05\xF0V[a\x03\xB2V[a\x011a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x01\xF6W`\0a\x01a\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[` \x02` \x01\x01Qa\x02nV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x01\xD5W\x82\x82\x81Q\x81\x10a\x01\x8DWa\x01\x8Da\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x014V[P\x7Fz\xC3a=\xC3\xB4>q#Y\x94 \xBDXa\x0C\xD6\xFF;\x14\xB6\x0E?%T\xA1\x0E\xC2\xCCM\x1E)\x81`@Qa\x02&\x91\x90a\x06/V[`@Q\x80\x91\x03\x90\xA1PV[a\x029a\x03\xF0V[a\x02C`\0a\x04\x1DV[V[`\0`\x01`\0a\x02T\x84a\x02nV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAD\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD2a\x03\xF0V[`\0[\x81Q\x81\x10\x15a\x03\x82W`\0a\x02\xF5\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x19V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03cW\x82\x82\x81Q\x81\x10a\x03 Wa\x03 a\x06\x19V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01Q`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xCCV[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xD5V[P\x7F[L\xFC\x86_\xA8H:\x99<\xD6)\x1F\x0Cg\x18T\xFC\xBFnD\x89\xD8\xD6\x912\\\xF4\xD8\x08\xA6S\x81`@Qa\x02&\x91\x90a\x06/V[a\x03\xBAa\x03\xF0V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xE4W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xCCV[a\x03\xED\x81a\x04\x1DV[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02CW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xCCV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04mV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xC6W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xE9Wa\x04\xE9a\x04mV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05-W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05EW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05YW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05kWa\x05ka\x04mV[a\x05y\x84\x82`\x05\x1B\x01a\x04\x83V[\x81\x81R\x84\x81\x01\x92P`\x07\x91\x90\x91\x1B\x83\x01\x84\x01\x90\x87\x82\x11\x15a\x05\x99W`\0\x80\xFD[\x92\x84\x01\x92[\x81\x84\x10\x15a\x05\xC2Wa\x05\xB0\x88\x85a\x04\xB4V[\x83R\x84\x83\x01\x92P`\x80\x84\x01\x93Pa\x05\x9EV[\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x05\xDFW`\0\x80\xFD[a\x05\xE9\x83\x83a\x04\xB4V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\x02W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05\xE9W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x06\x92Wa\x06\x7F\x83\x85Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x92\x84\x01\x92`\x80\x92\x90\x92\x01\x91`\x01\x01a\x06KV[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80cu\xD7\x05\xE9\x11a\0[W\x80cu\xD7\x05\xE9\x14a\0\xB2W\x80c\x8D\xA5\xCB[\x14a\0\xDAW\x80c\x9B0\xA5\xE6\x14a\0\xF5W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c\x0C\xE3\xA9\xFC\x14a\0\x82W\x80c+D\x1F\xF4\x14a\0\x97W\x80cqP\x18\xA6\x14a\0\xAAW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05IV[a\x01)V[\0[a\0\x95a\0\xA56`\x04a\x05IV[a\x023V[a\0\x95a\x03\x1FV[a\0\xC5a\0\xC06`\x04a\x06DV[a\x033V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xD1V[a\x01\x08a\x01\x036`\x04a\x06DV[a\x03\\V[`@Q\x90\x81R` \x01a\0\xD1V[a\0\x95a\x01$6`\x04a\x06gV[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[` \x02` \x01\x01Q`\0\x01Qa\x03\\V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xF7\xB8\xF5\xF8\xDE\xAC8N\xE1j\xF71\xFBzb\xE1cK\xDA\xA6\x08\x10lX\xC3\xA4\xC0,\xD3\x88\xEF\xFC\x81`@Qa\x02(\x91\x90a\x06\xA6V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x02\xEFW`\0a\x02^\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x02\xCEW\x82\x82\x81Q\x81\x10a\x02\x8AWa\x02\x8Aa\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02>V[P\x7F-\xE9\x19\xC4Rjy\x05\xBEtc\x1B\"#\x1C\x9D\xD2\xA5\xF2\x0F\xEB6\x97\xCF\x0E\xD3\xD8i\xFE\xF8\x07$\x81`@Qa\x02(\x91\x90a\x06\xA6V[a\x03'a\x03\xF6V[a\x031`\0a\x04#V[V[`\0`\x01`\0a\x03B\x84a\x03\\V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x03\x9B\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x031W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xDBWa\x04\xDBa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xF5W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05\x18Wa\x05\x18a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\\W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05tW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\x88W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\x9AWa\x05\x9Aa\x04sV[a\x05\xA8\x84\x82`\x05\x1B\x01a\x04\xB2V[\x81\x81R\x84\x81\x01\x92P`\xC0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xC7W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x068W\x84\x89\x03\x81\x81\x12\x15a\x05\xE5W`\0\x80\x81\xFD[a\x05\xEDa\x04\x89V[a\x05\xF7\x8B\x88a\x04\xE3V[\x81R`@`\x7F\x19\x83\x01\x12\x15a\x06\x0CW`\0\x80\x81\xFD[a\x06\x14a\x04\x89V[`\x80\x88\x015\x81R`\xA0\x88\x015\x89\x82\x01R\x81\x89\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xCCV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06VW`\0\x80\xFD[a\x06`\x83\x83a\x04\xE3V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06yW`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06`W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x07\x1CW\x83Qa\x06\xF8\x84\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x85\x01Q\x80Q`\x80\x85\x01R\x85\x01Q`\xA0\x84\x01R\x92\x84\x01\x92`\xC0\x90\x92\x01\x91`\x01\x01a\x06\xC2V[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; /// The deployed bytecode of the contract. pub static SIMPLESTAKETABLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); @@ -399,13 +427,13 @@ pub mod simple_stake_table { .method_hash([155, 48, 165, 230], (bls_vk,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `insert` (0x3d8d1040) function + ///Calls the contract's `insert` (0x2b441ff4) function pub fn insert( &self, - new_stakers: ::std::vec::Vec, + new_stakers: ::std::vec::Vec, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([61, 141, 16, 64], new_stakers) + .method_hash([43, 68, 31, 244], new_stakers) .expect("method not found (this should never happen)") } ///Calls the contract's `isStaker` (0x75d705e9) function @@ -425,13 +453,13 @@ pub mod simple_stake_table { .method_hash([141, 165, 203, 91], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `remove` (0xced47e66) function + ///Calls the contract's `remove` (0x0ce3a9fc) function pub fn remove( &self, - stakers_to_remove: ::std::vec::Vec, + stakers_to_remove: ::std::vec::Vec, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([206, 212, 126, 102], stakers_to_remove) + .method_hash([12, 227, 169, 252], stakers_to_remove) .expect("method not found (this should never happen)") } ///Calls the contract's `renounceOwnership` (0x715018a6) function @@ -699,8 +727,11 @@ pub mod simple_stake_table { Eq, Hash, )] - #[ethevent(name = "Added", abi = "Added((uint256,uint256,uint256,uint256)[])")] - pub struct AddedFilter(pub ::std::vec::Vec); + #[ethevent( + name = "Added", + abi = "Added(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" + )] + pub struct AddedFilter(pub ::std::vec::Vec); #[derive( Clone, ::ethers::contract::EthEvent, @@ -735,8 +766,11 @@ pub mod simple_stake_table { Eq, Hash, )] - #[ethevent(name = "Removed", abi = "Removed((uint256,uint256,uint256,uint256)[])")] - pub struct RemovedFilter(pub ::std::vec::Vec); + #[ethevent( + name = "Removed", + abi = "Removed(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" + )] + pub struct RemovedFilter(pub ::std::vec::Vec); ///Container type for all of the contract's events #[derive( Clone, @@ -813,7 +847,7 @@ pub mod simple_stake_table { pub struct HashBlsKeyCall { pub bls_vk: G2Point, } - ///Container type for all input parameters for the `insert` function with signature `insert((uint256,uint256,uint256,uint256)[])` and selector `0x3d8d1040` + ///Container type for all input parameters for the `insert` function with signature `insert(((uint256,uint256,uint256,uint256),(uint256,uint256))[])` and selector `0x2b441ff4` #[derive( Clone, ::ethers::contract::EthCall, @@ -826,9 +860,12 @@ pub mod simple_stake_table { Eq, Hash, )] - #[ethcall(name = "insert", abi = "insert((uint256,uint256,uint256,uint256)[])")] + #[ethcall( + name = "insert", + abi = "insert(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" + )] pub struct InsertCall { - pub new_stakers: ::std::vec::Vec, + pub new_stakers: ::std::vec::Vec, } ///Container type for all input parameters for the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` #[derive( @@ -862,7 +899,7 @@ pub mod simple_stake_table { )] #[ethcall(name = "owner", abi = "owner()")] pub struct OwnerCall; - ///Container type for all input parameters for the `remove` function with signature `remove((uint256,uint256,uint256,uint256)[])` and selector `0xced47e66` + ///Container type for all input parameters for the `remove` function with signature `remove(((uint256,uint256,uint256,uint256),(uint256,uint256))[])` and selector `0x0ce3a9fc` #[derive( Clone, ::ethers::contract::EthCall, @@ -875,9 +912,12 @@ pub mod simple_stake_table { Eq, Hash, )] - #[ethcall(name = "remove", abi = "remove((uint256,uint256,uint256,uint256)[])")] + #[ethcall( + name = "remove", + abi = "remove(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" + )] pub struct RemoveCall { - pub stakers_to_remove: ::std::vec::Vec, + pub stakers_to_remove: ::std::vec::Vec, } ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` #[derive( @@ -1086,4 +1126,38 @@ pub mod simple_stake_table { pub y_0: ::ethers::core::types::U256, pub y_1: ::ethers::core::types::U256, } + ///`EdOnBN254Point(uint256,uint256)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EdOnBN254Point { + pub x: ::ethers::core::types::U256, + pub y: ::ethers::core::types::U256, + } + ///`NodeInfo((uint256,uint256,uint256,uint256),(uint256,uint256))` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NodeInfo { + pub bls_vk: G2Point, + pub schnorr_vk: EdOnBN254Point, + } } diff --git a/contracts/src/SimpleStakeTable.sol b/contracts/src/SimpleStakeTable.sol index dd976b8398..bc83d470ea 100644 --- a/contracts/src/SimpleStakeTable.sol +++ b/contracts/src/SimpleStakeTable.sol @@ -3,41 +3,47 @@ pragma solidity ^0.8.0; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { BN254 } from "bn254/BN254.sol"; +import { EdOnBN254 } from "./libraries/EdOnBn254.sol"; /** * @title SimpleStakeTable * @dev An stake table mapping with owner-only access control. */ contract SimpleStakeTable is Ownable { - event Added(BN254.G2Point[]); - event Removed(BN254.G2Point[]); + event Added(NodeInfo[]); + event Removed(NodeInfo[]); error StakerAlreadyExists(BN254.G2Point); error StakerNotFound(BN254.G2Point); + struct NodeInfo { + BN254.G2Point blsVK; + EdOnBN254.EdOnBN254Point schnorrVK; + } + // State mapping from staker IDs to their staking status mapping(bytes32 => bool) private stakers; constructor(address initialOwner) Ownable(initialOwner) { } - function insert(BN254.G2Point[] memory newStakers) external onlyOwner { + function insert(NodeInfo[] memory newStakers) external onlyOwner { // TODO: revert if array empty for (uint256 i = 0; i < newStakers.length; i++) { - bytes32 stakerID = _hashBlsKey(newStakers[i]); + bytes32 stakerID = _hashBlsKey(newStakers[i].blsVK); if (stakers[stakerID]) { - revert StakerAlreadyExists(newStakers[i]); + revert StakerAlreadyExists(newStakers[i].blsVK); } stakers[stakerID] = true; } emit Added(newStakers); } - function remove(BN254.G2Point[] memory stakersToRemove) external onlyOwner { + function remove(NodeInfo[] memory stakersToRemove) external onlyOwner { // TODO: revert if array empty for (uint256 i = 0; i < stakersToRemove.length; i++) { - bytes32 stakerID = _hashBlsKey(stakersToRemove[i]); + bytes32 stakerID = _hashBlsKey(stakersToRemove[i].blsVK); if (!stakers[stakerID]) { - revert StakerNotFound(stakersToRemove[i]); + revert StakerNotFound(stakersToRemove[i].blsVK); } stakers[stakerID] = false; } diff --git a/contracts/test/SimpleStakeTable.t.sol b/contracts/test/SimpleStakeTable.t.sol index a43799d9bd..e25a520a00 100644 --- a/contracts/test/SimpleStakeTable.t.sol +++ b/contracts/test/SimpleStakeTable.t.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; -import "../src/SimpleStakeTable.sol"; +import { SimpleStakeTable } from "../src/SimpleStakeTable.sol"; +import { EdOnBN254 } from "../src/libraries/EdOnBn254.sol"; import { BN254 } from "bn254/BN254.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; @@ -15,64 +16,66 @@ contract SimpleStakeTableTest is Test { stakeTable = new SimpleStakeTable(owner); } - function points(uint64 num) private returns (BN254.G2Point[] memory) { + function nodes(uint64 num) private returns (SimpleStakeTable.NodeInfo[] memory) { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "gen-random-g2-point"; - BN254.G2Point[] memory ps = new BN254.G2Point[](num); + SimpleStakeTable.NodeInfo[] memory ps = new SimpleStakeTable.NodeInfo[](num); for (uint64 i = 0; i < num; i++) { cmds[2] = vm.toString(i + 1); bytes memory result = vm.ffi(cmds); - BN254.G2Point memory p = abi.decode(result, (BN254.G2Point)); - ps[i] = p; + BN254.G2Point memory bls = abi.decode(result, (BN254.G2Point)); + ps[i] = SimpleStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0)); } return ps; } function testInsertAndIsStaker() public { vm.prank(owner); - BN254.G2Point[] memory stakers = points(1); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); - assertTrue(stakeTable.isStaker(stakers[0])); + assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } function testInsertAndIsStakerMany() public { vm.prank(owner); - BN254.G2Point[] memory stakers = points(10); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(10); stakeTable.insert(stakers); - assertTrue(stakeTable.isStaker(stakers[0])); + assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } function testInsertRevertsIfStakerExists() public { vm.prank(owner); - BN254.G2Point[] memory stakers = points(1); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); // Try adding the same staker again vm.expectRevert( - abi.encodeWithSelector(SimpleStakeTable.StakerAlreadyExists.selector, stakers[0]) + abi.encodeWithSelector(SimpleStakeTable.StakerAlreadyExists.selector, stakers[0].blsVK) ); vm.prank(owner); stakeTable.insert(stakers); } function testRemoveAndIsNotStaker() public { - BN254.G2Point[] memory stakers = points(1); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); vm.prank(owner); stakeTable.insert(stakers); vm.prank(owner); stakeTable.remove(stakers); - assertFalse(stakeTable.isStaker(stakers[0])); + assertFalse(stakeTable.isStaker(stakers[0].blsVK)); } function testRemoveRevertsIfStakerNotFound() public { vm.prank(owner); - BN254.G2Point[] memory stakers = points(1); - vm.expectRevert(abi.encodeWithSelector(SimpleStakeTable.StakerNotFound.selector, stakers[0])); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + vm.expectRevert( + abi.encodeWithSelector(SimpleStakeTable.StakerNotFound.selector, stakers[0].blsVK) + ); // Attempt to remove a non-existent staker stakeTable.remove(stakers); } @@ -82,7 +85,7 @@ contract SimpleStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - BN254.G2Point[] memory stakers = points(1); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); } @@ -91,7 +94,7 @@ contract SimpleStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - BN254.G2Point[] memory stakers = points(1); + SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.remove(stakers); } } From 0c4df9a38a7051c0619eb6a9ab1f394ba5b884b8 Mon Sep 17 00:00:00 2001 From: sveitser Date: Mon, 25 Nov 2024 17:32:50 +0100 Subject: [PATCH 03/58] fix solhint error: named mapping keys and values --- contracts/src/SimpleStakeTable.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/SimpleStakeTable.sol b/contracts/src/SimpleStakeTable.sol index bc83d470ea..cd18c80fb2 100644 --- a/contracts/src/SimpleStakeTable.sol +++ b/contracts/src/SimpleStakeTable.sol @@ -22,7 +22,7 @@ contract SimpleStakeTable is Ownable { } // State mapping from staker IDs to their staking status - mapping(bytes32 => bool) private stakers; + mapping(bytes32 nodeID => bool isStaker) private stakers; constructor(address initialOwner) Ownable(initialOwner) { } From fdec50c9cd53d3541ee1528efb8b258bbd2cb5fd Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 11:59:26 +0100 Subject: [PATCH 04/58] WIP: contract stake table types to rust types Missing conversion from G2 Affine to BLSPubKey. --- Cargo.lock | 6 + contracts/rust/adapter/src/lib.rs | 1 + contracts/rust/adapter/src/stake_table.rs | 131 ++++++++++++++++++++++ contracts/src/SimpleStakeTable.sol | 2 +- types/Cargo.toml | 6 + types/src/lib.rs | 1 + types/src/v0/v0_3/mod.rs | 1 + types/src/v0/v0_3/stake_table.rs | 48 ++++++++ 8 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 contracts/rust/adapter/src/stake_table.rs create mode 100644 types/src/v0/v0_3/stake_table.rs diff --git a/Cargo.lock b/Cargo.lock index 9d6ccbb794..ad443eb18f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2841,6 +2841,9 @@ name = "espresso-types" version = "0.1.0" dependencies = [ "anyhow", + "ark-bn254", + "ark-ec", + "ark-ed-on-bn254", "ark-serialize", "async-broadcast", "async-trait", @@ -2853,16 +2856,19 @@ dependencies = [ "committable", "contract-bindings", "derive_more 1.0.0", + "diff-test-bn254", "dyn-clone", "ethers", "fluent-asserter", "futures", "hotshot", + "hotshot-contract-adapter", "hotshot-orchestrator", "hotshot-query-service", "hotshot-types", "itertools 0.12.1", "jf-merkle-tree", + "jf-signature 0.2.0", "jf-utils", "jf-vid", "lru 0.12.5", diff --git a/contracts/rust/adapter/src/lib.rs b/contracts/rust/adapter/src/lib.rs index b7cd11b355..8347358d4a 100644 --- a/contracts/rust/adapter/src/lib.rs +++ b/contracts/rust/adapter/src/lib.rs @@ -2,6 +2,7 @@ pub mod jellyfish; pub mod light_client; +pub mod stake_table; // Archived, legacy helpers and tests, to be removed soon. not included, reference/read only // mod archived diff --git a/contracts/rust/adapter/src/stake_table.rs b/contracts/rust/adapter/src/stake_table.rs new file mode 100644 index 0000000000..628e129f65 --- /dev/null +++ b/contracts/rust/adapter/src/stake_table.rs @@ -0,0 +1,131 @@ +use crate::jellyfish::u256_to_field; +use ark_ec::{ + twisted_edwards::{Affine, TECurveConfig}, + AffineRepr, +}; +use ark_ff::{BigInteger, Fp2, Fp2Config, PrimeField}; +use ethers::{ + abi::AbiDecode, + prelude::{AbiError, EthAbiCodec, EthAbiType}, + types::U256, +}; +use std::str::FromStr; + +// TODO: (alex) maybe move these commonly shared util to a crate +/// convert a field element to U256, panic if field size is larger than 256 bit +pub fn field_to_u256(f: F) -> U256 { + if F::MODULUS_BIT_SIZE > 256 { + panic!("Shouldn't convert a >256-bit field to U256"); + } + U256::from_little_endian(&f.into_bigint().to_bytes_le()) +} + +/// an intermediate representation of `BN254.G1Point` in solidity. +#[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] +pub struct ParsedG1Point { + /// x coordinate of affine repr + pub x: U256, + /// y coordinate of affine repr + pub y: U256, +} + +// this is convention from BN256 precompile +impl Default for ParsedG1Point { + fn default() -> Self { + Self { + x: U256::from(0), + y: U256::from(0), + } + } +} + +impl FromStr for ParsedG1Point { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl From> for ParsedG1Point +where + P::BaseField: PrimeField, +{ + fn from(p: Affine

) -> Self { + if p.is_zero() { + // this convention is from the BN precompile + Self { + x: U256::from(0), + y: U256::from(0), + } + } else { + Self { + x: field_to_u256::(*p.x().unwrap()), + y: field_to_u256::(*p.y().unwrap()), + } + } + } +} + +impl From for Affine

+where + P::BaseField: PrimeField, +{ + fn from(p: ParsedG1Point) -> Self { + if p == ParsedG1Point::default() { + Self::default() + } else { + Self::new_unchecked( + u256_to_field::(p.x), + u256_to_field::(p.y), + ) + } + } +} + +/// Intermediate representation of `G2Point` in Solidity +#[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] +pub struct ParsedG2Point { + /// x0 of x = x0 + u * x1 coordinate + pub x0: U256, + /// x1 of x = x0 + u * x1 coordinate + pub x1: U256, + /// y0 of y = y0 + u * y1 coordinate + pub y0: U256, + /// y1 of y = y0 + u * y1 coordinate + pub y1: U256, +} + +impl FromStr for ParsedG2Point { + type Err = AbiError; + fn from_str(s: &str) -> Result { + let parsed: (Self,) = AbiDecode::decode_hex(s)?; + Ok(parsed.0) + } +} + +impl>, C> From for Affine

+where + C: Fp2Config, +{ + fn from(p: ParsedG2Point) -> Self { + Self::new_unchecked( + Fp2::new(u256_to_field(p.x0), u256_to_field(p.x1)), + Fp2::new(u256_to_field(p.y0), u256_to_field(p.y1)), + ) + } +} + +impl>, C> From> for ParsedG2Point +where + C: Fp2Config, +{ + fn from(p: Affine

) -> Self { + Self { + x0: field_to_u256(p.x().unwrap().c0), + x1: field_to_u256(p.x().unwrap().c1), + y0: field_to_u256(p.y().unwrap().c0), + y1: field_to_u256(p.y().unwrap().c1), + } + } +} diff --git a/contracts/src/SimpleStakeTable.sol b/contracts/src/SimpleStakeTable.sol index cd18c80fb2..5293a7321f 100644 --- a/contracts/src/SimpleStakeTable.sol +++ b/contracts/src/SimpleStakeTable.sol @@ -26,7 +26,7 @@ contract SimpleStakeTable is Ownable { constructor(address initialOwner) Ownable(initialOwner) { } - function insert(NodeInfo[] memory newStakers) external onlyOwner { + function insert(NodeInfo[] memory newStakers) public onlyOwner { // TODO: revert if array empty for (uint256 i = 0; i < newStakers.length; i++) { bytes32 stakerID = _hashBlsKey(newStakers[i].blsVK); diff --git a/types/Cargo.toml b/types/Cargo.toml index 5d39890637..e6745dac3a 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -10,6 +10,9 @@ testing = [] [dependencies] anyhow = { workspace = true } +ark-bn254 = { workspace = true } +ark-ec = { workspace = true } +ark-ed-on-bn254 = { workspace = true } ark-serialize = { workspace = true } async-broadcast = { workspace = true } async-trait = { workspace = true } @@ -22,16 +25,19 @@ cld = { workspace = true } committable = { workspace = true } contract-bindings = { path = "../contract-bindings" } derive_more = { workspace = true } +diff-test-bn254 = { git = "https://github.com/EspressoSystems/solidity-bn254.git" } dyn-clone = { workspace = true } ethers = { workspace = true } fluent-asserter = "0.1.9" futures = { workspace = true } hotshot = { workspace = true } +hotshot-contract-adapter = { workspace = true } hotshot-orchestrator = { workspace = true } hotshot-query-service = { workspace = true } hotshot-types = { workspace = true } itertools = { workspace = true } jf-merkle-tree = { workspace = true } +jf-signature = { workspace = true } jf-utils = { workspace = true } # TODO temporary: used only for test_rng() jf-vid = { workspace = true } lru = { workspace = true } diff --git a/types/src/lib.rs b/types/src/lib.rs index 0ce6950965..54bfcbba7b 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -3,5 +3,6 @@ pub mod v0; // Re-export the latest major version compatibility types. pub use v0::*; +mod eth; pub mod eth_signature_key; mod reference_tests; diff --git a/types/src/v0/v0_3/mod.rs b/types/src/v0/v0_3/mod.rs index 86a0150a37..ec0da0fce9 100644 --- a/types/src/v0/v0_3/mod.rs +++ b/types/src/v0/v0_3/mod.rs @@ -21,6 +21,7 @@ mod chain_config; mod fee_info; mod header; mod solver; +mod stake_table; pub use auction::{BidTx, BidTxBody, FullNetworkTx, SolverAuctionResults}; pub use chain_config::*; diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs new file mode 100644 index 0000000000..0a3d07f26e --- /dev/null +++ b/types/src/v0/v0_3/stake_table.rs @@ -0,0 +1,48 @@ +use ark_ec::{bn, short_weierstrass, twisted_edwards}; +use ark_ed_on_bn254::EdwardsConfig; +use contract_bindings::simple_stake_table::{EdOnBN254Point, NodeInfo}; +use derive_more::derive::From; +use ethers::types::U256; +use hotshot::types::{BLSPubKey, SignatureKey}; +use hotshot_contract_adapter::stake_table::ParsedG1Point; +use hotshot_types::{light_client::StateVerKey, stake_table::StakeTableEntry, PeerConfig}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, From)] +struct PermissionedPeerConfig(pub(crate) PeerConfig); + +impl From for PermissionedPeerConfig { + fn from(node_info: NodeInfo) -> Self { + let NodeInfo { bls_vk, schnorr_vk } = node_info; + let stake_table_entry = { + let g2 = diff_test_bn254::ParsedG2Point { + x0: bls_vk.x_0, + x1: bls_vk.x_1, + y0: bls_vk.y_0, + y1: bls_vk.y_1, + }; + let g2_affine = short_weierstrass::Affine::::from(g2); + // let g2_proj = bn::G2Projective::from(g2_affine); + // TODO + let stake_key = BLSPubKey::generated_from_seed_indexed(Default::default(), 0).0; + StakeTableEntry { + stake_key, + stake_amount: U256::from(0), + } + }; + let state_ver_key = { + let EdOnBN254Point { x, y } = schnorr_vk; + let g1_point = ParsedG1Point { x, y }; + let state_sk_affine = twisted_edwards::Affine::::from(g1_point); + StateVerKey::from(state_sk_affine) + }; + PeerConfig { + stake_table_entry, + state_ver_key, + } + .into() + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +struct StakeTable(Vec>); From 4cfd276f1cba3b4bda94aa50fc529ee1a9585990 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 12:01:59 +0100 Subject: [PATCH 05/58] rename: SimpleStakeTable -> PermissionedStakeTable --- contract-bindings/src/lib.rs | 1 - contract-bindings/src/simple_stake_table.rs | 1163 ----------------- ...keTable.sol => PermissionedStakeTable.sol} | 2 +- ...ble.t.sol => PermissionedStakeTable.t.sol} | 34 +- 4 files changed, 19 insertions(+), 1181 deletions(-) delete mode 100644 contract-bindings/src/simple_stake_table.rs rename contracts/src/{SimpleStakeTable.sol => PermissionedStakeTable.sol} (97%) rename contracts/test/{SimpleStakeTable.t.sol => PermissionedStakeTable.t.sol} (65%) diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index 7a845305a4..cc6716e894 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -13,4 +13,3 @@ pub mod light_client_state_update_vk_mock; pub mod plonk_verifier; pub mod plonk_verifier_2; pub mod shared_types; -pub mod simple_stake_table; diff --git a/contract-bindings/src/simple_stake_table.rs b/contract-bindings/src/simple_stake_table.rs deleted file mode 100644 index d36ca18527..0000000000 --- a/contract-bindings/src/simple_stake_table.rs +++ /dev/null @@ -1,1163 +0,0 @@ -pub use simple_stake_table::*; -/// This module was auto-generated with ethers-rs Abigen. -/// More information at: -#[allow( - clippy::enum_variant_names, - clippy::too_many_arguments, - clippy::upper_case_acronyms, - clippy::type_complexity, - dead_code, - non_camel_case_types -)] -pub mod simple_stake_table { - #[allow(deprecated)] - fn __abi() -> ::ethers::core::abi::Abi { - ::ethers::core::abi::ethabi::Contract { - constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("initialOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some(::std::borrow::ToOwned::to_owned( - "address" - ),), - },], - }), - functions: ::core::convert::From::from([ - ( - ::std::borrow::ToOwned::to_owned("_hashBlsKey"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("_hashBlsKey"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("blsVK"), - kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), - ), - },], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes32"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::Pure, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("insert"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("insert"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("newStakers"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct SimpleStakeTable.NodeInfo[]", - ), - ), - },], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("isStaker"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("isStaker"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("staker"), - kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), - ), - },], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Bool, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bool"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("owner"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("owner"), - inputs: ::std::vec![], - outputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address"), - ), - },], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("remove"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("remove"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("stakersToRemove"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct SimpleStakeTable.NodeInfo[]", - ), - ), - },], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("renounceOwnership"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("renounceOwnership"), - inputs: ::std::vec![], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("transferOwnership"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("transferOwnership"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("newOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address"), - ), - },], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), - ]), - events: ::core::convert::From::from([ - ( - ::std::borrow::ToOwned::to_owned("Added"), - ::std::vec![::ethers::core::abi::ethabi::Event { - name: ::std::borrow::ToOwned::to_owned("Added"), - inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ],), - ), - ), - indexed: false, - },], - anonymous: false, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("OwnershipTransferred"), - ::std::vec![::ethers::core::abi::ethabi::Event { - name: ::std::borrow::ToOwned::to_owned("OwnershipTransferred",), - inputs: ::std::vec![ - ::ethers::core::abi::ethabi::EventParam { - name: ::std::borrow::ToOwned::to_owned("previousOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - indexed: true, - }, - ::ethers::core::abi::ethabi::EventParam { - name: ::std::borrow::ToOwned::to_owned("newOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - indexed: true, - }, - ], - anonymous: false, - },], - ), - ( - ::std::borrow::ToOwned::to_owned("Removed"), - ::std::vec![::ethers::core::abi::ethabi::Event { - name: ::std::borrow::ToOwned::to_owned("Removed"), - inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ],), - ), - ), - indexed: false, - },], - anonymous: false, - },], - ), - ]), - errors: ::core::convert::From::from([ - ( - ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner",), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("owner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address"), - ), - },], - },], - ), - ( - ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount",), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("account"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address"), - ), - },], - },], - ), - ( - ::std::borrow::ToOwned::to_owned("StakerAlreadyExists"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("StakerAlreadyExists",), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), - ), - },], - },], - ), - ( - ::std::borrow::ToOwned::to_owned("StakerNotFound"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("StakerNotFound"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), - ), - },], - },], - ), - ]), - receive: false, - fallback: false, - } - } - ///The parsed JSON ABI of the contract. - pub static SIMPLESTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = - ::ethers::contract::Lazy::new(__abi); - #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x0828\x03\x80a\x082\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x075\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80cu\xD7\x05\xE9\x11a\0[W\x80cu\xD7\x05\xE9\x14a\0\xB2W\x80c\x8D\xA5\xCB[\x14a\0\xDAW\x80c\x9B0\xA5\xE6\x14a\0\xF5W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c\x0C\xE3\xA9\xFC\x14a\0\x82W\x80c+D\x1F\xF4\x14a\0\x97W\x80cqP\x18\xA6\x14a\0\xAAW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05IV[a\x01)V[\0[a\0\x95a\0\xA56`\x04a\x05IV[a\x023V[a\0\x95a\x03\x1FV[a\0\xC5a\0\xC06`\x04a\x06DV[a\x033V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xD1V[a\x01\x08a\x01\x036`\x04a\x06DV[a\x03\\V[`@Q\x90\x81R` \x01a\0\xD1V[a\0\x95a\x01$6`\x04a\x06gV[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[` \x02` \x01\x01Q`\0\x01Qa\x03\\V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xF7\xB8\xF5\xF8\xDE\xAC8N\xE1j\xF71\xFBzb\xE1cK\xDA\xA6\x08\x10lX\xC3\xA4\xC0,\xD3\x88\xEF\xFC\x81`@Qa\x02(\x91\x90a\x06\xA6V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x02\xEFW`\0a\x02^\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x02\xCEW\x82\x82\x81Q\x81\x10a\x02\x8AWa\x02\x8Aa\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02>V[P\x7F-\xE9\x19\xC4Rjy\x05\xBEtc\x1B\"#\x1C\x9D\xD2\xA5\xF2\x0F\xEB6\x97\xCF\x0E\xD3\xD8i\xFE\xF8\x07$\x81`@Qa\x02(\x91\x90a\x06\xA6V[a\x03'a\x03\xF6V[a\x031`\0a\x04#V[V[`\0`\x01`\0a\x03B\x84a\x03\\V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x03\x9B\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x031W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xDBWa\x04\xDBa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xF5W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05\x18Wa\x05\x18a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\\W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05tW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\x88W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\x9AWa\x05\x9Aa\x04sV[a\x05\xA8\x84\x82`\x05\x1B\x01a\x04\xB2V[\x81\x81R\x84\x81\x01\x92P`\xC0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xC7W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x068W\x84\x89\x03\x81\x81\x12\x15a\x05\xE5W`\0\x80\x81\xFD[a\x05\xEDa\x04\x89V[a\x05\xF7\x8B\x88a\x04\xE3V[\x81R`@`\x7F\x19\x83\x01\x12\x15a\x06\x0CW`\0\x80\x81\xFD[a\x06\x14a\x04\x89V[`\x80\x88\x015\x81R`\xA0\x88\x015\x89\x82\x01R\x81\x89\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xCCV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06VW`\0\x80\xFD[a\x06`\x83\x83a\x04\xE3V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06yW`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06`W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x07\x1CW\x83Qa\x06\xF8\x84\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x85\x01Q\x80Q`\x80\x85\x01R\x85\x01Q`\xA0\x84\x01R\x92\x84\x01\x92`\xC0\x90\x92\x01\x91`\x01\x01a\x06\xC2V[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; - /// The bytecode of the contract. - pub static SIMPLESTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__BYTECODE); - #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80cu\xD7\x05\xE9\x11a\0[W\x80cu\xD7\x05\xE9\x14a\0\xB2W\x80c\x8D\xA5\xCB[\x14a\0\xDAW\x80c\x9B0\xA5\xE6\x14a\0\xF5W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80c\x0C\xE3\xA9\xFC\x14a\0\x82W\x80c+D\x1F\xF4\x14a\0\x97W\x80cqP\x18\xA6\x14a\0\xAAW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05IV[a\x01)V[\0[a\0\x95a\0\xA56`\x04a\x05IV[a\x023V[a\0\x95a\x03\x1FV[a\0\xC5a\0\xC06`\x04a\x06DV[a\x033V[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xD1V[a\x01\x08a\x01\x036`\x04a\x06DV[a\x03\\V[`@Q\x90\x81R` \x01a\0\xD1V[a\0\x95a\x01$6`\x04a\x06gV[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[` \x02` \x01\x01Q`\0\x01Qa\x03\\V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xF7\xB8\xF5\xF8\xDE\xAC8N\xE1j\xF71\xFBzb\xE1cK\xDA\xA6\x08\x10lX\xC3\xA4\xC0,\xD3\x88\xEF\xFC\x81`@Qa\x02(\x91\x90a\x06\xA6V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x02\xEFW`\0a\x02^\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\x90V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x02\xCEW\x82\x82\x81Q\x81\x10a\x02\x8AWa\x02\x8Aa\x06\x90V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02>V[P\x7F-\xE9\x19\xC4Rjy\x05\xBEtc\x1B\"#\x1C\x9D\xD2\xA5\xF2\x0F\xEB6\x97\xCF\x0E\xD3\xD8i\xFE\xF8\x07$\x81`@Qa\x02(\x91\x90a\x06\xA6V[a\x03'a\x03\xF6V[a\x031`\0a\x04#V[V[`\0`\x01`\0a\x03B\x84a\x03\\V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x03\x9B\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x031W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xDBWa\x04\xDBa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xF5W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05\x18Wa\x05\x18a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\\W`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05tW`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\x88W`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\x9AWa\x05\x9Aa\x04sV[a\x05\xA8\x84\x82`\x05\x1B\x01a\x04\xB2V[\x81\x81R\x84\x81\x01\x92P`\xC0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xC7W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x068W\x84\x89\x03\x81\x81\x12\x15a\x05\xE5W`\0\x80\x81\xFD[a\x05\xEDa\x04\x89V[a\x05\xF7\x8B\x88a\x04\xE3V[\x81R`@`\x7F\x19\x83\x01\x12\x15a\x06\x0CW`\0\x80\x81\xFD[a\x06\x14a\x04\x89V[`\x80\x88\x015\x81R`\xA0\x88\x015\x89\x82\x01R\x81\x89\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xCCV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06VW`\0\x80\xFD[a\x06`\x83\x83a\x04\xE3V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06yW`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06`W`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90\x84\x82\x01\x90`@\x85\x01\x90\x84[\x81\x81\x10\x15a\x07\x1CW\x83Qa\x06\xF8\x84\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x85\x01Q\x80Q`\x80\x85\x01R\x85\x01Q`\xA0\x84\x01R\x92\x84\x01\x92`\xC0\x90\x92\x01\x91`\x01\x01a\x06\xC2V[P\x90\x96\x95PPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; - /// The deployed bytecode of the contract. - pub static SIMPLESTAKETABLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = - ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); - pub struct SimpleStakeTable(::ethers::contract::Contract); - impl ::core::clone::Clone for SimpleStakeTable { - fn clone(&self) -> Self { - Self(::core::clone::Clone::clone(&self.0)) - } - } - impl ::core::ops::Deref for SimpleStakeTable { - type Target = ::ethers::contract::Contract; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl ::core::ops::DerefMut for SimpleStakeTable { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - impl ::core::fmt::Debug for SimpleStakeTable { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_tuple(::core::stringify!(SimpleStakeTable)) - .field(&self.address()) - .finish() - } - } - impl SimpleStakeTable { - /// Creates a new contract instance with the specified `ethers` client at - /// `address`. The contract derefs to a `ethers::Contract` object. - pub fn new>( - address: T, - client: ::std::sync::Arc, - ) -> Self { - Self(::ethers::contract::Contract::new( - address.into(), - SIMPLESTAKETABLE_ABI.clone(), - client, - )) - } - /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. - /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction - /// - /// Notes: - /// - If there are no constructor arguments, you should pass `()` as the argument. - /// - The default poll duration is 7 seconds. - /// - The default number of confirmations is 1 block. - /// - /// - /// # Example - /// - /// Generate contract bindings with `abigen!` and deploy a new contract instance. - /// - /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. - /// - /// ```ignore - /// # async fn deploy(client: ::std::sync::Arc) { - /// abigen!(Greeter, "../greeter.json"); - /// - /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); - /// let msg = greeter_contract.greet().call().await.unwrap(); - /// # } - /// ``` - pub fn deploy( - client: ::std::sync::Arc, - constructor_args: T, - ) -> ::core::result::Result< - ::ethers::contract::builders::ContractDeployer, - ::ethers::contract::ContractError, - > { - let factory = ::ethers::contract::ContractFactory::new( - SIMPLESTAKETABLE_ABI.clone(), - SIMPLESTAKETABLE_BYTECODE.clone().into(), - client, - ); - let deployer = factory.deploy(constructor_args)?; - let deployer = ::ethers::contract::ContractDeployer::new(deployer); - Ok(deployer) - } - ///Calls the contract's `_hashBlsKey` (0x9b30a5e6) function - pub fn hash_bls_key( - &self, - bls_vk: G2Point, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([155, 48, 165, 230], (bls_vk,)) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `insert` (0x2b441ff4) function - pub fn insert( - &self, - new_stakers: ::std::vec::Vec, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([43, 68, 31, 244], new_stakers) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `isStaker` (0x75d705e9) function - pub fn is_staker( - &self, - staker: G2Point, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([117, 215, 5, 233], (staker,)) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `owner` (0x8da5cb5b) function - pub fn owner( - &self, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([141, 165, 203, 91], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `remove` (0x0ce3a9fc) function - pub fn remove( - &self, - stakers_to_remove: ::std::vec::Vec, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([12, 227, 169, 252], stakers_to_remove) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `renounceOwnership` (0x715018a6) function - pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([113, 80, 24, 166], ()) - .expect("method not found (this should never happen)") - } - ///Calls the contract's `transferOwnership` (0xf2fde38b) function - pub fn transfer_ownership( - &self, - new_owner: ::ethers::core::types::Address, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([242, 253, 227, 139], new_owner) - .expect("method not found (this should never happen)") - } - ///Gets the contract's `Added` event - pub fn added_filter( - &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, AddedFilter> { - self.0.event() - } - ///Gets the contract's `OwnershipTransferred` event - pub fn ownership_transferred_filter( - &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> - { - self.0.event() - } - ///Gets the contract's `Removed` event - pub fn removed_filter( - &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RemovedFilter> { - self.0.event() - } - /// Returns an `Event` builder for all the events of this contract. - pub fn events( - &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, SimpleStakeTableEvents> - { - self.0 - .event_with_filter(::core::default::Default::default()) - } - } - impl From<::ethers::contract::Contract> - for SimpleStakeTable - { - fn from(contract: ::ethers::contract::Contract) -> Self { - Self::new(contract.address(), contract.client()) - } - } - ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` - #[derive( - Clone, - ::ethers::contract::EthError, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[etherror(name = "OwnableInvalidOwner", abi = "OwnableInvalidOwner(address)")] - pub struct OwnableInvalidOwner { - pub owner: ::ethers::core::types::Address, - } - ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` - #[derive( - Clone, - ::ethers::contract::EthError, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[etherror( - name = "OwnableUnauthorizedAccount", - abi = "OwnableUnauthorizedAccount(address)" - )] - pub struct OwnableUnauthorizedAccount { - pub account: ::ethers::core::types::Address, - } - ///Custom Error type `StakerAlreadyExists` with signature `StakerAlreadyExists((uint256,uint256,uint256,uint256))` and selector `0x360dc282` - #[derive( - Clone, - ::ethers::contract::EthError, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[etherror( - name = "StakerAlreadyExists", - abi = "StakerAlreadyExists((uint256,uint256,uint256,uint256))" - )] - pub struct StakerAlreadyExists(pub G2Point); - ///Custom Error type `StakerNotFound` with signature `StakerNotFound((uint256,uint256,uint256,uint256))` and selector `0x34a7561f` - #[derive( - Clone, - ::ethers::contract::EthError, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[etherror( - name = "StakerNotFound", - abi = "StakerNotFound((uint256,uint256,uint256,uint256))" - )] - pub struct StakerNotFound(pub G2Point); - ///Container type for all of the contract's custom errors - #[derive( - Clone, - ::ethers::contract::EthAbiType, - serde::Serialize, - serde::Deserialize, - Debug, - PartialEq, - Eq, - Hash, - )] - pub enum SimpleStakeTableErrors { - OwnableInvalidOwner(OwnableInvalidOwner), - OwnableUnauthorizedAccount(OwnableUnauthorizedAccount), - StakerAlreadyExists(StakerAlreadyExists), - StakerNotFound(StakerNotFound), - /// The standard solidity revert string, with selector - /// Error(string) -- 0x08c379a0 - RevertString(::std::string::String), - } - impl ::ethers::core::abi::AbiDecode for SimpleStakeTableErrors { - fn decode( - data: impl AsRef<[u8]>, - ) -> ::core::result::Result { - let data = data.as_ref(); - if let Ok(decoded) = - <::std::string::String as ::ethers::core::abi::AbiDecode>::decode(data) - { - return Ok(Self::RevertString(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::OwnableInvalidOwner(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::OwnableUnauthorizedAccount(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::StakerAlreadyExists(decoded)); - } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::StakerNotFound(decoded)); - } - Err(::ethers::core::abi::Error::InvalidData.into()) - } - } - impl ::ethers::core::abi::AbiEncode for SimpleStakeTableErrors { - fn encode(self) -> ::std::vec::Vec { - match self { - Self::OwnableInvalidOwner(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } - Self::OwnableUnauthorizedAccount(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } - Self::StakerAlreadyExists(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } - Self::StakerNotFound(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), - } - } - } - impl ::ethers::contract::ContractRevert for SimpleStakeTableErrors { - fn valid_selector(selector: [u8; 4]) -> bool { - match selector { - [0x08, 0xc3, 0x79, 0xa0] => true, - _ if selector - == ::selector() => - { - true - } - _ if selector - == ::selector() => - { - true - } - _ if selector - == ::selector() => - { - true - } - _ if selector == ::selector() => { - true - } - _ => false, - } - } - } - impl ::core::fmt::Display for SimpleStakeTableErrors { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - match self { - Self::OwnableInvalidOwner(element) => ::core::fmt::Display::fmt(element, f), - Self::OwnableUnauthorizedAccount(element) => ::core::fmt::Display::fmt(element, f), - Self::StakerAlreadyExists(element) => ::core::fmt::Display::fmt(element, f), - Self::StakerNotFound(element) => ::core::fmt::Display::fmt(element, f), - Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), - } - } - } - impl ::core::convert::From<::std::string::String> for SimpleStakeTableErrors { - fn from(value: String) -> Self { - Self::RevertString(value) - } - } - impl ::core::convert::From for SimpleStakeTableErrors { - fn from(value: OwnableInvalidOwner) -> Self { - Self::OwnableInvalidOwner(value) - } - } - impl ::core::convert::From for SimpleStakeTableErrors { - fn from(value: OwnableUnauthorizedAccount) -> Self { - Self::OwnableUnauthorizedAccount(value) - } - } - impl ::core::convert::From for SimpleStakeTableErrors { - fn from(value: StakerAlreadyExists) -> Self { - Self::StakerAlreadyExists(value) - } - } - impl ::core::convert::From for SimpleStakeTableErrors { - fn from(value: StakerNotFound) -> Self { - Self::StakerNotFound(value) - } - } - #[derive( - Clone, - ::ethers::contract::EthEvent, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethevent( - name = "Added", - abi = "Added(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" - )] - pub struct AddedFilter(pub ::std::vec::Vec); - #[derive( - Clone, - ::ethers::contract::EthEvent, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethevent( - name = "OwnershipTransferred", - abi = "OwnershipTransferred(address,address)" - )] - pub struct OwnershipTransferredFilter { - #[ethevent(indexed)] - pub previous_owner: ::ethers::core::types::Address, - #[ethevent(indexed)] - pub new_owner: ::ethers::core::types::Address, - } - #[derive( - Clone, - ::ethers::contract::EthEvent, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethevent( - name = "Removed", - abi = "Removed(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" - )] - pub struct RemovedFilter(pub ::std::vec::Vec); - ///Container type for all of the contract's events - #[derive( - Clone, - ::ethers::contract::EthAbiType, - serde::Serialize, - serde::Deserialize, - Debug, - PartialEq, - Eq, - Hash, - )] - pub enum SimpleStakeTableEvents { - AddedFilter(AddedFilter), - OwnershipTransferredFilter(OwnershipTransferredFilter), - RemovedFilter(RemovedFilter), - } - impl ::ethers::contract::EthLogDecode for SimpleStakeTableEvents { - fn decode_log( - log: &::ethers::core::abi::RawLog, - ) -> ::core::result::Result { - if let Ok(decoded) = AddedFilter::decode_log(log) { - return Ok(SimpleStakeTableEvents::AddedFilter(decoded)); - } - if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { - return Ok(SimpleStakeTableEvents::OwnershipTransferredFilter(decoded)); - } - if let Ok(decoded) = RemovedFilter::decode_log(log) { - return Ok(SimpleStakeTableEvents::RemovedFilter(decoded)); - } - Err(::ethers::core::abi::Error::InvalidData) - } - } - impl ::core::fmt::Display for SimpleStakeTableEvents { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - match self { - Self::AddedFilter(element) => ::core::fmt::Display::fmt(element, f), - Self::OwnershipTransferredFilter(element) => ::core::fmt::Display::fmt(element, f), - Self::RemovedFilter(element) => ::core::fmt::Display::fmt(element, f), - } - } - } - impl ::core::convert::From for SimpleStakeTableEvents { - fn from(value: AddedFilter) -> Self { - Self::AddedFilter(value) - } - } - impl ::core::convert::From for SimpleStakeTableEvents { - fn from(value: OwnershipTransferredFilter) -> Self { - Self::OwnershipTransferredFilter(value) - } - } - impl ::core::convert::From for SimpleStakeTableEvents { - fn from(value: RemovedFilter) -> Self { - Self::RemovedFilter(value) - } - } - ///Container type for all input parameters for the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall( - name = "_hashBlsKey", - abi = "_hashBlsKey((uint256,uint256,uint256,uint256))" - )] - pub struct HashBlsKeyCall { - pub bls_vk: G2Point, - } - ///Container type for all input parameters for the `insert` function with signature `insert(((uint256,uint256,uint256,uint256),(uint256,uint256))[])` and selector `0x2b441ff4` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall( - name = "insert", - abi = "insert(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" - )] - pub struct InsertCall { - pub new_stakers: ::std::vec::Vec, - } - ///Container type for all input parameters for the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "isStaker", abi = "isStaker((uint256,uint256,uint256,uint256))")] - pub struct IsStakerCall { - pub staker: G2Point, - } - ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "owner", abi = "owner()")] - pub struct OwnerCall; - ///Container type for all input parameters for the `remove` function with signature `remove(((uint256,uint256,uint256,uint256),(uint256,uint256))[])` and selector `0x0ce3a9fc` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall( - name = "remove", - abi = "remove(((uint256,uint256,uint256,uint256),(uint256,uint256))[])" - )] - pub struct RemoveCall { - pub stakers_to_remove: ::std::vec::Vec, - } - ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] - pub struct RenounceOwnershipCall; - ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] - pub struct TransferOwnershipCall { - pub new_owner: ::ethers::core::types::Address, - } - ///Container type for all of the contract's call - #[derive( - Clone, - ::ethers::contract::EthAbiType, - serde::Serialize, - serde::Deserialize, - Debug, - PartialEq, - Eq, - Hash, - )] - pub enum SimpleStakeTableCalls { - HashBlsKey(HashBlsKeyCall), - Insert(InsertCall), - IsStaker(IsStakerCall), - Owner(OwnerCall), - Remove(RemoveCall), - RenounceOwnership(RenounceOwnershipCall), - TransferOwnership(TransferOwnershipCall), - } - impl ::ethers::core::abi::AbiDecode for SimpleStakeTableCalls { - fn decode( - data: impl AsRef<[u8]>, - ) -> ::core::result::Result { - let data = data.as_ref(); - if let Ok(decoded) = ::decode(data) { - return Ok(Self::HashBlsKey(decoded)); - } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Insert(decoded)); - } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::IsStaker(decoded)); - } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Owner(decoded)); - } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Remove(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::RenounceOwnership(decoded)); - } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::TransferOwnership(decoded)); - } - Err(::ethers::core::abi::Error::InvalidData.into()) - } - } - impl ::ethers::core::abi::AbiEncode for SimpleStakeTableCalls { - fn encode(self) -> Vec { - match self { - Self::HashBlsKey(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Insert(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::IsStaker(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Remove(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::RenounceOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::TransferOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), - } - } - } - impl ::core::fmt::Display for SimpleStakeTableCalls { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - match self { - Self::HashBlsKey(element) => ::core::fmt::Display::fmt(element, f), - Self::Insert(element) => ::core::fmt::Display::fmt(element, f), - Self::IsStaker(element) => ::core::fmt::Display::fmt(element, f), - Self::Owner(element) => ::core::fmt::Display::fmt(element, f), - Self::Remove(element) => ::core::fmt::Display::fmt(element, f), - Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), - Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), - } - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: HashBlsKeyCall) -> Self { - Self::HashBlsKey(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: InsertCall) -> Self { - Self::Insert(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: IsStakerCall) -> Self { - Self::IsStaker(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: OwnerCall) -> Self { - Self::Owner(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: RemoveCall) -> Self { - Self::Remove(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: RenounceOwnershipCall) -> Self { - Self::RenounceOwnership(value) - } - } - impl ::core::convert::From for SimpleStakeTableCalls { - fn from(value: TransferOwnershipCall) -> Self { - Self::TransferOwnership(value) - } - } - ///Container type for all return fields from the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct HashBlsKeyReturn(pub [u8; 32]); - ///Container type for all return fields from the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct IsStakerReturn(pub bool); - ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct OwnerReturn(pub ::ethers::core::types::Address); - ///`G2Point(uint256,uint256,uint256,uint256)` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct G2Point { - pub x_0: ::ethers::core::types::U256, - pub x_1: ::ethers::core::types::U256, - pub y_0: ::ethers::core::types::U256, - pub y_1: ::ethers::core::types::U256, - } - ///`EdOnBN254Point(uint256,uint256)` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct EdOnBN254Point { - pub x: ::ethers::core::types::U256, - pub y: ::ethers::core::types::U256, - } - ///`NodeInfo((uint256,uint256,uint256,uint256),(uint256,uint256))` - #[derive( - Clone, - ::ethers::contract::EthAbiType, - ::ethers::contract::EthAbiCodec, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - pub struct NodeInfo { - pub bls_vk: G2Point, - pub schnorr_vk: EdOnBN254Point, - } -} diff --git a/contracts/src/SimpleStakeTable.sol b/contracts/src/PermissionedStakeTable.sol similarity index 97% rename from contracts/src/SimpleStakeTable.sol rename to contracts/src/PermissionedStakeTable.sol index 5293a7321f..3491dea3fc 100644 --- a/contracts/src/SimpleStakeTable.sol +++ b/contracts/src/PermissionedStakeTable.sol @@ -9,7 +9,7 @@ import { EdOnBN254 } from "./libraries/EdOnBn254.sol"; * @title SimpleStakeTable * @dev An stake table mapping with owner-only access control. */ -contract SimpleStakeTable is Ownable { +contract PermissionedStakeTable is Ownable { event Added(NodeInfo[]); event Removed(NodeInfo[]); diff --git a/contracts/test/SimpleStakeTable.t.sol b/contracts/test/PermissionedStakeTable.t.sol similarity index 65% rename from contracts/test/SimpleStakeTable.t.sol rename to contracts/test/PermissionedStakeTable.t.sol index e25a520a00..abdf82d681 100644 --- a/contracts/test/SimpleStakeTable.t.sol +++ b/contracts/test/PermissionedStakeTable.t.sol @@ -2,65 +2,67 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; -import { SimpleStakeTable } from "../src/SimpleStakeTable.sol"; +import { PermissionedStakeTable } from "../src/PermissionedStakeTable.sol"; import { EdOnBN254 } from "../src/libraries/EdOnBn254.sol"; import { BN254 } from "bn254/BN254.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -contract SimpleStakeTableTest is Test { - SimpleStakeTable stakeTable; +contract PermissionedStakeTableTest is Test { + PermissionedStakeTable stakeTable; address owner = address(1); // mock owner address function setUp() public { vm.prank(owner); // impersonate the owner - stakeTable = new SimpleStakeTable(owner); + stakeTable = new PermissionedStakeTable(owner); } - function nodes(uint64 num) private returns (SimpleStakeTable.NodeInfo[] memory) { + function nodes(uint64 num) private returns (PermissionedStakeTable.NodeInfo[] memory) { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "gen-random-g2-point"; - SimpleStakeTable.NodeInfo[] memory ps = new SimpleStakeTable.NodeInfo[](num); + PermissionedStakeTable.NodeInfo[] memory ps = new PermissionedStakeTable.NodeInfo[](num); for (uint64 i = 0; i < num; i++) { cmds[2] = vm.toString(i + 1); bytes memory result = vm.ffi(cmds); BN254.G2Point memory bls = abi.decode(result, (BN254.G2Point)); - ps[i] = SimpleStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0)); + ps[i] = PermissionedStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0)); } return ps; } function testInsertAndIsStaker() public { vm.prank(owner); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } function testInsertAndIsStakerMany() public { vm.prank(owner); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(10); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(10); stakeTable.insert(stakers); assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } function testInsertRevertsIfStakerExists() public { vm.prank(owner); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); // Try adding the same staker again vm.expectRevert( - abi.encodeWithSelector(SimpleStakeTable.StakerAlreadyExists.selector, stakers[0].blsVK) + abi.encodeWithSelector( + PermissionedStakeTable.StakerAlreadyExists.selector, stakers[0].blsVK + ) ); vm.prank(owner); stakeTable.insert(stakers); } function testRemoveAndIsNotStaker() public { - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); vm.prank(owner); stakeTable.insert(stakers); @@ -72,9 +74,9 @@ contract SimpleStakeTableTest is Test { function testRemoveRevertsIfStakerNotFound() public { vm.prank(owner); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); vm.expectRevert( - abi.encodeWithSelector(SimpleStakeTable.StakerNotFound.selector, stakers[0].blsVK) + abi.encodeWithSelector(PermissionedStakeTable.StakerNotFound.selector, stakers[0].blsVK) ); // Attempt to remove a non-existent staker stakeTable.remove(stakers); @@ -85,7 +87,7 @@ contract SimpleStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.insert(stakers); } @@ -94,7 +96,7 @@ contract SimpleStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - SimpleStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); stakeTable.remove(stakers); } } From 10d3d13f709a6fd489169b5bc8e1156c34cd91e3 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 12:18:44 +0100 Subject: [PATCH 06/58] PermissionedStakeTable contract: add DA flag - Update bindings. - Add tests for event emission. --- .typos.toml | 1 + contract-bindings/src/lib.rs | 1 + .../src/permissioned_stake_table.rs | 1170 +++++++++++++++++ contracts/src/PermissionedStakeTable.sol | 4 + contracts/test/PermissionedStakeTable.t.sol | 22 +- justfile | 2 +- types/src/v0/v0_3/stake_table.rs | 11 +- 7 files changed, 1203 insertions(+), 8 deletions(-) create mode 100644 contract-bindings/src/permissioned_stake_table.rs diff --git a/.typos.toml b/.typos.toml index 48ac32a608..d80b10dae9 100644 --- a/.typos.toml +++ b/.typos.toml @@ -2,6 +2,7 @@ extend-exclude = [ ".env", "*.json", + "**/*.pdf", "doc/*.svg", "doc/*.puml", "contracts/lib", diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index cc6716e894..ee76dcf578 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -10,6 +10,7 @@ pub mod light_client; pub mod light_client_mock; pub mod light_client_state_update_vk; pub mod light_client_state_update_vk_mock; +pub mod permissioned_stake_table; pub mod plonk_verifier; pub mod plonk_verifier_2; pub mod shared_types; diff --git a/contract-bindings/src/permissioned_stake_table.rs b/contract-bindings/src/permissioned_stake_table.rs new file mode 100644 index 0000000000..f7919ce378 --- /dev/null +++ b/contract-bindings/src/permissioned_stake_table.rs @@ -0,0 +1,1170 @@ +pub use permissioned_stake_table::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod permissioned_stake_table { + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("initialOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some(::std::borrow::ToOwned::to_owned( + "address" + ),), + },], + }), + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("_hashBlsKey"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("_hashBlsKey"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("blsVK"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bytes32"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::Pure, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("insert"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("insert"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("newStakers"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("isStaker"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("isStaker"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("staker"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("owner"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("owner"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("remove"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("remove"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("stakersToRemove"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("renounceOwnership"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("renounceOwnership"), + inputs: ::std::vec![], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("transferOwnership"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("transferOwnership"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("newOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, + },], + ), + ]), + events: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("Added"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("Added"), + inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ],), + ), + ), + indexed: false, + },], + anonymous: false, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("OwnershipTransferred"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("OwnershipTransferred",), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("previousOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + indexed: true, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("newOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + indexed: true, + }, + ], + anonymous: false, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("Removed"), + ::std::vec![::ethers::core::abi::ethabi::Event { + name: ::std::borrow::ToOwned::to_owned("Removed"), + inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ],), + ), + ), + indexed: false, + },], + anonymous: false, + },], + ), + ]), + errors: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("OwnableInvalidOwner",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("owner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("OwnableUnauthorizedAccount",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("account"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("StakerAlreadyExists"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("StakerAlreadyExists",), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + },], + ), + ( + ::std::borrow::ToOwned::to_owned("StakerNotFound"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("StakerNotFound"), + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("struct BN254.G2Point"), + ), + },], + },], + ), + ]), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static PERMISSIONEDSTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x08~8\x03\x80a\x08~\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x07\x81\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + /// The bytecode of the contract. + pub static PERMISSIONEDSTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + /// The deployed bytecode of the contract. + pub static PERMISSIONEDSTAKETABLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct PermissionedStakeTable(::ethers::contract::Contract); + impl ::core::clone::Clone for PermissionedStakeTable { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for PermissionedStakeTable { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for PermissionedStakeTable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for PermissionedStakeTable { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(PermissionedStakeTable)) + .field(&self.address()) + .finish() + } + } + impl PermissionedStakeTable { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + PERMISSIONEDSTAKETABLE_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + PERMISSIONEDSTAKETABLE_ABI.clone(), + PERMISSIONEDSTAKETABLE_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `_hashBlsKey` (0x9b30a5e6) function + pub fn hash_bls_key( + &self, + bls_vk: G2Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([155, 48, 165, 230], (bls_vk,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `insert` (0xcd1da5e5) function + pub fn insert( + &self, + new_stakers: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([205, 29, 165, 229], new_stakers) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `isStaker` (0x75d705e9) function + pub fn is_staker( + &self, + staker: G2Point, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([117, 215, 5, 233], (staker,)) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `owner` (0x8da5cb5b) function + pub fn owner( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([141, 165, 203, 91], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `remove` (0x51826034) function + pub fn remove( + &self, + stakers_to_remove: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([81, 130, 96, 52], stakers_to_remove) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `renounceOwnership` (0x715018a6) function + pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([113, 80, 24, 166], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `transferOwnership` (0xf2fde38b) function + pub fn transfer_ownership( + &self, + new_owner: ::ethers::core::types::Address, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([242, 253, 227, 139], new_owner) + .expect("method not found (this should never happen)") + } + ///Gets the contract's `Added` event + pub fn added_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, AddedFilter> { + self.0.event() + } + ///Gets the contract's `OwnershipTransferred` event + pub fn ownership_transferred_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> + { + self.0.event() + } + ///Gets the contract's `Removed` event + pub fn removed_filter( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RemovedFilter> { + self.0.event() + } + /// Returns an `Event` builder for all the events of this contract. + pub fn events( + &self, + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, PermissionedStakeTableEvents> + { + self.0 + .event_with_filter(::core::default::Default::default()) + } + } + impl From<::ethers::contract::Contract> + for PermissionedStakeTable + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "OwnableInvalidOwner", abi = "OwnableInvalidOwner(address)")] + pub struct OwnableInvalidOwner { + pub owner: ::ethers::core::types::Address, + } + ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "OwnableUnauthorizedAccount", + abi = "OwnableUnauthorizedAccount(address)" + )] + pub struct OwnableUnauthorizedAccount { + pub account: ::ethers::core::types::Address, + } + ///Custom Error type `StakerAlreadyExists` with signature `StakerAlreadyExists((uint256,uint256,uint256,uint256))` and selector `0x360dc282` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "StakerAlreadyExists", + abi = "StakerAlreadyExists((uint256,uint256,uint256,uint256))" + )] + pub struct StakerAlreadyExists(pub G2Point); + ///Custom Error type `StakerNotFound` with signature `StakerNotFound((uint256,uint256,uint256,uint256))` and selector `0x34a7561f` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror( + name = "StakerNotFound", + abi = "StakerNotFound((uint256,uint256,uint256,uint256))" + )] + pub struct StakerNotFound(pub G2Point); + ///Container type for all of the contract's custom errors + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum PermissionedStakeTableErrors { + OwnableInvalidOwner(OwnableInvalidOwner), + OwnableUnauthorizedAccount(OwnableUnauthorizedAccount), + StakerAlreadyExists(StakerAlreadyExists), + StakerNotFound(StakerNotFound), + /// The standard solidity revert string, with selector + /// Error(string) -- 0x08c379a0 + RevertString(::std::string::String), + } + impl ::ethers::core::abi::AbiDecode for PermissionedStakeTableErrors { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = + <::std::string::String as ::ethers::core::abi::AbiDecode>::decode(data) + { + return Ok(Self::RevertString(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::OwnableInvalidOwner(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::OwnableUnauthorizedAccount(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::StakerAlreadyExists(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::StakerNotFound(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for PermissionedStakeTableErrors { + fn encode(self) -> ::std::vec::Vec { + match self { + Self::OwnableInvalidOwner(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::OwnableUnauthorizedAccount(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::StakerAlreadyExists(element) => { + ::ethers::core::abi::AbiEncode::encode(element) + } + Self::StakerNotFound(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), + } + } + } + impl ::ethers::contract::ContractRevert for PermissionedStakeTableErrors { + fn valid_selector(selector: [u8; 4]) -> bool { + match selector { + [0x08, 0xc3, 0x79, 0xa0] => true, + _ if selector + == ::selector() => + { + true + } + _ if selector + == ::selector() => + { + true + } + _ if selector + == ::selector() => + { + true + } + _ if selector == ::selector() => { + true + } + _ => false, + } + } + } + impl ::core::fmt::Display for PermissionedStakeTableErrors { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::OwnableInvalidOwner(element) => ::core::fmt::Display::fmt(element, f), + Self::OwnableUnauthorizedAccount(element) => ::core::fmt::Display::fmt(element, f), + Self::StakerAlreadyExists(element) => ::core::fmt::Display::fmt(element, f), + Self::StakerNotFound(element) => ::core::fmt::Display::fmt(element, f), + Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), + } + } + } + impl ::core::convert::From<::std::string::String> for PermissionedStakeTableErrors { + fn from(value: String) -> Self { + Self::RevertString(value) + } + } + impl ::core::convert::From for PermissionedStakeTableErrors { + fn from(value: OwnableInvalidOwner) -> Self { + Self::OwnableInvalidOwner(value) + } + } + impl ::core::convert::From for PermissionedStakeTableErrors { + fn from(value: OwnableUnauthorizedAccount) -> Self { + Self::OwnableUnauthorizedAccount(value) + } + } + impl ::core::convert::From for PermissionedStakeTableErrors { + fn from(value: StakerAlreadyExists) -> Self { + Self::StakerAlreadyExists(value) + } + } + impl ::core::convert::From for PermissionedStakeTableErrors { + fn from(value: StakerNotFound) -> Self { + Self::StakerNotFound(value) + } + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent( + name = "Added", + abi = "Added(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + )] + pub struct AddedFilter(pub ::std::vec::Vec); + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent( + name = "OwnershipTransferred", + abi = "OwnershipTransferred(address,address)" + )] + pub struct OwnershipTransferredFilter { + #[ethevent(indexed)] + pub previous_owner: ::ethers::core::types::Address, + #[ethevent(indexed)] + pub new_owner: ::ethers::core::types::Address, + } + #[derive( + Clone, + ::ethers::contract::EthEvent, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethevent( + name = "Removed", + abi = "Removed(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + )] + pub struct RemovedFilter(pub ::std::vec::Vec); + ///Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum PermissionedStakeTableEvents { + AddedFilter(AddedFilter), + OwnershipTransferredFilter(OwnershipTransferredFilter), + RemovedFilter(RemovedFilter), + } + impl ::ethers::contract::EthLogDecode for PermissionedStakeTableEvents { + fn decode_log( + log: &::ethers::core::abi::RawLog, + ) -> ::core::result::Result { + if let Ok(decoded) = AddedFilter::decode_log(log) { + return Ok(PermissionedStakeTableEvents::AddedFilter(decoded)); + } + if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { + return Ok(PermissionedStakeTableEvents::OwnershipTransferredFilter( + decoded, + )); + } + if let Ok(decoded) = RemovedFilter::decode_log(log) { + return Ok(PermissionedStakeTableEvents::RemovedFilter(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData) + } + } + impl ::core::fmt::Display for PermissionedStakeTableEvents { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::AddedFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::OwnershipTransferredFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::RemovedFilter(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for PermissionedStakeTableEvents { + fn from(value: AddedFilter) -> Self { + Self::AddedFilter(value) + } + } + impl ::core::convert::From for PermissionedStakeTableEvents { + fn from(value: OwnershipTransferredFilter) -> Self { + Self::OwnershipTransferredFilter(value) + } + } + impl ::core::convert::From for PermissionedStakeTableEvents { + fn from(value: RemovedFilter) -> Self { + Self::RemovedFilter(value) + } + } + ///Container type for all input parameters for the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "_hashBlsKey", + abi = "_hashBlsKey((uint256,uint256,uint256,uint256))" + )] + pub struct HashBlsKeyCall { + pub bls_vk: G2Point, + } + ///Container type for all input parameters for the `insert` function with signature `insert(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])` and selector `0xcd1da5e5` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "insert", + abi = "insert(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + )] + pub struct InsertCall { + pub new_stakers: ::std::vec::Vec, + } + ///Container type for all input parameters for the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "isStaker", abi = "isStaker((uint256,uint256,uint256,uint256))")] + pub struct IsStakerCall { + pub staker: G2Point, + } + ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "owner", abi = "owner()")] + pub struct OwnerCall; + ///Container type for all input parameters for the `remove` function with signature `remove(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])` and selector `0x51826034` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall( + name = "remove", + abi = "remove(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + )] + pub struct RemoveCall { + pub stakers_to_remove: ::std::vec::Vec, + } + ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] + pub struct RenounceOwnershipCall; + ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] + pub struct TransferOwnershipCall { + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all of the contract's call + #[derive( + Clone, + ::ethers::contract::EthAbiType, + serde::Serialize, + serde::Deserialize, + Debug, + PartialEq, + Eq, + Hash, + )] + pub enum PermissionedStakeTableCalls { + HashBlsKey(HashBlsKeyCall), + Insert(InsertCall), + IsStaker(IsStakerCall), + Owner(OwnerCall), + Remove(RemoveCall), + RenounceOwnership(RenounceOwnershipCall), + TransferOwnership(TransferOwnershipCall), + } + impl ::ethers::core::abi::AbiDecode for PermissionedStakeTableCalls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = ::decode(data) { + return Ok(Self::HashBlsKey(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Insert(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::IsStaker(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Owner(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Remove(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::RenounceOwnership(decoded)); + } + if let Ok(decoded) = + ::decode(data) + { + return Ok(Self::TransferOwnership(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for PermissionedStakeTableCalls { + fn encode(self) -> Vec { + match self { + Self::HashBlsKey(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Insert(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::IsStaker(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Remove(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RenounceOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::TransferOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for PermissionedStakeTableCalls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::HashBlsKey(element) => ::core::fmt::Display::fmt(element, f), + Self::Insert(element) => ::core::fmt::Display::fmt(element, f), + Self::IsStaker(element) => ::core::fmt::Display::fmt(element, f), + Self::Owner(element) => ::core::fmt::Display::fmt(element, f), + Self::Remove(element) => ::core::fmt::Display::fmt(element, f), + Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: HashBlsKeyCall) -> Self { + Self::HashBlsKey(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: InsertCall) -> Self { + Self::Insert(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: IsStakerCall) -> Self { + Self::IsStaker(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: OwnerCall) -> Self { + Self::Owner(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: RemoveCall) -> Self { + Self::Remove(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: RenounceOwnershipCall) -> Self { + Self::RenounceOwnership(value) + } + } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: TransferOwnershipCall) -> Self { + Self::TransferOwnership(value) + } + } + ///Container type for all return fields from the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct HashBlsKeyReturn(pub [u8; 32]); + ///Container type for all return fields from the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct IsStakerReturn(pub bool); + ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct OwnerReturn(pub ::ethers::core::types::Address); + ///`G2Point(uint256,uint256,uint256,uint256)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct G2Point { + pub x_0: ::ethers::core::types::U256, + pub x_1: ::ethers::core::types::U256, + pub y_0: ::ethers::core::types::U256, + pub y_1: ::ethers::core::types::U256, + } + ///`EdOnBN254Point(uint256,uint256)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct EdOnBN254Point { + pub x: ::ethers::core::types::U256, + pub y: ::ethers::core::types::U256, + } + ///`NodeInfo((uint256,uint256,uint256,uint256),(uint256,uint256),bool)` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct NodeInfo { + pub bls_vk: G2Point, + pub schnorr_vk: EdOnBN254Point, + pub is_da: bool, + } +} diff --git a/contracts/src/PermissionedStakeTable.sol b/contracts/src/PermissionedStakeTable.sol index 3491dea3fc..73821b3285 100644 --- a/contracts/src/PermissionedStakeTable.sol +++ b/contracts/src/PermissionedStakeTable.sol @@ -17,8 +17,12 @@ contract PermissionedStakeTable is Ownable { error StakerNotFound(BN254.G2Point); struct NodeInfo { + /// The consensus signing key BN254.G2Point blsVK; + /// The consensus signing key. Only used for storage in this contract. EdOnBN254.EdOnBN254Point schnorrVK; + /// Is the Node DA Node? Only used for storage in this contract. + bool isDA; } // State mapping from staker IDs to their staking status diff --git a/contracts/test/PermissionedStakeTable.t.sol b/contracts/test/PermissionedStakeTable.t.sol index abdf82d681..05a0203a5a 100644 --- a/contracts/test/PermissionedStakeTable.t.sol +++ b/contracts/test/PermissionedStakeTable.t.sol @@ -27,22 +27,32 @@ contract PermissionedStakeTableTest is Test { cmds[2] = vm.toString(i + 1); bytes memory result = vm.ffi(cmds); BN254.G2Point memory bls = abi.decode(result, (BN254.G2Point)); - ps[i] = PermissionedStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0)); + ps[i] = PermissionedStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0), true); } return ps; } - function testInsertAndIsStaker() public { + function testInsert() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + + vm.expectEmit(); + emit PermissionedStakeTable.Added(stakers); + stakeTable.insert(stakers); + assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } - function testInsertAndIsStakerMany() public { + function testInsertMany() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(10); + + vm.expectEmit(); + emit PermissionedStakeTable.Added(stakers); + stakeTable.insert(stakers); + assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } @@ -61,12 +71,16 @@ contract PermissionedStakeTableTest is Test { stakeTable.insert(stakers); } - function testRemoveAndIsNotStaker() public { + function testRemove() public { PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); vm.prank(owner); stakeTable.insert(stakers); vm.prank(owner); + + vm.expectEmit(); + emit PermissionedStakeTable.Removed(stakers); + stakeTable.remove(stakers); assertFalse(stakeTable.isStaker(stakers[0].blsVK)); diff --git a/justfile b/justfile index fd2f6b0e6b..d8d98ee568 100644 --- a/justfile +++ b/justfile @@ -79,7 +79,7 @@ build-docker-images: scripts/build-docker-images-native # generate rust bindings for contracts -REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$|^PlonkVerifier2$|^SimpleStakeTable$" +REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$|^PlonkVerifier2$|^PermissionedStakeTable$" gen-bindings: forge bind --contracts ./contracts/src/ --crate-name contract-bindings --bindings-path contract-bindings --select "{{REGEXP}}" --overwrite --force diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs index 0a3d07f26e..32f9700176 100644 --- a/types/src/v0/v0_3/stake_table.rs +++ b/types/src/v0/v0_3/stake_table.rs @@ -1,6 +1,6 @@ -use ark_ec::{bn, short_weierstrass, twisted_edwards}; +use ark_ec::{short_weierstrass, twisted_edwards}; use ark_ed_on_bn254::EdwardsConfig; -use contract_bindings::simple_stake_table::{EdOnBN254Point, NodeInfo}; +use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; use derive_more::derive::From; use ethers::types::U256; use hotshot::types::{BLSPubKey, SignatureKey}; @@ -13,7 +13,12 @@ struct PermissionedPeerConfig(pub(crate) PeerConfig); impl From for PermissionedPeerConfig { fn from(node_info: NodeInfo) -> Self { - let NodeInfo { bls_vk, schnorr_vk } = node_info; + let NodeInfo { + bls_vk, + schnorr_vk, + // TODO: handle DA flag + .. + } = node_info; let stake_table_entry = { let g2 = diff_test_bn254::ParsedG2Point { x0: bls_vk.x_0, From beed5398c4b6dc42da2ef58b0298380a324dfb89 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 13:44:28 +0100 Subject: [PATCH 07/58] Allow setting an initial stake table on deployment - The stake table isn't useful without stakers I think it makes sense to require it to be provided on deployment. --- .../src/permissioned_stake_table.rs | 43 +++++++++++++++---- contracts/src/PermissionedStakeTable.sol | 4 +- contracts/test/PermissionedStakeTable.t.sol | 36 +++++++++------- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/contract-bindings/src/permissioned_stake_table.rs b/contract-bindings/src/permissioned_stake_table.rs index f7919ce378..a9d2e911d0 100644 --- a/contract-bindings/src/permissioned_stake_table.rs +++ b/contract-bindings/src/permissioned_stake_table.rs @@ -14,13 +14,40 @@ pub mod permissioned_stake_table { fn __abi() -> ::ethers::core::abi::Abi { ::ethers::core::abi::ethabi::Contract { constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("initialOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some(::std::borrow::ToOwned::to_owned( - "address" - ),), - },], + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("initialOwner"), + kind: ::ethers::core::abi::ethabi::ParamType::Address, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("address"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("initialStakers"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new(::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ], + ),), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ), + ), + }, + ], }), functions: ::core::convert::From::from([ ( @@ -337,7 +364,7 @@ pub mod permissioned_stake_table { pub static PERMISSIONEDSTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`@Qa\x08~8\x03\x80a\x08~\x839\x81\x01`@\x81\x90Ra\0/\x91a\0\xBEV[\x80`\x01`\x01`\xA0\x1B\x03\x81\x16a\0^W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01`@Q\x80\x91\x03\x90\xFD[a\0g\x81a\0nV[PPa\0\xEEV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0` \x82\x84\x03\x12\x15a\0\xD0W`\0\x80\xFD[\x81Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\0\xE7W`\0\x80\xFD[\x93\x92PPPV[a\x07\x81\x80a\0\xFD`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0\r\x108\x03\x80b\0\r\x10\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x03\x81V[\x81`\x01`\x01`\xA0\x1B\x03\x81\x16b\0\0eW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01[`@Q\x80\x91\x03\x90\xFD[b\0\0p\x81b\0\0\x84V[Pb\0\0|\x81b\0\0\xD4V[PPb\0\x05\x7FV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[b\0\0\xDEb\0\x01\xF2V[`\0[\x81Q\x81\x10\x15b\0\x01\xB5W`\0b\0\x01\x1E\x83\x83\x81Q\x81\x10b\0\x01\x06Wb\0\x01\x06b\0\x04\xD7V[` \x02` \x01\x01Q`\0\x01Qb\0\x02#` \x1B` \x1CV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15b\0\x01\x93W\x82\x82\x81Q\x81\x10b\0\x01NWb\0\x01Nb\0\x04\xD7V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01b\0\0\\V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01b\0\0\xE1V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qb\0\x01\xE7\x91\x90b\0\x04\xEDV[`@Q\x80\x91\x03\x90\xA1PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14b\0\x02!W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01b\0\0\\V[V[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01b\0\x02c\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\xBBWb\0\x02\xBBb\0\x02\x80V[`@R\x90V[`@Q`\x80\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\xBBWb\0\x02\xBBb\0\x02\x80V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x03\x11Wb\0\x03\x11b\0\x02\x80V[`@R\x91\x90PV[`\0`@\x82\x84\x03\x12\x15b\0\x03,W`\0\x80\xFD[`@\x80Q\x90\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x03QWb\0\x03Qb\0\x02\x80V[`@R\x82Q\x81R` \x92\x83\x01Q\x92\x81\x01\x92\x90\x92RP\x91\x90PV[\x80Q\x80\x15\x15\x81\x14b\0\x03|W`\0\x80\xFD[\x91\x90PV[`\0\x80`@\x80\x84\x86\x03\x12\x15b\0\x03\x96W`\0\x80\xFD[\x83Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x03\xAEW`\0\x80\xFD[` \x85\x81\x01Q\x91\x94P\x90`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\x03\xCEW`\0\x80\xFD[\x81\x87\x01\x91P\x87`\x1F\x83\x01\x12b\0\x03\xE3W`\0\x80\xFD[\x81Q\x81\x81\x11\x15b\0\x03\xF8Wb\0\x03\xF8b\0\x02\x80V[b\0\x04\x08\x84\x82`\x05\x1B\x01b\0\x02\xE6V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x8A\x83\x11\x15b\0\x04(W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15b\0\x04\xC6W\x84\x8B\x03\x81\x81\x12\x15b\0\x04HW`\0\x80\x81\xFD[b\0\x04Rb\0\x02\x96V[`\x80\x80\x83\x12\x15b\0\x04cW`\0\x80\x81\xFD[b\0\x04mb\0\x02\xC1V[\x88Q\x81R\x89\x89\x01Q\x8A\x82\x01R\x8A\x89\x01Q\x8B\x82\x01R``\x80\x8A\x01Q\x90\x82\x01R\x80\x83R\x92Pb\0\x04\x9E\x8E\x82\x8A\x01b\0\x03\x19V[\x89\x83\x01RPb\0\x04\xB1`\xC0\x88\x01b\0\x03kV[\x81\x8A\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92b\0\x04-V[P\x80\x96PPPPPPP\x92P\x92\x90PV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15b\0\x05rW\x81Qb\0\x05B\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01b\0\x05\nV[P\x91\x97\x96PPPPPPPV[a\x07\x81\x80b\0\x05\x8F`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; /// The bytecode of the contract. pub static PERMISSIONEDSTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); diff --git a/contracts/src/PermissionedStakeTable.sol b/contracts/src/PermissionedStakeTable.sol index 73821b3285..d1f607c2dc 100644 --- a/contracts/src/PermissionedStakeTable.sol +++ b/contracts/src/PermissionedStakeTable.sol @@ -28,7 +28,9 @@ contract PermissionedStakeTable is Ownable { // State mapping from staker IDs to their staking status mapping(bytes32 nodeID => bool isStaker) private stakers; - constructor(address initialOwner) Ownable(initialOwner) { } + constructor(address initialOwner, NodeInfo[] memory initialStakers) Ownable(initialOwner) { + insert(initialStakers); + } function insert(NodeInfo[] memory newStakers) public onlyOwner { // TODO: revert if array empty diff --git a/contracts/test/PermissionedStakeTable.t.sol b/contracts/test/PermissionedStakeTable.t.sol index 05a0203a5a..7aaffb7d02 100644 --- a/contracts/test/PermissionedStakeTable.t.sol +++ b/contracts/test/PermissionedStakeTable.t.sol @@ -9,32 +9,38 @@ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; contract PermissionedStakeTableTest is Test { PermissionedStakeTable stakeTable; - address owner = address(1); // mock owner address + address owner = address(1); function setUp() public { - vm.prank(owner); // impersonate the owner - stakeTable = new PermissionedStakeTable(owner); + vm.prank(owner); + PermissionedStakeTable.NodeInfo[] memory initialStakers = nodes(0, 1); + stakeTable = new PermissionedStakeTable(owner, initialStakers); } - function nodes(uint64 num) private returns (PermissionedStakeTable.NodeInfo[] memory) { + // Create `numNodes` node IDs from `start` for testing. + function nodes(uint64 start, uint64 numNodes) + private + returns (PermissionedStakeTable.NodeInfo[] memory) + { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "gen-random-g2-point"; - PermissionedStakeTable.NodeInfo[] memory ps = new PermissionedStakeTable.NodeInfo[](num); + PermissionedStakeTable.NodeInfo[] memory ps = + new PermissionedStakeTable.NodeInfo[](numNodes); - for (uint64 i = 0; i < num; i++) { - cmds[2] = vm.toString(i + 1); + for (uint64 i = 0; i < numNodes; i++) { + cmds[2] = vm.toString(start + 1 + i); bytes memory result = vm.ffi(cmds); BN254.G2Point memory bls = abi.decode(result, (BN254.G2Point)); - ps[i] = PermissionedStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 0), true); + ps[i] = PermissionedStakeTable.NodeInfo(bls, EdOnBN254.EdOnBN254Point(0, 1), true); } return ps; } function testInsert() public { vm.prank(owner); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); vm.expectEmit(); emit PermissionedStakeTable.Added(stakers); @@ -46,7 +52,7 @@ contract PermissionedStakeTableTest is Test { function testInsertMany() public { vm.prank(owner); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(10); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 10); vm.expectEmit(); emit PermissionedStakeTable.Added(stakers); @@ -58,7 +64,7 @@ contract PermissionedStakeTableTest is Test { function testInsertRevertsIfStakerExists() public { vm.prank(owner); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); stakeTable.insert(stakers); // Try adding the same staker again @@ -72,7 +78,7 @@ contract PermissionedStakeTableTest is Test { } function testRemove() public { - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); vm.prank(owner); stakeTable.insert(stakers); @@ -88,7 +94,7 @@ contract PermissionedStakeTableTest is Test { function testRemoveRevertsIfStakerNotFound() public { vm.prank(owner); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); vm.expectRevert( abi.encodeWithSelector(PermissionedStakeTable.StakerNotFound.selector, stakers[0].blsVK) ); @@ -101,7 +107,7 @@ contract PermissionedStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); stakeTable.insert(stakers); } @@ -110,7 +116,7 @@ contract PermissionedStakeTableTest is Test { vm.expectRevert( abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); - PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1); + PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); stakeTable.remove(stakers); } } From c919dd1ed9a169dfed5a9a9761dd6a884c0dccf3 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 15:36:17 +0100 Subject: [PATCH 08/58] deploy: load initial stake table from toml file --- Cargo.lock | 3 +++ docker-compose.yaml | 2 +- sequencer/src/bin/deploy.rs | 25 ++++++++++++++++++++ types/src/v0/v0_3/mod.rs | 1 + types/src/v0/v0_3/stake_table.rs | 40 ++++++++++++++++++-------------- utils/Cargo.toml | 2 ++ utils/src/deployer.rs | 38 +++++++++++++++++++++++++++++- utils/src/lib.rs | 1 + utils/src/stake_table.rs | 27 +++++++++++++++++++++ 9 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 utils/src/stake_table.rs diff --git a/Cargo.lock b/Cargo.lock index ad443eb18f..4b083937c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2888,6 +2888,7 @@ dependencies = [ "tide-disco", "time 0.3.36", "tokio", + "toml", "tracing", "url", "vbs", @@ -8752,6 +8753,7 @@ dependencies = [ "futures", "hotshot", "hotshot-contract-adapter", + "hotshot-types", "log-panics", "portpicker", "reqwest 0.11.27", @@ -8760,6 +8762,7 @@ dependencies = [ "surf", "tempfile", "tokio", + "toml", "tracing", "url", ] diff --git a/docker-compose.yaml b/docker-compose.yaml index c12d4c5c3e..60d230afd9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -17,7 +17,7 @@ services: deploy-sequencer-contracts: image: ghcr.io/espressosystems/espresso-sequencer/deploy:main - command: deploy --only fee-contract + command: deploy --only sequencer,permissioned-stake-table environment: - ESPRESSO_SEQUENCER_ETH_MULTISIG_ADDRESS - ESPRESSO_SEQUENCER_L1_PROVIDER diff --git a/sequencer/src/bin/deploy.rs b/sequencer/src/bin/deploy.rs index 6a87bfc9c9..c6793a0466 100644 --- a/sequencer/src/bin/deploy.rs +++ b/sequencer/src/bin/deploy.rs @@ -1,6 +1,7 @@ use std::{fs::File, io::stdout, path::PathBuf}; use clap::Parser; +use espresso_types::PubKey; use ethers::types::Address; use futures::FutureExt; use hotshot_stake_table::config::STAKE_TABLE_CAPACITY; @@ -8,6 +9,7 @@ use hotshot_state_prover::service::light_client_genesis; use sequencer_utils::{ deployer::{deploy, ContractGroup, Contracts, DeployedContracts}, logging, + stake_table::PermissionedStakeTableConfig, }; use url::Url; @@ -111,6 +113,20 @@ struct Options { #[clap(long, env = "ESPRESSO_SEQUENCER_PERMISSIONED_PROVER")] permissioned_prover: Option

, + /// A toml file with the initial stake table. + /// + /// Schema: + /// + /// public_keys = [ + /// { + /// stake_table_key = "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + /// state_ver_key = "SCHNORR_VER_KEY~lJqDaVZyM0hWP2Br52IX5FeE-dCAIC-dPX7bL5-qUx-vjbunwe-ENOeZxj6FuOyvDCFzoGeP7yZ0fM995qF-CRE", + /// da = true, + /// }, + /// ] + #[clap(long, env = "ESPRESSO_SEQUENCER_INITIAL_PERMISSIONED_STAKE_TABLE_PATH")] + initial_stake_table_path: Option, + #[clap(flatten)] logging: logging::Config, } @@ -126,6 +142,14 @@ async fn main() -> anyhow::Result<()> { let genesis = light_client_genesis(&sequencer_url, opt.stake_table_capacity).boxed(); + let initial_stake_table = if let Some(path) = opt.initial_stake_table_path { + Some(PermissionedStakeTableConfig::::from_toml_file( + &path, + )?) + } else { + None + }; + let contracts = deploy( opt.rpc_url, opt.mnemonic, @@ -136,6 +160,7 @@ async fn main() -> anyhow::Result<()> { genesis, opt.permissioned_prover, contracts, + initial_stake_table, ) .await?; diff --git a/types/src/v0/v0_3/mod.rs b/types/src/v0/v0_3/mod.rs index ec0da0fce9..a40e76c3c7 100644 --- a/types/src/v0/v0_3/mod.rs +++ b/types/src/v0/v0_3/mod.rs @@ -28,3 +28,4 @@ pub use chain_config::*; pub use fee_info::IterableFeeInfo; pub use header::Header; pub use solver::*; +pub use stake_table::CombinedStakeTable; diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs index 32f9700176..e46541d631 100644 --- a/types/src/v0/v0_3/stake_table.rs +++ b/types/src/v0/v0_3/stake_table.rs @@ -1,25 +1,27 @@ -use ark_ec::{short_weierstrass, twisted_edwards}; +use crate::PubKey; +use ark_ec::{bn, short_weierstrass, twisted_edwards}; use ark_ed_on_bn254::EdwardsConfig; use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; use derive_more::derive::From; -use ethers::types::U256; -use hotshot::types::{BLSPubKey, SignatureKey}; use hotshot_contract_adapter::stake_table::ParsedG1Point; -use hotshot_types::{light_client::StateVerKey, stake_table::StakeTableEntry, PeerConfig}; +use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, From)] -struct PermissionedPeerConfig(pub(crate) PeerConfig); +pub struct PermissionedPeerConfig(pub(crate) PeerConfigKeys); + +/// Stake table holding all staking information (DA and non-DA stakers) +#[derive(Debug, Clone, Serialize, Deserialize, From)] +pub struct CombinedStakeTable(Vec>); impl From for PermissionedPeerConfig { fn from(node_info: NodeInfo) -> Self { let NodeInfo { bls_vk, schnorr_vk, - // TODO: handle DA flag - .. + is_da, } = node_info; - let stake_table_entry = { + let stake_table_key = { let g2 = diff_test_bn254::ParsedG2Point { x0: bls_vk.x_0, x1: bls_vk.x_1, @@ -27,12 +29,12 @@ impl From for PermissionedPeerConfig { y1: bls_vk.y_1, }; let g2_affine = short_weierstrass::Affine::::from(g2); - // let g2_proj = bn::G2Projective::from(g2_affine); - // TODO - let stake_key = BLSPubKey::generated_from_seed_indexed(Default::default(), 0).0; - StakeTableEntry { - stake_key, - stake_amount: U256::from(0), + // TODO: maybe this works until I find a better way + let g2_proj = bn::G2Projective::::from(g2_affine); + unsafe { + std::mem::transmute::, PubKey>( + g2_proj, + ) } }; let state_ver_key = { @@ -41,13 +43,15 @@ impl From for PermissionedPeerConfig { let state_sk_affine = twisted_edwards::Affine::::from(g1_point); StateVerKey::from(state_sk_affine) }; - PeerConfig { - stake_table_entry, + PeerConfigKeys { + stake_table_key, state_ver_key, + da: is_da, + stake: 1, } .into() } } -#[derive(Debug, Clone, Serialize, Deserialize)] -struct StakeTable(Vec>); +// #[derive(Debug, Clone, Serialize, Deserialize)] +// struct StakeTable(Vec>); diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 5328ae0d71..0a89952ef5 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -19,6 +19,7 @@ derive_more = { workspace = true } ethers = { workspace = true } futures = { workspace = true } hotshot = { workspace = true } +hotshot-types = { workspace = true } hotshot-contract-adapter = { workspace = true } log-panics = { workspace = true } portpicker = { workspace = true } @@ -29,5 +30,6 @@ serde_json = "^1.0.113" surf = "2.3.2" tempfile = { workspace = true } tokio = { workspace = true } +toml = { workspace = true } tracing = "0.1.37" url = "2.3.1" diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index ce95f8ba21..01a86cb7d3 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -7,6 +7,7 @@ use contract_bindings::{ light_client_mock::LIGHTCLIENTMOCK_ABI, light_client_state_update_vk::LightClientStateUpdateVK, light_client_state_update_vk_mock::LightClientStateUpdateVKMock, + permissioned_stake_table::PermissionedStakeTable, plonk_verifier::PlonkVerifier, }; use derive_more::Display; @@ -15,6 +16,7 @@ use ethers::{ utils::hex, }; use futures::future::{BoxFuture, FutureExt}; +use hotshot::types::SignatureKey; use hotshot_contract_adapter::light_client::{ LightClientConstructorArgs, ParsedLightClientState, ParsedStakeTableState, }; @@ -22,6 +24,8 @@ use std::sync::Arc; use std::{collections::HashMap, io::Write, ops::Deref}; use url::Url; +use crate::stake_table::PermissionedStakeTableConfig; + /// Set of predeployed contracts. #[derive(Clone, Debug, Parser)] pub struct DeployedContracts { @@ -48,6 +52,10 @@ pub struct DeployedContracts { /// Use an already-deployed FeeContract.sol proxy instead of deploying a new one. #[clap(long, env = Contract::FeeContractProxy)] fee_contract_proxy: Option
, + + /// Use an already-deployed PermissonedStakeTable.sol proxy instead of deploying a new one. + #[clap(long, env = Contract::FeeContractProxy)] + permissioned_stake_table: Option
, } /// An identifier for a particular contract. @@ -65,6 +73,8 @@ pub enum Contract { FeeContract, #[display("ESPRESSO_SEQUENCER_FEE_CONTRACT_PROXY_ADDRESS")] FeeContractProxy, + #[display("ESPRESSO_SEQUENCER_PERMISSIONED_STAKE_TABLE_ADDRESS")] + PermissonedStakeTable, } impl From for OsStr { @@ -98,6 +108,9 @@ impl From for Contracts { if let Some(addr) = deployed.fee_contract_proxy { m.insert(Contract::FeeContractProxy, addr); } + if let Some(addr) = deployed.permissioned_stake_table { + m.insert(Contract::PermissonedStakeTable, addr); + } Self(m) } } @@ -298,7 +311,7 @@ pub async fn deploy_mock_light_client_contract( } #[allow(clippy::too_many_arguments)] -pub async fn deploy( +pub async fn deploy( l1url: Url, mnemonic: String, account_index: u32, @@ -308,6 +321,7 @@ pub async fn deploy( genesis: BoxFuture<'_, anyhow::Result<(ParsedLightClientState, ParsedStakeTableState)>>, permissioned_prover: Option
, mut contracts: Contracts, + initial_stake_table: Option>, ) -> anyhow::Result { let provider = Provider::::try_from(l1url.to_string())?; let chain_id = provider.get_chainid().await?.as_u64(); @@ -426,6 +440,27 @@ pub async fn deploy( } } + // `PermissionedStakeTable.sol` + if should_deploy(ContractGroup::PermissionedStakeTable, &only) { + let stake_table_address = contracts + .deploy_tx( + Contract::PermissonedStakeTable, + PermissionedStakeTable::deploy(l1.clone(), ())?, + ) + .await?; + let stake_table = PermissionedStakeTable::new(stake_table_address, l1.clone()); + + // Transfer ownership to the multisig wallet if provided. + if let Some(owner) = multisig_address { + tracing::info!( + %stake_table_address, + %owner, + "transferring fee contract proxy ownership to multisig", + ); + stake_table.transfer_ownership(owner).send().await?.await?; + } + } + Ok(contracts) } @@ -459,6 +494,7 @@ pub async fn is_proxy_contract( pub enum ContractGroup { FeeContract, LightClient, + PermissionedStakeTable, } #[cfg(any(test, feature = "testing"))] diff --git a/utils/src/lib.rs b/utils/src/lib.rs index ec8bce5825..18c01a06d2 100644 --- a/utils/src/lib.rs +++ b/utils/src/lib.rs @@ -24,6 +24,7 @@ pub mod blocknative; pub mod deployer; pub mod logging; pub mod ser; +pub mod stake_table; pub mod test_utils; pub type Signer = SignerMiddleware, LocalWallet>; diff --git a/utils/src/stake_table.rs b/utils/src/stake_table.rs new file mode 100644 index 0000000000..6c1b91adac --- /dev/null +++ b/utils/src/stake_table.rs @@ -0,0 +1,27 @@ +use hotshot::types::SignatureKey; +use hotshot_types::network::PeerConfigKeys; +use std::{fs, path::Path}; + +/// A stake table config stored in a file +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +#[serde(bound(deserialize = ""))] +pub struct PermissionedStakeTableConfig { + /// The list of public keys that are initially inserted into the + /// permissioned stake table contract. + #[serde(default)] + pub public_keys: Vec>, +} + +impl PermissionedStakeTableConfig { + pub fn from_toml_file(path: &Path) -> anyhow::Result { + let config_file_as_string: String = fs::read_to_string(path) + .unwrap_or_else(|_| panic!("Could not read config file located at {}", path.display())); + + Ok( + toml::from_str::(&config_file_as_string).expect(&format!( + "Unable to convert config file {} to TOML", + path.display() + )), + ) + } +} From 6b8d822d42e3f28313c6f5ddcca22580ff043f01 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 27 Nov 2024 16:16:03 +0100 Subject: [PATCH 09/58] Use serde instead of unsafe rust We will add some more ergonomic code for conversion to jellyfish at some point. This code can be used as a stop gap until then. --- Cargo.lock | 2 +- types/Cargo.toml | 1 + types/src/v0/v0_3/stake_table.rs | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b083937c0..c336c5ed44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2845,6 +2845,7 @@ dependencies = [ "ark-ec", "ark-ed-on-bn254", "ark-serialize", + "ark-std", "async-broadcast", "async-trait", "base64-bytes", @@ -2888,7 +2889,6 @@ dependencies = [ "tide-disco", "time 0.3.36", "tokio", - "toml", "tracing", "url", "vbs", diff --git a/types/Cargo.toml b/types/Cargo.toml index e6745dac3a..940789b9db 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -14,6 +14,7 @@ ark-bn254 = { workspace = true } ark-ec = { workspace = true } ark-ed-on-bn254 = { workspace = true } ark-serialize = { workspace = true } +ark-std = { workspace = true } async-broadcast = { workspace = true } async-trait = { workspace = true } base64-bytes = { workspace = true } diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs index e46541d631..8be6f28644 100644 --- a/types/src/v0/v0_3/stake_table.rs +++ b/types/src/v0/v0_3/stake_table.rs @@ -1,10 +1,16 @@ use crate::PubKey; -use ark_ec::{bn, short_weierstrass, twisted_edwards}; +use ark_ec::{ + bn, + short_weierstrass::{self, Projective}, + twisted_edwards, AffineRepr, +}; use ark_ed_on_bn254::EdwardsConfig; +use ark_serialize::{CanonicalDeserialize as _, CanonicalSerialize}; use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; use derive_more::derive::From; use hotshot_contract_adapter::stake_table::ParsedG1Point; use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys}; +use jf_utils::to_bytes; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, From)] @@ -29,13 +35,9 @@ impl From for PermissionedPeerConfig { y1: bls_vk.y_1, }; let g2_affine = short_weierstrass::Affine::::from(g2); - // TODO: maybe this works until I find a better way - let g2_proj = bn::G2Projective::::from(g2_affine); - unsafe { - std::mem::transmute::, PubKey>( - g2_proj, - ) - } + // TODO: remove unwrap + let b = to_bytes!(&g2_affine.into_group()).unwrap(); + PubKey::deserialize_compressed(&b[..]).unwrap() }; let state_ver_key = { let EdOnBN254Point { x, y } = schnorr_vk; From 80dc00ee50b9532a7dbd9030651b8c6509316141 Mon Sep 17 00:00:00 2001 From: Mathis Date: Wed, 4 Dec 2024 16:11:44 +0100 Subject: [PATCH 10/58] Update utils/src/deployer.rs Co-authored-by: Alysia Tech --- utils/src/deployer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index 01a86cb7d3..c66a01f840 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -455,7 +455,7 @@ pub async fn deploy( tracing::info!( %stake_table_address, %owner, - "transferring fee contract proxy ownership to multisig", + "transferring PermissionedStakeTable ownership to multisig", ); stake_table.transfer_ownership(owner).send().await?.await?; } From f1741e34be54a650b42fce3be5aea61d3f758347 Mon Sep 17 00:00:00 2001 From: sveitser Date: Wed, 4 Dec 2024 09:42:50 +0100 Subject: [PATCH 11/58] WIP: load initial stake table from file --- Cargo.lock | 1 + contracts/rust/adapter/Cargo.toml | 1 + contracts/rust/adapter/src/stake_table.rs | 151 ++++++++++++++-------- process-compose.yaml | 2 +- types/src/v0/v0_3/stake_table.rs | 31 ++++- utils/src/deployer.rs | 5 +- utils/src/stake_table.rs | 21 +++ 7 files changed, 153 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c336c5ed44..3f7272fc09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4119,6 +4119,7 @@ dependencies = [ "ark-serialize", "ark-std", "contract-bindings", + "derive_more 1.0.0", "diff-test-bn254", "ethers", "hotshot-types", diff --git a/contracts/rust/adapter/Cargo.toml b/contracts/rust/adapter/Cargo.toml index d242940fc4..a0716dd7b3 100644 --- a/contracts/rust/adapter/Cargo.toml +++ b/contracts/rust/adapter/Cargo.toml @@ -15,6 +15,7 @@ ark-poly = { workspace = true } ark-serialize = { workspace = true } ark-std = { workspace = true } contract-bindings = { path = "../../../contract-bindings" } +derive_more = { workspace = true } diff-test-bn254 = { git = "https://github.com/EspressoSystems/solidity-bn254.git" } ethers = { version = "2.0.4" } hotshot-types = { workspace = true } diff --git a/contracts/rust/adapter/src/stake_table.rs b/contracts/rust/adapter/src/stake_table.rs index 628e129f65..21d081ad20 100644 --- a/contracts/rust/adapter/src/stake_table.rs +++ b/contracts/rust/adapter/src/stake_table.rs @@ -4,11 +4,14 @@ use ark_ec::{ AffineRepr, }; use ark_ff::{BigInteger, Fp2, Fp2Config, PrimeField}; +use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; +use derive_more::derive::From; use ethers::{ abi::AbiDecode, prelude::{AbiError, EthAbiCodec, EthAbiType}, types::U256, }; +use hotshot_types::{network::PeerConfigKeys, signature_key::BLSPubKey}; use std::str::FromStr; // TODO: (alex) maybe move these commonly shared util to a crate @@ -20,9 +23,9 @@ pub fn field_to_u256(f: F) -> U256 { U256::from_little_endian(&f.into_bigint().to_bytes_le()) } -/// an intermediate representation of `BN254.G1Point` in solidity. +/// an intermediate representation of `EdOnBN254Point` in solidity. #[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] -pub struct ParsedG1Point { +pub struct ParsedEdOnBN254Point { /// x coordinate of affine repr pub x: U256, /// y coordinate of affine repr @@ -30,7 +33,7 @@ pub struct ParsedG1Point { } // this is convention from BN256 precompile -impl Default for ParsedG1Point { +impl Default for ParsedEdOnBN254Point { fn default() -> Self { Self { x: U256::from(0), @@ -39,7 +42,16 @@ impl Default for ParsedG1Point { } } -impl FromStr for ParsedG1Point { +impl From for EdOnBN254Point { + fn from(value: ParsedEdOnBN254Point) -> Self { + Self { + x: value.x, + y: value.y, + } + } +} + +impl FromStr for ParsedEdOnBN254Point { type Err = AbiError; fn from_str(s: &str) -> Result { let parsed: (Self,) = AbiDecode::decode_hex(s)?; @@ -47,7 +59,7 @@ impl FromStr for ParsedG1Point { } } -impl From> for ParsedG1Point +impl From> for ParsedEdOnBN254Point where P::BaseField: PrimeField, { @@ -67,12 +79,12 @@ where } } -impl From for Affine

+impl From for Affine

where P::BaseField: PrimeField, { - fn from(p: ParsedG1Point) -> Self { - if p == ParsedG1Point::default() { + fn from(p: ParsedEdOnBN254Point) -> Self { + if p == ParsedEdOnBN254Point::default() { Self::default() } else { Self::new_unchecked( @@ -83,49 +95,86 @@ where } } -/// Intermediate representation of `G2Point` in Solidity -#[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] -pub struct ParsedG2Point { - /// x0 of x = x0 + u * x1 coordinate - pub x0: U256, - /// x1 of x = x0 + u * x1 coordinate - pub x1: U256, - /// y0 of y = y0 + u * y1 coordinate - pub y0: U256, - /// y1 of y = y0 + u * y1 coordinate - pub y1: U256, -} +// /// Intermediate representation of `G2Point` in Solidity +// #[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] +// pub struct ParsedG2Point { +// /// x0 of x = x0 + u * x1 coordinate +// pub x0: U256, +// /// x1 of x = x0 + u * x1 coordinate +// pub x1: U256, +// /// y0 of y = y0 + u * y1 coordinate +// pub y0: U256, +// /// y1 of y = y0 + u * y1 coordinate +// pub y1: U256, +// } -impl FromStr for ParsedG2Point { - type Err = AbiError; - fn from_str(s: &str) -> Result { - let parsed: (Self,) = AbiDecode::decode_hex(s)?; - Ok(parsed.0) - } -} +// impl FromStr for ParsedG2Point { +// type Err = AbiError; +// fn from_str(s: &str) -> Result { +// let parsed: (Self,) = AbiDecode::decode_hex(s)?; +// Ok(parsed.0) +// } +// } -impl>, C> From for Affine

-where - C: Fp2Config, -{ - fn from(p: ParsedG2Point) -> Self { - Self::new_unchecked( - Fp2::new(u256_to_field(p.x0), u256_to_field(p.x1)), - Fp2::new(u256_to_field(p.y0), u256_to_field(p.y1)), - ) - } -} +// impl>, C> From for Affine

+// where +// C: Fp2Config, +// { +// fn from(p: ParsedG2Point) -> Self { +// Self::new_unchecked( +// Fp2::new(u256_to_field(p.x0), u256_to_field(p.x1)), +// Fp2::new(u256_to_field(p.y0), u256_to_field(p.y1)), +// ) +// } +// } -impl>, C> From> for ParsedG2Point -where - C: Fp2Config, -{ - fn from(p: Affine

) -> Self { - Self { - x0: field_to_u256(p.x().unwrap().c0), - x1: field_to_u256(p.x().unwrap().c1), - y0: field_to_u256(p.y().unwrap().c0), - y1: field_to_u256(p.y().unwrap().c1), - } - } -} +// impl>, C> From> for ParsedG2Point +// where +// C: Fp2Config, +// { +// fn from(p: Affine

) -> Self { +// Self { +// x0: field_to_u256(p.x().unwrap().c0), +// x1: field_to_u256(p.x().unwrap().c1), +// y0: field_to_u256(p.y().unwrap().c0), +// y1: field_to_u256(p.y().unwrap().c1), +// } +// } +// } + +// pub trait ToAffine { +// fn to_affine(&self) -> Affine

; +// } +// impl>, C> ToAffine for BLSPubKey +// where +// C: Fp2Config, +// { +// fn to_affine(&self) -> Affine

{ +// self.to_affine() +// } +// } + +#[derive(Clone, Debug, From)] +pub struct NodeInfoSol(NodeInfo); + +// impl From<> for NodeInfoSol { +// fn from(p: PeerConfigKeys) -> Self { +// let bls: ParsedG2Point = p.stake_table_key.to_affine().into(); +// let schnorr: ParsedG1Point = p.state_ver_key.to_affine().into(); +// Self(NodeInfo { +// bls_vk: bls.into(), +// schnorr_vk: schnorr.into(), +// is_da: p.da, +// }) +// } +// } + +// impl From for PeerConfigKeys { +// fn from(p: NodeInfoSol) -> Self { +// PeerConfigKeys { +// bls_pub_key: p.0.bls_pub_key, +// ip: p.0.ip, +// port: p.0.port, +// } +// } +// } diff --git a/process-compose.yaml b/process-compose.yaml index bf0a95b44a..0f6c524450 100644 --- a/process-compose.yaml +++ b/process-compose.yaml @@ -29,7 +29,7 @@ processes: # script will think they're already deployed. command: unset ESPRESSO_SEQUENCER_HOTSHOT_ADDRESS ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS && deploy --only - fee-contract + fee-contract,permissioned-stake-table namespace: setup depends_on: demo-l1-network: diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs index 8be6f28644..4248031e39 100644 --- a/types/src/v0/v0_3/stake_table.rs +++ b/types/src/v0/v0_3/stake_table.rs @@ -8,19 +8,25 @@ use ark_ed_on_bn254::EdwardsConfig; use ark_serialize::{CanonicalDeserialize as _, CanonicalSerialize}; use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; use derive_more::derive::From; -use hotshot_contract_adapter::stake_table::ParsedG1Point; +use diff_test_bn254::ParsedG2Point; +use hotshot_contract_adapter::stake_table::{NodeInfoSol, ParsedEdOnBN254Point}; use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys}; use jf_utils::to_bytes; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, From)] -pub struct PermissionedPeerConfig(pub(crate) PeerConfigKeys); +pub struct PermissionedStakeTableEntry{ + pub stake_table_key: PubKey, + pub state_ver_key: StateVerKey, + pub da: bool, + // pub stake: u64, // TODO unused, maybe remove? +}; /// Stake table holding all staking information (DA and non-DA stakers) #[derive(Debug, Clone, Serialize, Deserialize, From)] pub struct CombinedStakeTable(Vec>); -impl From for PermissionedPeerConfig { +impl From for PermissionedStakeTableEntry { fn from(node_info: NodeInfo) -> Self { let NodeInfo { bls_vk, @@ -41,19 +47,32 @@ impl From for PermissionedPeerConfig { }; let state_ver_key = { let EdOnBN254Point { x, y } = schnorr_vk; - let g1_point = ParsedG1Point { x, y }; + let g1_point = ParsedEdOnBN254Point { x, y }; let state_sk_affine = twisted_edwards::Affine::::from(g1_point); StateVerKey::from(state_sk_affine) }; - PeerConfigKeys { + Self { stake_table_key, state_ver_key, da: is_da, - stake: 1, + // stake: 1, } .into() } } +impl From for NodeInfoSol { + fn from(e: PermissionedStakeTableEntry) -> Self { + let bls: ParsedG2Point = e.stake_table_key.to_affine().into(); + let bls_vk = PubKey::from(bls); + let schnorr: ParsedEdOnBN254Point = e.state_ver_key.to_affine().into(); + Self(NodeInfo { + bls_vk, + schnorr_vk: schnorr.into(), + is_da: e.da, + }) + } +} + // #[derive(Debug, Clone, Serialize, Deserialize)] // struct StakeTable(Vec>); diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index c66a01f840..51324acc3b 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -445,7 +445,10 @@ pub async fn deploy( let stake_table_address = contracts .deploy_tx( Contract::PermissonedStakeTable, - PermissionedStakeTable::deploy(l1.clone(), ())?, + PermissionedStakeTable::deploy( + l1.clone(), + (), // TODO initial stake table + )?, ) .await?; let stake_table = PermissionedStakeTable::new(stake_table_address, l1.clone()); diff --git a/utils/src/stake_table.rs b/utils/src/stake_table.rs index 6c1b91adac..a2a467cedb 100644 --- a/utils/src/stake_table.rs +++ b/utils/src/stake_table.rs @@ -1,4 +1,6 @@ +use contract_bindings::permissioned_stake_table::NodeInfo; use hotshot::types::SignatureKey; +use hotshot_contract_adapter::stake_table::ParsedEdOnBN254Point; use hotshot_types::network::PeerConfigKeys; use std::{fs, path::Path}; @@ -25,3 +27,22 @@ impl PermissionedStakeTableConfig { ) } } + +impl From> for Vec { + fn from(value: PermissionedStakeTableConfig) -> Self { + value + .public_keys + .into_iter() + .map(|peer_config| { + let g1: ParsedEdOnBN254Point = peer_config.state_ver_key.to_affine().into(); + // XXX We don't have a trait on the Bls key to provide .to_affine() + // let g2: ParsedG2Point = peer_config.stake_table_key.to_affine().into(); + NodeInfo { + bls_vk: todo!(), + schnorr_vk: g1.into(), + is_da: peer_config.da, + } + }) + .collect() + } +} From f926e84a39a38163c9b74e97353a2a57cb345f56 Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 15:16:06 +0100 Subject: [PATCH 12/58] Move solidity <-> jf code to contract adapter --- Cargo.lock | 5 +- contracts/rust/adapter/Cargo.toml | 1 + contracts/rust/adapter/src/stake_table.rs | 168 +++++++++++----------- types/Cargo.toml | 4 - types/src/v0/v0_3/stake_table.rs | 72 +--------- 5 files changed, 87 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 645a44b75f..0a06876fe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2847,11 +2847,7 @@ name = "espresso-types" version = "0.1.0" dependencies = [ "anyhow", - "ark-bn254", - "ark-ec", - "ark-ed-on-bn254", "ark-serialize", - "ark-std", "async-broadcast", "async-trait", "base64-bytes", @@ -4134,6 +4130,7 @@ dependencies = [ "jf-utils", "num-bigint", "num-traits", + "serde", ] [[package]] diff --git a/contracts/rust/adapter/Cargo.toml b/contracts/rust/adapter/Cargo.toml index a0716dd7b3..5f095044cc 100644 --- a/contracts/rust/adapter/Cargo.toml +++ b/contracts/rust/adapter/Cargo.toml @@ -24,6 +24,7 @@ jf-plonk = { workspace = true } jf-utils = { workspace = true } num-bigint = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } +serde.workspace = true [[bin]] name = "eval-domain" diff --git a/contracts/rust/adapter/src/stake_table.rs b/contracts/rust/adapter/src/stake_table.rs index 21d081ad20..46abf81fe0 100644 --- a/contracts/rust/adapter/src/stake_table.rs +++ b/contracts/rust/adapter/src/stake_table.rs @@ -1,17 +1,21 @@ use crate::jellyfish::u256_to_field; use ark_ec::{ - twisted_edwards::{Affine, TECurveConfig}, + short_weierstrass, + twisted_edwards::{self, Affine, TECurveConfig}, AffineRepr, }; -use ark_ff::{BigInteger, Fp2, Fp2Config, PrimeField}; -use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; -use derive_more::derive::From; +use ark_ed_on_bn254::EdwardsConfig; +use ark_ff::{BigInteger, PrimeField}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use contract_bindings::permissioned_stake_table::{self, EdOnBN254Point, NodeInfo}; +use diff_test_bn254::ParsedG2Point; use ethers::{ abi::AbiDecode, prelude::{AbiError, EthAbiCodec, EthAbiType}, types::U256, }; -use hotshot_types::{network::PeerConfigKeys, signature_key::BLSPubKey}; +use hotshot_types::{light_client::StateVerKey, signature_key::BLSPubKey}; +use serde::{Deserialize, Serialize}; use std::str::FromStr; // TODO: (alex) maybe move these commonly shared util to a crate @@ -51,6 +55,13 @@ impl From for EdOnBN254Point { } } +impl From for ParsedEdOnBN254Point { + fn from(value: EdOnBN254Point) -> Self { + let EdOnBN254Point { x, y } = value; + Self { x, y } + } +} + impl FromStr for ParsedEdOnBN254Point { type Err = AbiError; fn from_str(s: &str) -> Result { @@ -95,86 +106,71 @@ where } } -// /// Intermediate representation of `G2Point` in Solidity -// #[derive(Clone, PartialEq, Eq, Debug, EthAbiType, EthAbiCodec)] -// pub struct ParsedG2Point { -// /// x0 of x = x0 + u * x1 coordinate -// pub x0: U256, -// /// x1 of x = x0 + u * x1 coordinate -// pub x1: U256, -// /// y0 of y = y0 + u * y1 coordinate -// pub y0: U256, -// /// y1 of y = y0 + u * y1 coordinate -// pub y1: U256, -// } - -// impl FromStr for ParsedG2Point { -// type Err = AbiError; -// fn from_str(s: &str) -> Result { -// let parsed: (Self,) = AbiDecode::decode_hex(s)?; -// Ok(parsed.0) -// } -// } - -// impl>, C> From for Affine

-// where -// C: Fp2Config, -// { -// fn from(p: ParsedG2Point) -> Self { -// Self::new_unchecked( -// Fp2::new(u256_to_field(p.x0), u256_to_field(p.x1)), -// Fp2::new(u256_to_field(p.y0), u256_to_field(p.y1)), -// ) -// } -// } - -// impl>, C> From> for ParsedG2Point -// where -// C: Fp2Config, -// { -// fn from(p: Affine

) -> Self { -// Self { -// x0: field_to_u256(p.x().unwrap().c0), -// x1: field_to_u256(p.x().unwrap().c1), -// y0: field_to_u256(p.y().unwrap().c0), -// y1: field_to_u256(p.y().unwrap().c1), -// } -// } -// } - -// pub trait ToAffine { -// fn to_affine(&self) -> Affine

; -// } -// impl>, C> ToAffine for BLSPubKey -// where -// C: Fp2Config, -// { -// fn to_affine(&self) -> Affine

{ -// self.to_affine() -// } -// } - -#[derive(Clone, Debug, From)] -pub struct NodeInfoSol(NodeInfo); +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct NodeInfoJf { + pub stake_table_key: BLSPubKey, + pub state_ver_key: StateVerKey, + pub da: bool, +} -// impl From<> for NodeInfoSol { -// fn from(p: PeerConfigKeys) -> Self { -// let bls: ParsedG2Point = p.stake_table_key.to_affine().into(); -// let schnorr: ParsedG1Point = p.state_ver_key.to_affine().into(); -// Self(NodeInfo { -// bls_vk: bls.into(), -// schnorr_vk: schnorr.into(), -// is_da: p.da, -// }) -// } -// } +impl From for NodeInfo { + fn from(value: NodeInfoJf) -> Self { + let NodeInfoJf { + stake_table_key, + state_ver_key, + da, + } = value; + let ParsedG2Point { x0, x1, y0, y1 } = stake_table_key.to_affine().into(); + let schnorr: ParsedEdOnBN254Point = state_ver_key.to_affine().into(); + Self { + bls_vk: permissioned_stake_table::G2Point { + x_0: x0, + x_1: x1, + y_0: y0, + y_1: y1, + }, + schnorr_vk: schnorr.into(), + is_da: da, + } + } +} -// impl From for PeerConfigKeys { -// fn from(p: NodeInfoSol) -> Self { -// PeerConfigKeys { -// bls_pub_key: p.0.bls_pub_key, -// ip: p.0.ip, -// port: p.0.port, -// } -// } -// } +impl From for NodeInfoJf { + fn from(value: NodeInfo) -> Self { + let NodeInfo { + bls_vk, + schnorr_vk, + is_da, + } = value; + let stake_table_key = { + let g2 = diff_test_bn254::ParsedG2Point { + x0: bls_vk.x_0, + x1: bls_vk.x_1, + y0: bls_vk.y_0, + y1: bls_vk.y_1, + }; + let g2_affine = short_weierstrass::Affine::::from(g2); + let mut bytes = vec![]; + // TODO: remove serde round-trip once jellyfin provides a way to + // convert from Affine representation to VerKey. + // + // Serialization and de-serialization shouldn't fail. + g2_affine + .into_group() + .serialize_compressed(&mut bytes) + .unwrap(); + BLSPubKey::deserialize_compressed(&bytes[..]).unwrap() + }; + let state_ver_key = { + let g1_point: ParsedEdOnBN254Point = schnorr_vk.into(); + let state_sk_affine = twisted_edwards::Affine::::from(g1_point); + StateVerKey::from(state_sk_affine) + }; + Self { + stake_table_key, + state_ver_key, + da: is_da, + } + .into() + } +} diff --git a/types/Cargo.toml b/types/Cargo.toml index 940789b9db..af261ab453 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -10,11 +10,7 @@ testing = [] [dependencies] anyhow = { workspace = true } -ark-bn254 = { workspace = true } -ark-ec = { workspace = true } -ark-ed-on-bn254 = { workspace = true } ark-serialize = { workspace = true } -ark-std = { workspace = true } async-broadcast = { workspace = true } async-trait = { workspace = true } base64-bytes = { workspace = true } diff --git a/types/src/v0/v0_3/stake_table.rs b/types/src/v0/v0_3/stake_table.rs index 4248031e39..6d5e41f189 100644 --- a/types/src/v0/v0_3/stake_table.rs +++ b/types/src/v0/v0_3/stake_table.rs @@ -1,78 +1,12 @@ use crate::PubKey; -use ark_ec::{ - bn, - short_weierstrass::{self, Projective}, - twisted_edwards, AffineRepr, -}; -use ark_ed_on_bn254::EdwardsConfig; -use ark_serialize::{CanonicalDeserialize as _, CanonicalSerialize}; -use contract_bindings::permissioned_stake_table::{EdOnBN254Point, NodeInfo}; use derive_more::derive::From; -use diff_test_bn254::ParsedG2Point; -use hotshot_contract_adapter::stake_table::{NodeInfoSol, ParsedEdOnBN254Point}; -use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys}; -use jf_utils::to_bytes; +use hotshot_contract_adapter::stake_table::NodeInfoJf; +use hotshot_types::network::PeerConfigKeys; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize, From)] -pub struct PermissionedStakeTableEntry{ - pub stake_table_key: PubKey, - pub state_ver_key: StateVerKey, - pub da: bool, - // pub stake: u64, // TODO unused, maybe remove? -}; +pub struct PermissionedStakeTableEntry(NodeInfoJf); /// Stake table holding all staking information (DA and non-DA stakers) #[derive(Debug, Clone, Serialize, Deserialize, From)] pub struct CombinedStakeTable(Vec>); - -impl From for PermissionedStakeTableEntry { - fn from(node_info: NodeInfo) -> Self { - let NodeInfo { - bls_vk, - schnorr_vk, - is_da, - } = node_info; - let stake_table_key = { - let g2 = diff_test_bn254::ParsedG2Point { - x0: bls_vk.x_0, - x1: bls_vk.x_1, - y0: bls_vk.y_0, - y1: bls_vk.y_1, - }; - let g2_affine = short_weierstrass::Affine::::from(g2); - // TODO: remove unwrap - let b = to_bytes!(&g2_affine.into_group()).unwrap(); - PubKey::deserialize_compressed(&b[..]).unwrap() - }; - let state_ver_key = { - let EdOnBN254Point { x, y } = schnorr_vk; - let g1_point = ParsedEdOnBN254Point { x, y }; - let state_sk_affine = twisted_edwards::Affine::::from(g1_point); - StateVerKey::from(state_sk_affine) - }; - Self { - stake_table_key, - state_ver_key, - da: is_da, - // stake: 1, - } - .into() - } -} - -impl From for NodeInfoSol { - fn from(e: PermissionedStakeTableEntry) -> Self { - let bls: ParsedG2Point = e.stake_table_key.to_affine().into(); - let bls_vk = PubKey::from(bls); - let schnorr: ParsedEdOnBN254Point = e.state_ver_key.to_affine().into(); - Self(NodeInfo { - bls_vk, - schnorr_vk: schnorr.into(), - is_da: e.da, - }) - } -} - -// #[derive(Debug, Clone, Serialize, Deserialize)] -// struct StakeTable(Vec>); From 0862ca73a01597af6fd9bec4fa6a627d9e5a02c2 Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 15:43:04 +0100 Subject: [PATCH 13/58] Load initial stake table from file --- contracts/rust/adapter/src/stake_table.rs | 18 ++++++++++- sequencer/src/bin/deploy.rs | 5 +-- utils/src/deployer.rs | 12 +++---- utils/src/stake_table.rs | 38 +++++++++++------------ 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/contracts/rust/adapter/src/stake_table.rs b/contracts/rust/adapter/src/stake_table.rs index 46abf81fe0..52d5c1b9db 100644 --- a/contracts/rust/adapter/src/stake_table.rs +++ b/contracts/rust/adapter/src/stake_table.rs @@ -14,7 +14,7 @@ use ethers::{ prelude::{AbiError, EthAbiCodec, EthAbiType}, types::U256, }; -use hotshot_types::{light_client::StateVerKey, signature_key::BLSPubKey}; +use hotshot_types::{light_client::StateVerKey, network::PeerConfigKeys, signature_key::BLSPubKey}; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -174,3 +174,19 @@ impl From for NodeInfoJf { .into() } } + +impl From> for NodeInfoJf { + fn from(value: PeerConfigKeys) -> Self { + let PeerConfigKeys { + stake_table_key, + state_ver_key, + da, + .. + } = value; + Self { + stake_table_key, + state_ver_key, + da, + } + } +} diff --git a/sequencer/src/bin/deploy.rs b/sequencer/src/bin/deploy.rs index c6793a0466..d3a62204ae 100644 --- a/sequencer/src/bin/deploy.rs +++ b/sequencer/src/bin/deploy.rs @@ -1,7 +1,6 @@ use std::{fs::File, io::stdout, path::PathBuf}; use clap::Parser; -use espresso_types::PubKey; use ethers::types::Address; use futures::FutureExt; use hotshot_stake_table::config::STAKE_TABLE_CAPACITY; @@ -143,9 +142,7 @@ async fn main() -> anyhow::Result<()> { let genesis = light_client_genesis(&sequencer_url, opt.stake_table_capacity).boxed(); let initial_stake_table = if let Some(path) = opt.initial_stake_table_path { - Some(PermissionedStakeTableConfig::::from_toml_file( - &path, - )?) + Some(PermissionedStakeTableConfig::from_toml_file(&path)?.into()) } else { None }; diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index 51324acc3b..2f382c6659 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -7,7 +7,7 @@ use contract_bindings::{ light_client_mock::LIGHTCLIENTMOCK_ABI, light_client_state_update_vk::LightClientStateUpdateVK, light_client_state_update_vk_mock::LightClientStateUpdateVKMock, - permissioned_stake_table::PermissionedStakeTable, + permissioned_stake_table::{NodeInfo, PermissionedStakeTable}, plonk_verifier::PlonkVerifier, }; use derive_more::Display; @@ -311,7 +311,7 @@ pub async fn deploy_mock_light_client_contract( } #[allow(clippy::too_many_arguments)] -pub async fn deploy( +pub async fn deploy( l1url: Url, mnemonic: String, account_index: u32, @@ -321,7 +321,7 @@ pub async fn deploy( genesis: BoxFuture<'_, anyhow::Result<(ParsedLightClientState, ParsedStakeTableState)>>, permissioned_prover: Option

, mut contracts: Contracts, - initial_stake_table: Option>, + initial_stake_table: Option>, ) -> anyhow::Result { let provider = Provider::::try_from(l1url.to_string())?; let chain_id = provider.get_chainid().await?.as_u64(); @@ -442,13 +442,11 @@ pub async fn deploy( // `PermissionedStakeTable.sol` if should_deploy(ContractGroup::PermissionedStakeTable, &only) { + let initial_stake_table: Vec<_> = initial_stake_table.unwrap_or_default(); let stake_table_address = contracts .deploy_tx( Contract::PermissonedStakeTable, - PermissionedStakeTable::deploy( - l1.clone(), - (), // TODO initial stake table - )?, + PermissionedStakeTable::deploy(l1.clone(), initial_stake_table)?, ) .await?; let stake_table = PermissionedStakeTable::new(stake_table_address, l1.clone()); diff --git a/utils/src/stake_table.rs b/utils/src/stake_table.rs index a2a467cedb..1129ad66b4 100644 --- a/utils/src/stake_table.rs +++ b/utils/src/stake_table.rs @@ -1,47 +1,47 @@ +/// Utilities for loading an initial permissioned stake table from a toml file. +/// +/// The initial stake table is passed to the permissioned stake table contract +/// on deployment. use contract_bindings::permissioned_stake_table::NodeInfo; -use hotshot::types::SignatureKey; -use hotshot_contract_adapter::stake_table::ParsedEdOnBN254Point; +use hotshot::types::{BLSPubKey, SignatureKey}; +use hotshot_contract_adapter::stake_table::{NodeInfoJf, ParsedEdOnBN254Point}; use hotshot_types::network::PeerConfigKeys; use std::{fs, path::Path}; /// A stake table config stored in a file #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(bound(deserialize = ""))] -pub struct PermissionedStakeTableConfig { +pub struct PermissionedStakeTableConfig { /// The list of public keys that are initially inserted into the /// permissioned stake table contract. #[serde(default)] - pub public_keys: Vec>, + pub public_keys: Vec>, } -impl PermissionedStakeTableConfig { +impl PermissionedStakeTableConfig { pub fn from_toml_file(path: &Path) -> anyhow::Result { let config_file_as_string: String = fs::read_to_string(path) .unwrap_or_else(|_| panic!("Could not read config file located at {}", path.display())); Ok( - toml::from_str::(&config_file_as_string).expect(&format!( - "Unable to convert config file {} to TOML", - path.display() - )), + toml::from_str::(&config_file_as_string).unwrap_or_else(|err| { + panic!( + "Unable to convert config file {} to TOML: {err}", + path.display() + ) + }), ) } } -impl From> for Vec { - fn from(value: PermissionedStakeTableConfig) -> Self { +impl From for Vec { + fn from(value: PermissionedStakeTableConfig) -> Self { value .public_keys .into_iter() .map(|peer_config| { - let g1: ParsedEdOnBN254Point = peer_config.state_ver_key.to_affine().into(); - // XXX We don't have a trait on the Bls key to provide .to_affine() - // let g2: ParsedG2Point = peer_config.stake_table_key.to_affine().into(); - NodeInfo { - bls_vk: todo!(), - schnorr_vk: g1.into(), - is_da: peer_config.da, - } + let node_info: NodeInfoJf = peer_config.clone().into(); + node_info.into() }) .collect() } From 1b2ccd533dc88c2c5c97e143ac5d20e18990aac5 Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 15:53:12 +0100 Subject: [PATCH 14/58] remove unused imports --- utils/src/deployer.rs | 3 --- utils/src/stake_table.rs | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index 2f382c6659..bf62d71573 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -16,7 +16,6 @@ use ethers::{ utils::hex, }; use futures::future::{BoxFuture, FutureExt}; -use hotshot::types::SignatureKey; use hotshot_contract_adapter::light_client::{ LightClientConstructorArgs, ParsedLightClientState, ParsedStakeTableState, }; @@ -24,8 +23,6 @@ use std::sync::Arc; use std::{collections::HashMap, io::Write, ops::Deref}; use url::Url; -use crate::stake_table::PermissionedStakeTableConfig; - /// Set of predeployed contracts. #[derive(Clone, Debug, Parser)] pub struct DeployedContracts { diff --git a/utils/src/stake_table.rs b/utils/src/stake_table.rs index 1129ad66b4..1f5dbda0b5 100644 --- a/utils/src/stake_table.rs +++ b/utils/src/stake_table.rs @@ -3,8 +3,8 @@ /// The initial stake table is passed to the permissioned stake table contract /// on deployment. use contract_bindings::permissioned_stake_table::NodeInfo; -use hotshot::types::{BLSPubKey, SignatureKey}; -use hotshot_contract_adapter::stake_table::{NodeInfoJf, ParsedEdOnBN254Point}; +use hotshot::types::BLSPubKey; +use hotshot_contract_adapter::stake_table::NodeInfoJf; use hotshot_types::network::PeerConfigKeys; use std::{fs, path::Path}; From b2d5236c63b24b5d8763933e26badef2ee639a95 Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 15:59:48 +0100 Subject: [PATCH 15/58] remove unused module --- types/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/types/src/lib.rs b/types/src/lib.rs index 54bfcbba7b..0ce6950965 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -3,6 +3,5 @@ pub mod v0; // Re-export the latest major version compatibility types. pub use v0::*; -mod eth; pub mod eth_signature_key; mod reference_tests; From b642d06afa05ad792b57b30e9b737aeee91bb6c4 Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 16:15:39 +0100 Subject: [PATCH 16/58] dev-node: fix arguments to deploy function --- sequencer/src/bin/espresso-dev-node.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sequencer/src/bin/espresso-dev-node.rs b/sequencer/src/bin/espresso-dev-node.rs index a6e19d41c9..1280c87315 100644 --- a/sequencer/src/bin/espresso-dev-node.rs +++ b/sequencer/src/bin/espresso-dev-node.rs @@ -270,6 +270,7 @@ async fn main() -> anyhow::Result<()> { async { Ok(lc_genesis.clone()) }.boxed(), None, contracts.clone(), + None, // initial stake table ) .await?; From 2827cfa43873b8e77548b76c1082ac5a11787c0f Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 16:21:47 +0100 Subject: [PATCH 17/58] fix clippy --- contracts/rust/adapter/src/stake_table.rs | 1 - sequencer/src/bin/deploy.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/contracts/rust/adapter/src/stake_table.rs b/contracts/rust/adapter/src/stake_table.rs index 52d5c1b9db..a3ed6f7383 100644 --- a/contracts/rust/adapter/src/stake_table.rs +++ b/contracts/rust/adapter/src/stake_table.rs @@ -171,7 +171,6 @@ impl From for NodeInfoJf { state_ver_key, da: is_da, } - .into() } } diff --git a/sequencer/src/bin/deploy.rs b/sequencer/src/bin/deploy.rs index d3a62204ae..604e7248c2 100644 --- a/sequencer/src/bin/deploy.rs +++ b/sequencer/src/bin/deploy.rs @@ -118,8 +118,8 @@ struct Options { /// /// public_keys = [ /// { - /// stake_table_key = "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", - /// state_ver_key = "SCHNORR_VER_KEY~lJqDaVZyM0hWP2Br52IX5FeE-dCAIC-dPX7bL5-qUx-vjbunwe-ENOeZxj6FuOyvDCFzoGeP7yZ0fM995qF-CRE", + /// stake_table_key = "BLS_VER_KEY~...", + /// state_ver_key = "SCHNORR_VER_KEY~...", /// da = true, /// }, /// ] From e15c2b3bbe0db4ac3e878531d5bbb5ae66b9d9fc Mon Sep 17 00:00:00 2001 From: sveitser Date: Thu, 5 Dec 2024 16:53:09 +0100 Subject: [PATCH 18/58] fix Cargo.toml for bindings generation breaks if we use: `serde.workspace = true` --- contracts/rust/adapter/Cargo.toml | 2 +- utils/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/rust/adapter/Cargo.toml b/contracts/rust/adapter/Cargo.toml index 5f095044cc..947e8f568f 100644 --- a/contracts/rust/adapter/Cargo.toml +++ b/contracts/rust/adapter/Cargo.toml @@ -24,7 +24,7 @@ jf-plonk = { workspace = true } jf-utils = { workspace = true } num-bigint = { version = "0.4", default-features = false } num-traits = { version = "0.2", default-features = false } -serde.workspace = true +serde = { workspace = true } [[bin]] name = "eval-domain" diff --git a/utils/Cargo.toml b/utils/Cargo.toml index 0a89952ef5..27aa0f435a 100644 --- a/utils/Cargo.toml +++ b/utils/Cargo.toml @@ -19,8 +19,8 @@ derive_more = { workspace = true } ethers = { workspace = true } futures = { workspace = true } hotshot = { workspace = true } -hotshot-types = { workspace = true } hotshot-contract-adapter = { workspace = true } +hotshot-types = { workspace = true } log-panics = { workspace = true } portpicker = { workspace = true } # for price oracle and align with ethers-rs dep From 1120c7b7528346825a5de22fcb5ea0a81118aa64 Mon Sep 17 00:00:00 2001 From: sveitser Date: Fri, 6 Dec 2024 17:15:54 +0100 Subject: [PATCH 19/58] combine adding and removing into single event --- .../src/permissioned_stake_table.rs | 498 +++++++++--------- contracts/src/PermissionedStakeTable.sol | 26 +- contracts/test/PermissionedStakeTable.t.sol | 33 +- 3 files changed, 274 insertions(+), 283 deletions(-) diff --git a/contract-bindings/src/permissioned_stake_table.rs b/contract-bindings/src/permissioned_stake_table.rs index a9d2e911d0..416ad97bdf 100644 --- a/contract-bindings/src/permissioned_stake_table.rs +++ b/contract-bindings/src/permissioned_stake_table.rs @@ -14,40 +14,27 @@ pub mod permissioned_stake_table { fn __abi() -> ::ethers::core::abi::Abi { ::ethers::core::abi::ethabi::Contract { constructor: ::core::option::Option::Some(::ethers::core::abi::ethabi::Constructor { - inputs: ::std::vec![ - ::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("initialOwner"), - kind: ::ethers::core::abi::ethabi::ParamType::Address, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("address"), - ), - }, - ::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("initialStakers"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new(::ethers::core::abi::ethabi::ParamType::Tuple( - ::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Bool, - ], - ),), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct PermissionedStakeTable.NodeInfo[]", - ), - ), - }, - ], + inputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("initialStakers"), + kind: ::ethers::core::abi::ethabi::ParamType::Array(::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Bool, + ],), + ),), + internal_type: ::core::option::Option::Some(::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ),), + },], }), functions: ::core::convert::From::from([ ( @@ -77,40 +64,6 @@ pub mod permissioned_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::Pure, },], ), - ( - ::std::borrow::ToOwned::to_owned("insert"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("insert"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("newStakers"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Bool, - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct PermissionedStakeTable.NodeInfo[]", - ), - ), - },], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), ( ::std::borrow::ToOwned::to_owned("isStaker"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -154,40 +107,6 @@ pub mod permissioned_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, },], ), - ( - ::std::borrow::ToOwned::to_owned("remove"), - ::std::vec![::ethers::core::abi::ethabi::Function { - name: ::std::borrow::ToOwned::to_owned("remove"), - inputs: ::std::vec![::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("stakersToRemove"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ],), - ::ethers::core::abi::ethabi::ParamType::Bool, - ],), - ), - ), - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned( - "struct PermissionedStakeTable.NodeInfo[]", - ), - ), - },], - outputs: ::std::vec![], - constant: ::core::option::Option::None, - state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, - },], - ), ( ::std::borrow::ToOwned::to_owned("renounceOwnership"), ::std::vec![::ethers::core::abi::ethabi::Function { @@ -214,36 +133,101 @@ pub mod permissioned_stake_table { state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, },], ), - ]), - events: ::core::convert::From::from([ ( - ::std::borrow::ToOwned::to_owned("Added"), - ::std::vec![::ethers::core::abi::ethabi::Event { - name: ::std::borrow::ToOwned::to_owned("Added"), - inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::std::borrow::ToOwned::to_owned("update"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("update"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("stakersToRemove"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Bool, ],), + ), + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("newStakers"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Bool, ],), - ::ethers::core::abi::ethabi::ParamType::Bool, - ],), + ), ), - ), - indexed: false, - },], - anonymous: false, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct PermissionedStakeTable.NodeInfo[]", + ), + ), + }, + ], + outputs: ::std::vec![], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::NonPayable, },], ), + ]), + events: ::core::convert::From::from([ ( ::std::borrow::ToOwned::to_owned("OwnershipTransferred"), ::std::vec![::ethers::core::abi::ethabi::Event { @@ -264,30 +248,85 @@ pub mod permissioned_stake_table { },], ), ( - ::std::borrow::ToOwned::to_owned("Removed"), + ::std::borrow::ToOwned::to_owned("StakersUpdated"), ::std::vec![::ethers::core::abi::ethabi::Event { - name: ::std::borrow::ToOwned::to_owned("Removed"), - inputs: ::std::vec![::ethers::core::abi::ethabi::EventParam { - name: ::std::string::String::new(), - kind: ::ethers::core::abi::ethabi::ParamType::Array( - ::std::boxed::Box::new( - ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + name: ::std::borrow::ToOwned::to_owned("StakersUpdated"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("removed"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Bool, ],), + ), + ), + indexed: false, + }, + ::ethers::core::abi::ethabi::EventParam { + name: ::std::borrow::ToOwned::to_owned("added"), + kind: ::ethers::core::abi::ethabi::ParamType::Array( + ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), - ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Tuple( + ::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ::ethers::core::abi::ethabi::ParamType::Uint( + 256usize + ), + ], + ), + ::ethers::core::abi::ethabi::ParamType::Bool, ],), - ::ethers::core::abi::ethabi::ParamType::Bool, - ],), + ), ), - ), - indexed: false, - },], + indexed: false, + }, + ], anonymous: false, },], ), @@ -364,12 +403,12 @@ pub mod permissioned_stake_table { pub static PERMISSIONEDSTAKETABLE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0\r\x108\x03\x80b\0\r\x10\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x03\x81V[\x81`\x01`\x01`\xA0\x1B\x03\x81\x16b\0\0eW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01[`@Q\x80\x91\x03\x90\xFD[b\0\0p\x81b\0\0\x84V[Pb\0\0|\x81b\0\0\xD4V[PPb\0\x05\x7FV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[b\0\0\xDEb\0\x01\xF2V[`\0[\x81Q\x81\x10\x15b\0\x01\xB5W`\0b\0\x01\x1E\x83\x83\x81Q\x81\x10b\0\x01\x06Wb\0\x01\x06b\0\x04\xD7V[` \x02` \x01\x01Q`\0\x01Qb\0\x02#` \x1B` \x1CV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15b\0\x01\x93W\x82\x82\x81Q\x81\x10b\0\x01NWb\0\x01Nb\0\x04\xD7V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01b\0\0\\V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01b\0\0\xE1V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qb\0\x01\xE7\x91\x90b\0\x04\xEDV[`@Q\x80\x91\x03\x90\xA1PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14b\0\x02!W`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01b\0\0\\V[V[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01b\0\x02c\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\xBBWb\0\x02\xBBb\0\x02\x80V[`@R\x90V[`@Q`\x80\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\xBBWb\0\x02\xBBb\0\x02\x80V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x03\x11Wb\0\x03\x11b\0\x02\x80V[`@R\x91\x90PV[`\0`@\x82\x84\x03\x12\x15b\0\x03,W`\0\x80\xFD[`@\x80Q\x90\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x03QWb\0\x03Qb\0\x02\x80V[`@R\x82Q\x81R` \x92\x83\x01Q\x92\x81\x01\x92\x90\x92RP\x91\x90PV[\x80Q\x80\x15\x15\x81\x14b\0\x03|W`\0\x80\xFD[\x91\x90PV[`\0\x80`@\x80\x84\x86\x03\x12\x15b\0\x03\x96W`\0\x80\xFD[\x83Q`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14b\0\x03\xAEW`\0\x80\xFD[` \x85\x81\x01Q\x91\x94P\x90`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\x03\xCEW`\0\x80\xFD[\x81\x87\x01\x91P\x87`\x1F\x83\x01\x12b\0\x03\xE3W`\0\x80\xFD[\x81Q\x81\x81\x11\x15b\0\x03\xF8Wb\0\x03\xF8b\0\x02\x80V[b\0\x04\x08\x84\x82`\x05\x1B\x01b\0\x02\xE6V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x8A\x83\x11\x15b\0\x04(W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15b\0\x04\xC6W\x84\x8B\x03\x81\x81\x12\x15b\0\x04HW`\0\x80\x81\xFD[b\0\x04Rb\0\x02\x96V[`\x80\x80\x83\x12\x15b\0\x04cW`\0\x80\x81\xFD[b\0\x04mb\0\x02\xC1V[\x88Q\x81R\x89\x89\x01Q\x8A\x82\x01R\x8A\x89\x01Q\x8B\x82\x01R``\x80\x8A\x01Q\x90\x82\x01R\x80\x83R\x92Pb\0\x04\x9E\x8E\x82\x8A\x01b\0\x03\x19V[\x89\x83\x01RPb\0\x04\xB1`\xC0\x88\x01b\0\x03kV[\x81\x8A\x01R\x85RP\x93\x84\x01\x93\x92\x85\x01\x92b\0\x04-V[P\x80\x96PPPPPPP\x92P\x92\x90PV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15b\0\x05rW\x81Qb\0\x05B\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01b\0\x05\nV[P\x91\x97\x96PPPPPPPV[a\x07\x81\x80b\0\x05\x8F`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + const __BYTECODE: &[u8] = b"`\x80`@R4\x80\x15b\0\0\x11W`\0\x80\xFD[P`@Qb\0\x0B\xF28\x03\x80b\0\x0B\xF2\x839\x81\x01`@\x81\x90Rb\0\x004\x91b\0\x03\x03V[3\x80b\0\0\\W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01[`@Q\x80\x91\x03\x90\xFD[b\0\0g\x81b\0\0zV[Pb\0\0s\x81b\0\0\xCAV[Pb\0\x04LV[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0[\x81Q\x81\x10\x15b\0\x01\xA1W`\0b\0\x01\n\x83\x83\x81Q\x81\x10b\0\0\xF2Wb\0\0\xF2b\0\x046V[` \x02` \x01\x01Q`\0\x01Qb\0\x01\xA5` \x1B` \x1CV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15b\0\x01\x7FW\x82\x82\x81Q\x81\x10b\0\x01:Wb\0\x01:b\0\x046V[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01b\0\0SV[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01b\0\0\xCDV[PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01b\0\x01\xE5\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02=Wb\0\x02=b\0\x02\x02V[`@R\x90V[`@Q`\x80\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02=Wb\0\x02=b\0\x02\x02V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\x93Wb\0\x02\x93b\0\x02\x02V[`@R\x91\x90PV[`\0`@\x82\x84\x03\x12\x15b\0\x02\xAEW`\0\x80\xFD[`@\x80Q\x90\x81\x01`\x01`\x01`@\x1B\x03\x81\x11\x82\x82\x10\x17\x15b\0\x02\xD3Wb\0\x02\xD3b\0\x02\x02V[`@R\x82Q\x81R` \x92\x83\x01Q\x92\x81\x01\x92\x90\x92RP\x91\x90PV[\x80Q\x80\x15\x15\x81\x14b\0\x02\xFEW`\0\x80\xFD[\x91\x90PV[`\0` \x80\x83\x85\x03\x12\x15b\0\x03\x17W`\0\x80\xFD[\x82Q`\x01`\x01`@\x1B\x03\x80\x82\x11\x15b\0\x03/W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12b\0\x03DW`\0\x80\xFD[\x81Q\x81\x81\x11\x15b\0\x03YWb\0\x03Yb\0\x02\x02V[b\0\x03i\x84\x82`\x05\x1B\x01b\0\x02hV[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15b\0\x03\x89W`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15b\0\x04*W\x84\x89\x03\x81\x81\x12\x15b\0\x03\xA9W`\0\x80\x81\xFD[b\0\x03\xB3b\0\x02\x18V[`\x80\x80\x83\x12\x15b\0\x03\xC4W`\0\x80\x81\xFD[b\0\x03\xCEb\0\x02CV[\x92P\x87Q\x83R\x88\x88\x01Q\x89\x84\x01R`@\x80\x89\x01Q\x81\x85\x01R``\x80\x8A\x01Q\x81\x86\x01RP\x83\x83Rb\0\x04\x02\x8D\x83\x8B\x01b\0\x02\x9BV[\x8A\x84\x01Rb\0\x04\x14`\xC0\x8A\x01b\0\x02\xEDV[\x90\x83\x01RP\x85RP\x93\x84\x01\x93\x92\x85\x01\x92b\0\x03\x8EV[P\x97\x96PPPPPPPV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[a\x07\x96\x80b\0\x04\\`\09`\0\xF3\xFE`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0bW`\x005`\xE0\x1C\x80cqP\x18\xA6\x14a\0gW\x80cu\xD7\x05\xE9\x14a\0qW\x80c\x8D\xA5\xCB[\x14a\0\x99W\x80c\x9B0\xA5\xE6\x14a\0\xB4W\x80c\xA8\xA0\xEA\\\x14a\0\xD5W\x80c\xF2\xFD\xE3\x8B\x14a\0\xE8W[`\0\x80\xFD[a\0oa\0\xFBV[\0[a\0\x84a\0\x7F6`\x04a\x05\x1EV[a\x01\x0FV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\x90V[a\0\xC7a\0\xC26`\x04a\x05\x1EV[a\x018V[`@Q\x90\x81R` \x01a\0\x90V[a\0oa\0\xE36`\x04a\x062V[a\x01\x94V[a\0oa\0\xF66`\x04a\x06\x96V[a\x01\xEBV[a\x01\x03a\x02.V[a\x01\r`\0a\x02[V[V[`\0`\x01`\0a\x01\x1E\x84a\x018V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x01w\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x01\x9Ca\x02.V[a\x01\xA5\x82a\x02\xABV[a\x01\xAE\x81a\x03qV[\x7F5\r\xA2J2\x14l\xFD\x14\xB4\xFD\x11\xFB>;t\xA3\xB9\xA0\xCC\x92\x01KEL)S\xA0\x0E\xAB\xA3=\x82\x82`@Qa\x01\xDF\x92\x91\x90a\x07EV[`@Q\x80\x91\x03\x90\xA1PPV[a\x01\xF3a\x02.V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x02\"W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01[`@Q\x80\x91\x03\x90\xFD[a\x02+\x81a\x02[V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x01\rW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x02\x19V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0[\x81Q\x81\x10\x15a\x03mW`\0a\x02\xDF\x83\x83\x81Q\x81\x10a\x02\xCEWa\x02\xCEa\x07sV[` \x02` \x01\x01Q`\0\x01Qa\x018V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03NW\x82\x82\x81Q\x81\x10a\x03\nWa\x03\na\x07sV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x02\x19V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xAEV[PPV[`\0[\x81Q\x81\x10\x15a\x03mW`\0a\x03\x94\x83\x83\x81Q\x81\x10a\x02\xCEWa\x02\xCEa\x07sV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x04\x04W\x82\x82\x81Q\x81\x10a\x03\xC0Wa\x03\xC0a\x07sV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x02\x19V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x03tV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04^Wa\x04^a\x04%V[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04^Wa\x04^a\x04%V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xB0Wa\x04\xB0a\x04%V[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xCAW`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xEDWa\x04\xEDa\x04%V[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0`\x80\x82\x84\x03\x12\x15a\x050W`\0\x80\xFD[a\x05:\x83\x83a\x04\xB8V[\x93\x92PPPV[`\0\x82`\x1F\x83\x01\x12a\x05RW`\0\x80\xFD[\x815` g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x05nWa\x05na\x04%V[a\x05|\x81\x83`\x05\x1B\x01a\x04\x87V[\x82\x81R`\xE0\x92\x83\x02\x85\x01\x82\x01\x92\x82\x82\x01\x91\x90\x87\x85\x11\x15a\x05\x9BW`\0\x80\xFD[\x83\x87\x01[\x85\x81\x10\x15a\x06%W\x80\x89\x03\x82\x81\x12\x15a\x05\xB8W`\0\x80\x81\xFD[a\x05\xC0a\x04;V[a\x05\xCA\x8B\x84a\x04\xB8V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x05\xE0W`\0\x80\x81\xFD[a\x05\xE8a\x04dV[`\x80\x85\x015\x81R`\xA0\x85\x015\x89\x82\x01R\x82\x89\x01R`\xC0\x84\x015\x92P\x82\x15\x15\x83\x14a\x06\x12W`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x92\x84\x01\x92\x81\x01a\x05\x9FV[P\x90\x97\x96PPPPPPPV[`\0\x80`@\x83\x85\x03\x12\x15a\x06EW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x06]W`\0\x80\xFD[a\x06i\x86\x83\x87\x01a\x05AV[\x93P` \x85\x015\x91P\x80\x82\x11\x15a\x06\x7FW`\0\x80\xFD[Pa\x06\x8C\x85\x82\x86\x01a\x05AV[\x91PP\x92P\x92\x90PV[`\0` \x82\x84\x03\x12\x15a\x06\xA8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05:W`\0\x80\xFD[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P` \x84\x01`\0[\x83\x81\x10\x15a\x07:W\x81Qa\x07\n\x88\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x84\x01Q\x80Q`\x80\x8A\x01R\x84\x01Q`\xA0\x89\x01R`@\x01Q\x15\x15`\xC0\x88\x01R`\xE0\x90\x96\x01\x95\x90\x82\x01\x90`\x01\x01a\x06\xD4V[P\x94\x95\x94PPPPPV[`@\x81R`\0a\x07X`@\x83\x01\x85a\x06\xBFV[\x82\x81\x03` \x84\x01Ra\x07j\x81\x85a\x06\xBFV[\x95\x94PPPPPV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD\xFE\xA1dsolcC\0\x08\x17\0\n"; /// The bytecode of the contract. pub static PERMISSIONEDSTAKETABLE_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0}W`\x005`\xE0\x1C\x80c\x8D\xA5\xCB[\x11a\0[W\x80c\x8D\xA5\xCB[\x14a\0\xC7W\x80c\x9B0\xA5\xE6\x14a\0\xE2W\x80c\xCD\x1D\xA5\xE5\x14a\x01\x03W\x80c\xF2\xFD\xE3\x8B\x14a\x01\x16W`\0\x80\xFD[\x80cQ\x82`4\x14a\0\x82W\x80cqP\x18\xA6\x14a\0\x97W\x80cu\xD7\x05\xE9\x14a\0\x9FW[`\0\x80\xFD[a\0\x95a\0\x906`\x04a\x05lV[a\x01)V[\0[a\0\x95a\x023V[a\0\xB2a\0\xAD6`\x04a\x06\x83V[a\x02GV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\xBEV[a\0\xF5a\0\xF06`\x04a\x06\x83V[a\x02pV[`@Q\x90\x81R` \x01a\0\xBEV[a\0\x95a\x01\x116`\x04a\x05lV[a\x02\xCCV[a\0\x95a\x01$6`\x04a\x06\xA6V[a\x03\xB8V[a\x011a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x01\xF8W`\0a\x01e\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[` \x02` \x01\x01Q`\0\x01Qa\x02pV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x01\xD9W\x82\x82\x81Q\x81\x10a\x01\x90Wa\x01\x90a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01[`@Q\x80\x91\x03\x90\xFD[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x014V[P\x7F\xD4\xBD\x18%\xB9a\xF5\xC0\xFF\xB5\xCB\xA8\x15\x04\x14\x0F\xA9\x9D\x99/V\xD08\xA0Y\xD0{qa\xFC\x16\xFD\x81`@Qa\x02(\x91\x90a\x06\xE5V[`@Q\x80\x91\x03\x90\xA1PV[a\x02;a\x03\xF6V[a\x02E`\0a\x04#V[V[`\0`\x01`\0a\x02V\x84a\x02pV[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x02\xAF\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x02\xD4a\x03\xF6V[`\0[\x81Q\x81\x10\x15a\x03\x88W`\0a\x02\xF7\x83\x83\x81Q\x81\x10a\x01TWa\x01Ta\x06\xCFV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x03gW\x82\x82\x81Q\x81\x10a\x03#Wa\x03#a\x06\xCFV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x01\xD0V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x02\xD7V[P\x7FN\x90\xAE!_1`\x99\xC2\xB6gD%.\x9F\x07\x17\xC7\x9E)\x8B\xA0^#&\x0F\xFAiW\x85T\xF5\x81`@Qa\x02(\x91\x90a\x06\xE5V[a\x03\xC0a\x03\xF6V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x03\xEAW`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01a\x01\xD0V[a\x03\xF3\x81a\x04#V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x02EW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x01\xD0V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xACWa\x04\xACa\x04sV[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xFEWa\x04\xFEa\x04sV[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x05\x18W`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x05;Wa\x05;a\x04sV[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0` \x80\x83\x85\x03\x12\x15a\x05\x7FW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x05\x97W`\0\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x05\xABW`\0\x80\xFD[\x815\x81\x81\x11\x15a\x05\xBDWa\x05\xBDa\x04sV[a\x05\xCB\x84\x82`\x05\x1B\x01a\x04\xD5V[\x81\x81R\x84\x81\x01\x92P`\xE0\x91\x82\x02\x84\x01\x85\x01\x91\x88\x83\x11\x15a\x05\xEAW`\0\x80\xFD[\x93\x85\x01\x93[\x82\x85\x10\x15a\x06wW\x84\x89\x03\x81\x81\x12\x15a\x06\x08W`\0\x80\x81\xFD[a\x06\x10a\x04\x89V[a\x06\x1A\x8B\x88a\x05\x06V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x060W`\0\x80\x81\xFD[a\x068a\x04\xB2V[`\x80\x89\x015\x81R`\xA0\x89\x015\x8A\x82\x01R\x82\x8A\x01R`\xC0\x88\x015\x92P\x82\x15\x15\x83\x14a\x06bW`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x93\x84\x01\x93\x92\x85\x01\x92a\x05\xEFV[P\x97\x96PPPPPPPV[`\0`\x80\x82\x84\x03\x12\x15a\x06\x95W`\0\x80\xFD[a\x06\x9F\x83\x83a\x05\x06V[\x93\x92PPPV[`\0` \x82\x84\x03\x12\x15a\x06\xB8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x06\x9FW`\0\x80\xFD[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[` \x80\x82R\x82Q\x82\x82\x01\x81\x90R`\0\x91\x90`@\x90\x81\x85\x01\x90\x86\x84\x01\x85[\x82\x81\x10\x15a\x07gW\x81Qa\x078\x85\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x87\x01Q\x80Q`\x80\x87\x01R\x87\x01Q`\xA0\x86\x01R\x85\x01Q\x15\x15`\xC0\x85\x01R`\xE0\x90\x93\x01\x92\x90\x85\x01\x90`\x01\x01a\x07\x02V[P\x91\x97\x96PPPPPPPV\xFE\xA1dsolcC\0\x08\x17\0\n"; + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R4\x80\x15a\0\x10W`\0\x80\xFD[P`\x046\x10a\0bW`\x005`\xE0\x1C\x80cqP\x18\xA6\x14a\0gW\x80cu\xD7\x05\xE9\x14a\0qW\x80c\x8D\xA5\xCB[\x14a\0\x99W\x80c\x9B0\xA5\xE6\x14a\0\xB4W\x80c\xA8\xA0\xEA\\\x14a\0\xD5W\x80c\xF2\xFD\xE3\x8B\x14a\0\xE8W[`\0\x80\xFD[a\0oa\0\xFBV[\0[a\0\x84a\0\x7F6`\x04a\x05\x1EV[a\x01\x0FV[`@Q\x90\x15\x15\x81R` \x01[`@Q\x80\x91\x03\x90\xF3[`\0T`@Q`\x01`\x01`\xA0\x1B\x03\x90\x91\x16\x81R` \x01a\0\x90V[a\0\xC7a\0\xC26`\x04a\x05\x1EV[a\x018V[`@Q\x90\x81R` \x01a\0\x90V[a\0oa\0\xE36`\x04a\x062V[a\x01\x94V[a\0oa\0\xF66`\x04a\x06\x96V[a\x01\xEBV[a\x01\x03a\x02.V[a\x01\r`\0a\x02[V[V[`\0`\x01`\0a\x01\x1E\x84a\x018V[\x81R` \x81\x01\x91\x90\x91R`@\x01`\0 T`\xFF\x16\x92\x91PPV[`\0\x81`\0\x01Q\x82` \x01Q\x83`@\x01Q\x84``\x01Q`@Q` \x01a\x01w\x94\x93\x92\x91\x90\x93\x84R` \x84\x01\x92\x90\x92R`@\x83\x01R``\x82\x01R`\x80\x01\x90V[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x80Q\x90` \x01 \x90P\x91\x90PV[a\x01\x9Ca\x02.V[a\x01\xA5\x82a\x02\xABV[a\x01\xAE\x81a\x03qV[\x7F5\r\xA2J2\x14l\xFD\x14\xB4\xFD\x11\xFB>;t\xA3\xB9\xA0\xCC\x92\x01KEL)S\xA0\x0E\xAB\xA3=\x82\x82`@Qa\x01\xDF\x92\x91\x90a\x07EV[`@Q\x80\x91\x03\x90\xA1PPV[a\x01\xF3a\x02.V[`\x01`\x01`\xA0\x1B\x03\x81\x16a\x02\"W`@Qc\x1EO\xBD\xF7`\xE0\x1B\x81R`\0`\x04\x82\x01R`$\x01[`@Q\x80\x91\x03\x90\xFD[a\x02+\x81a\x02[V[PV[`\0T`\x01`\x01`\xA0\x1B\x03\x163\x14a\x01\rW`@Qc\x11\x8C\xDA\xA7`\xE0\x1B\x81R3`\x04\x82\x01R`$\x01a\x02\x19V[`\0\x80T`\x01`\x01`\xA0\x1B\x03\x83\x81\x16`\x01`\x01`\xA0\x1B\x03\x19\x83\x16\x81\x17\x84U`@Q\x91\x90\x92\x16\x92\x83\x91\x7F\x8B\xE0\x07\x9CS\x16Y\x14\x13D\xCD\x1F\xD0\xA4\xF2\x84\x19I\x7F\x97\"\xA3\xDA\xAF\xE3\xB4\x18okdW\xE0\x91\x90\xA3PPV[`\0[\x81Q\x81\x10\x15a\x03mW`\0a\x02\xDF\x83\x83\x81Q\x81\x10a\x02\xCEWa\x02\xCEa\x07sV[` \x02` \x01\x01Q`\0\x01Qa\x018V[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16a\x03NW\x82\x82\x81Q\x81\x10a\x03\nWa\x03\na\x07sV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc4\xA7V\x1F`\xE0\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x02\x19V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x90U\x01a\x02\xAEV[PPV[`\0[\x81Q\x81\x10\x15a\x03mW`\0a\x03\x94\x83\x83\x81Q\x81\x10a\x02\xCEWa\x02\xCEa\x07sV[`\0\x81\x81R`\x01` R`@\x90 T\x90\x91P`\xFF\x16\x15a\x04\x04W\x82\x82\x81Q\x81\x10a\x03\xC0Wa\x03\xC0a\x07sV[` \x90\x81\x02\x91\x90\x91\x01\x81\x01QQ`@\x80Qc\x1B\x06\xE1A`\xE1\x1B\x81R\x82Q`\x04\x82\x01R\x92\x82\x01Q`$\x84\x01R\x81\x01Q`D\x83\x01R``\x01Q`d\x82\x01R`\x84\x01a\x02\x19V[`\0\x90\x81R`\x01` \x81\x90R`@\x90\x91 \x80T`\xFF\x19\x16\x82\x17\x90U\x01a\x03tV[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@Q``\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04^Wa\x04^a\x04%V[`@R\x90V[`@\x80Q\x90\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04^Wa\x04^a\x04%V[`@Q`\x1F\x82\x01`\x1F\x19\x16\x81\x01g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x81\x11\x82\x82\x10\x17\x15a\x04\xB0Wa\x04\xB0a\x04%V[`@R\x91\x90PV[`\0`\x80\x82\x84\x03\x12\x15a\x04\xCAW`\0\x80\xFD[`@Q`\x80\x81\x01\x81\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17\x15a\x04\xEDWa\x04\xEDa\x04%V[\x80`@RP\x80\x91P\x825\x81R` \x83\x015` \x82\x01R`@\x83\x015`@\x82\x01R``\x83\x015``\x82\x01RP\x92\x91PPV[`\0`\x80\x82\x84\x03\x12\x15a\x050W`\0\x80\xFD[a\x05:\x83\x83a\x04\xB8V[\x93\x92PPPV[`\0\x82`\x1F\x83\x01\x12a\x05RW`\0\x80\xFD[\x815` g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x15a\x05nWa\x05na\x04%V[a\x05|\x81\x83`\x05\x1B\x01a\x04\x87V[\x82\x81R`\xE0\x92\x83\x02\x85\x01\x82\x01\x92\x82\x82\x01\x91\x90\x87\x85\x11\x15a\x05\x9BW`\0\x80\xFD[\x83\x87\x01[\x85\x81\x10\x15a\x06%W\x80\x89\x03\x82\x81\x12\x15a\x05\xB8W`\0\x80\x81\xFD[a\x05\xC0a\x04;V[a\x05\xCA\x8B\x84a\x04\xB8V[\x81R`@\x80`\x7F\x19\x84\x01\x12\x15a\x05\xE0W`\0\x80\x81\xFD[a\x05\xE8a\x04dV[`\x80\x85\x015\x81R`\xA0\x85\x015\x89\x82\x01R\x82\x89\x01R`\xC0\x84\x015\x92P\x82\x15\x15\x83\x14a\x06\x12W`\0\x80\x81\xFD[\x81\x01\x91\x90\x91R\x84R\x92\x84\x01\x92\x81\x01a\x05\x9FV[P\x90\x97\x96PPPPPPPV[`\0\x80`@\x83\x85\x03\x12\x15a\x06EW`\0\x80\xFD[\x825g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x82\x11\x15a\x06]W`\0\x80\xFD[a\x06i\x86\x83\x87\x01a\x05AV[\x93P` \x85\x015\x91P\x80\x82\x11\x15a\x06\x7FW`\0\x80\xFD[Pa\x06\x8C\x85\x82\x86\x01a\x05AV[\x91PP\x92P\x92\x90PV[`\0` \x82\x84\x03\x12\x15a\x06\xA8W`\0\x80\xFD[\x815`\x01`\x01`\xA0\x1B\x03\x81\x16\x81\x14a\x05:W`\0\x80\xFD[`\0\x81Q\x80\x84R` \x80\x85\x01\x94P` \x84\x01`\0[\x83\x81\x10\x15a\x07:W\x81Qa\x07\n\x88\x82Q\x80Q\x82R` \x81\x01Q` \x83\x01R`@\x81\x01Q`@\x83\x01R``\x81\x01Q``\x83\x01RPPV[\x80\x84\x01Q\x80Q`\x80\x8A\x01R\x84\x01Q`\xA0\x89\x01R`@\x01Q\x15\x15`\xC0\x88\x01R`\xE0\x90\x96\x01\x95\x90\x82\x01\x90`\x01\x01a\x06\xD4V[P\x94\x95\x94PPPPPV[`@\x81R`\0a\x07X`@\x83\x01\x85a\x06\xBFV[\x82\x81\x03` \x84\x01Ra\x07j\x81\x85a\x06\xBFV[\x95\x94PPPPPV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD\xFE\xA1dsolcC\0\x08\x17\0\n"; /// The deployed bytecode of the contract. pub static PERMISSIONEDSTAKETABLE_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); @@ -458,15 +497,6 @@ pub mod permissioned_stake_table { .method_hash([155, 48, 165, 230], (bls_vk,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `insert` (0xcd1da5e5) function - pub fn insert( - &self, - new_stakers: ::std::vec::Vec, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([205, 29, 165, 229], new_stakers) - .expect("method not found (this should never happen)") - } ///Calls the contract's `isStaker` (0x75d705e9) function pub fn is_staker( &self, @@ -484,15 +514,6 @@ pub mod permissioned_stake_table { .method_hash([141, 165, 203, 91], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `remove` (0x51826034) function - pub fn remove( - &self, - stakers_to_remove: ::std::vec::Vec, - ) -> ::ethers::contract::builders::ContractCall { - self.0 - .method_hash([81, 130, 96, 52], stakers_to_remove) - .expect("method not found (this should never happen)") - } ///Calls the contract's `renounceOwnership` (0x715018a6) function pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { self.0 @@ -508,11 +529,15 @@ pub mod permissioned_stake_table { .method_hash([242, 253, 227, 139], new_owner) .expect("method not found (this should never happen)") } - ///Gets the contract's `Added` event - pub fn added_filter( + ///Calls the contract's `update` (0xa8a0ea5c) function + pub fn update( &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, AddedFilter> { - self.0.event() + stakers_to_remove: ::std::vec::Vec, + new_stakers: ::std::vec::Vec, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([168, 160, 234, 92], (stakers_to_remove, new_stakers)) + .expect("method not found (this should never happen)") } ///Gets the contract's `OwnershipTransferred` event pub fn ownership_transferred_filter( @@ -521,10 +546,11 @@ pub mod permissioned_stake_table { { self.0.event() } - ///Gets the contract's `Removed` event - pub fn removed_filter( + ///Gets the contract's `StakersUpdated` event + pub fn stakers_updated_filter( &self, - ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RemovedFilter> { + ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, StakersUpdatedFilter> + { self.0.event() } /// Returns an `Event` builder for all the events of this contract. @@ -758,23 +784,6 @@ pub mod permissioned_stake_table { Eq, Hash, )] - #[ethevent( - name = "Added", - abi = "Added(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" - )] - pub struct AddedFilter(pub ::std::vec::Vec); - #[derive( - Clone, - ::ethers::contract::EthEvent, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] #[ethevent( name = "OwnershipTransferred", abi = "OwnershipTransferred(address,address)" @@ -798,10 +807,13 @@ pub mod permissioned_stake_table { Hash, )] #[ethevent( - name = "Removed", - abi = "Removed(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + name = "StakersUpdated", + abi = "StakersUpdated(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[],((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" )] - pub struct RemovedFilter(pub ::std::vec::Vec); + pub struct StakersUpdatedFilter { + pub removed: ::std::vec::Vec, + pub added: ::std::vec::Vec, + } ///Container type for all of the contract's events #[derive( Clone, @@ -814,24 +826,20 @@ pub mod permissioned_stake_table { Hash, )] pub enum PermissionedStakeTableEvents { - AddedFilter(AddedFilter), OwnershipTransferredFilter(OwnershipTransferredFilter), - RemovedFilter(RemovedFilter), + StakersUpdatedFilter(StakersUpdatedFilter), } impl ::ethers::contract::EthLogDecode for PermissionedStakeTableEvents { fn decode_log( log: &::ethers::core::abi::RawLog, ) -> ::core::result::Result { - if let Ok(decoded) = AddedFilter::decode_log(log) { - return Ok(PermissionedStakeTableEvents::AddedFilter(decoded)); - } if let Ok(decoded) = OwnershipTransferredFilter::decode_log(log) { return Ok(PermissionedStakeTableEvents::OwnershipTransferredFilter( decoded, )); } - if let Ok(decoded) = RemovedFilter::decode_log(log) { - return Ok(PermissionedStakeTableEvents::RemovedFilter(decoded)); + if let Ok(decoded) = StakersUpdatedFilter::decode_log(log) { + return Ok(PermissionedStakeTableEvents::StakersUpdatedFilter(decoded)); } Err(::ethers::core::abi::Error::InvalidData) } @@ -839,25 +847,19 @@ pub mod permissioned_stake_table { impl ::core::fmt::Display for PermissionedStakeTableEvents { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { - Self::AddedFilter(element) => ::core::fmt::Display::fmt(element, f), Self::OwnershipTransferredFilter(element) => ::core::fmt::Display::fmt(element, f), - Self::RemovedFilter(element) => ::core::fmt::Display::fmt(element, f), + Self::StakersUpdatedFilter(element) => ::core::fmt::Display::fmt(element, f), } } } - impl ::core::convert::From for PermissionedStakeTableEvents { - fn from(value: AddedFilter) -> Self { - Self::AddedFilter(value) - } - } impl ::core::convert::From for PermissionedStakeTableEvents { fn from(value: OwnershipTransferredFilter) -> Self { Self::OwnershipTransferredFilter(value) } } - impl ::core::convert::From for PermissionedStakeTableEvents { - fn from(value: RemovedFilter) -> Self { - Self::RemovedFilter(value) + impl ::core::convert::From for PermissionedStakeTableEvents { + fn from(value: StakersUpdatedFilter) -> Self { + Self::StakersUpdatedFilter(value) } } ///Container type for all input parameters for the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` @@ -880,26 +882,6 @@ pub mod permissioned_stake_table { pub struct HashBlsKeyCall { pub bls_vk: G2Point, } - ///Container type for all input parameters for the `insert` function with signature `insert(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])` and selector `0xcd1da5e5` - #[derive( - Clone, - ::ethers::contract::EthCall, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[ethcall( - name = "insert", - abi = "insert(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" - )] - pub struct InsertCall { - pub new_stakers: ::std::vec::Vec, - } ///Container type for all input parameters for the `isStaker` function with signature `isStaker((uint256,uint256,uint256,uint256))` and selector `0x75d705e9` #[derive( Clone, @@ -932,7 +914,7 @@ pub mod permissioned_stake_table { )] #[ethcall(name = "owner", abi = "owner()")] pub struct OwnerCall; - ///Container type for all input parameters for the `remove` function with signature `remove(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])` and selector `0x51826034` + ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` #[derive( Clone, ::ethers::contract::EthCall, @@ -945,14 +927,9 @@ pub mod permissioned_stake_table { Eq, Hash, )] - #[ethcall( - name = "remove", - abi = "remove(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" - )] - pub struct RemoveCall { - pub stakers_to_remove: ::std::vec::Vec, - } - ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] + pub struct RenounceOwnershipCall; + ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` #[derive( Clone, ::ethers::contract::EthCall, @@ -965,9 +942,11 @@ pub mod permissioned_stake_table { Eq, Hash, )] - #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] - pub struct RenounceOwnershipCall; - ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] + pub struct TransferOwnershipCall { + pub new_owner: ::ethers::core::types::Address, + } + ///Container type for all input parameters for the `update` function with signature `update(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[],((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])` and selector `0xa8a0ea5c` #[derive( Clone, ::ethers::contract::EthCall, @@ -980,9 +959,13 @@ pub mod permissioned_stake_table { Eq, Hash, )] - #[ethcall(name = "transferOwnership", abi = "transferOwnership(address)")] - pub struct TransferOwnershipCall { - pub new_owner: ::ethers::core::types::Address, + #[ethcall( + name = "update", + abi = "update(((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[],((uint256,uint256,uint256,uint256),(uint256,uint256),bool)[])" + )] + pub struct UpdateCall { + pub stakers_to_remove: ::std::vec::Vec, + pub new_stakers: ::std::vec::Vec, } ///Container type for all of the contract's call #[derive( @@ -997,12 +980,11 @@ pub mod permissioned_stake_table { )] pub enum PermissionedStakeTableCalls { HashBlsKey(HashBlsKeyCall), - Insert(InsertCall), IsStaker(IsStakerCall), Owner(OwnerCall), - Remove(RemoveCall), RenounceOwnership(RenounceOwnershipCall), TransferOwnership(TransferOwnershipCall), + Update(UpdateCall), } impl ::ethers::core::abi::AbiDecode for PermissionedStakeTableCalls { fn decode( @@ -1012,18 +994,12 @@ pub mod permissioned_stake_table { if let Ok(decoded) = ::decode(data) { return Ok(Self::HashBlsKey(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Insert(decoded)); - } if let Ok(decoded) = ::decode(data) { return Ok(Self::IsStaker(decoded)); } if let Ok(decoded) = ::decode(data) { return Ok(Self::Owner(decoded)); } - if let Ok(decoded) = ::decode(data) { - return Ok(Self::Remove(decoded)); - } if let Ok(decoded) = ::decode(data) { @@ -1034,6 +1010,9 @@ pub mod permissioned_stake_table { { return Ok(Self::TransferOwnership(decoded)); } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Update(decoded)); + } Err(::ethers::core::abi::Error::InvalidData.into()) } } @@ -1041,12 +1020,11 @@ pub mod permissioned_stake_table { fn encode(self) -> Vec { match self { Self::HashBlsKey(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Insert(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::IsStaker(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::Owner(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::Remove(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::RenounceOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::TransferOwnership(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Update(element) => ::ethers::core::abi::AbiEncode::encode(element), } } } @@ -1054,12 +1032,11 @@ pub mod permissioned_stake_table { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::HashBlsKey(element) => ::core::fmt::Display::fmt(element, f), - Self::Insert(element) => ::core::fmt::Display::fmt(element, f), Self::IsStaker(element) => ::core::fmt::Display::fmt(element, f), Self::Owner(element) => ::core::fmt::Display::fmt(element, f), - Self::Remove(element) => ::core::fmt::Display::fmt(element, f), Self::RenounceOwnership(element) => ::core::fmt::Display::fmt(element, f), Self::TransferOwnership(element) => ::core::fmt::Display::fmt(element, f), + Self::Update(element) => ::core::fmt::Display::fmt(element, f), } } } @@ -1068,11 +1045,6 @@ pub mod permissioned_stake_table { Self::HashBlsKey(value) } } - impl ::core::convert::From for PermissionedStakeTableCalls { - fn from(value: InsertCall) -> Self { - Self::Insert(value) - } - } impl ::core::convert::From for PermissionedStakeTableCalls { fn from(value: IsStakerCall) -> Self { Self::IsStaker(value) @@ -1083,11 +1055,6 @@ pub mod permissioned_stake_table { Self::Owner(value) } } - impl ::core::convert::From for PermissionedStakeTableCalls { - fn from(value: RemoveCall) -> Self { - Self::Remove(value) - } - } impl ::core::convert::From for PermissionedStakeTableCalls { fn from(value: RenounceOwnershipCall) -> Self { Self::RenounceOwnership(value) @@ -1098,6 +1065,11 @@ pub mod permissioned_stake_table { Self::TransferOwnership(value) } } + impl ::core::convert::From for PermissionedStakeTableCalls { + fn from(value: UpdateCall) -> Self { + Self::Update(value) + } + } ///Container type for all return fields from the `_hashBlsKey` function with signature `_hashBlsKey((uint256,uint256,uint256,uint256))` and selector `0x9b30a5e6` #[derive( Clone, diff --git a/contracts/src/PermissionedStakeTable.sol b/contracts/src/PermissionedStakeTable.sol index d1f607c2dc..17c1341750 100644 --- a/contracts/src/PermissionedStakeTable.sol +++ b/contracts/src/PermissionedStakeTable.sol @@ -10,8 +10,7 @@ import { EdOnBN254 } from "./libraries/EdOnBn254.sol"; * @dev An stake table mapping with owner-only access control. */ contract PermissionedStakeTable is Ownable { - event Added(NodeInfo[]); - event Removed(NodeInfo[]); + event StakersUpdated(NodeInfo[] removed, NodeInfo[] added); error StakerAlreadyExists(BN254.G2Point); error StakerNotFound(BN254.G2Point); @@ -28,11 +27,24 @@ contract PermissionedStakeTable is Ownable { // State mapping from staker IDs to their staking status mapping(bytes32 nodeID => bool isStaker) private stakers; - constructor(address initialOwner, NodeInfo[] memory initialStakers) Ownable(initialOwner) { + constructor(NodeInfo[] memory initialStakers) Ownable(msg.sender) { insert(initialStakers); } - function insert(NodeInfo[] memory newStakers) public onlyOwner { + // public methods + + function update(NodeInfo[] memory stakersToRemove, NodeInfo[] memory newStakers) + public + onlyOwner + { + remove(stakersToRemove); + insert(newStakers); + emit StakersUpdated(stakersToRemove, newStakers); + } + + // internal methods + + function insert(NodeInfo[] memory newStakers) internal { // TODO: revert if array empty for (uint256 i = 0; i < newStakers.length; i++) { bytes32 stakerID = _hashBlsKey(newStakers[i].blsVK); @@ -41,10 +53,9 @@ contract PermissionedStakeTable is Ownable { } stakers[stakerID] = true; } - emit Added(newStakers); } - function remove(NodeInfo[] memory stakersToRemove) external onlyOwner { + function remove(NodeInfo[] memory stakersToRemove) internal { // TODO: revert if array empty for (uint256 i = 0; i < stakersToRemove.length; i++) { bytes32 stakerID = _hashBlsKey(stakersToRemove[i].blsVK); @@ -53,9 +64,10 @@ contract PermissionedStakeTable is Ownable { } stakers[stakerID] = false; } - emit Removed(stakersToRemove); } + // view methods + function isStaker(BN254.G2Point memory staker) external view returns (bool) { return stakers[_hashBlsKey(staker)]; } diff --git a/contracts/test/PermissionedStakeTable.t.sol b/contracts/test/PermissionedStakeTable.t.sol index 7aaffb7d02..bd5fbb974a 100644 --- a/contracts/test/PermissionedStakeTable.t.sol +++ b/contracts/test/PermissionedStakeTable.t.sol @@ -14,7 +14,7 @@ contract PermissionedStakeTableTest is Test { function setUp() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory initialStakers = nodes(0, 1); - stakeTable = new PermissionedStakeTable(owner, initialStakers); + stakeTable = new PermissionedStakeTable(initialStakers); } // Create `numNodes` node IDs from `start` for testing. @@ -41,11 +41,12 @@ contract PermissionedStakeTableTest is Test { function testInsert() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); vm.expectEmit(); - emit PermissionedStakeTable.Added(stakers); + emit PermissionedStakeTable.StakersUpdated(empty, stakers); - stakeTable.insert(stakers); + stakeTable.update(empty, stakers); assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } @@ -53,11 +54,12 @@ contract PermissionedStakeTableTest is Test { function testInsertMany() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 10); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); vm.expectEmit(); - emit PermissionedStakeTable.Added(stakers); + emit PermissionedStakeTable.StakersUpdated(empty, stakers); - stakeTable.insert(stakers); + stakeTable.update(empty, stakers); assertTrue(stakeTable.isStaker(stakers[0].blsVK)); } @@ -65,7 +67,8 @@ contract PermissionedStakeTableTest is Test { function testInsertRevertsIfStakerExists() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); - stakeTable.insert(stakers); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); + stakeTable.update(empty, stakers); // Try adding the same staker again vm.expectRevert( @@ -74,20 +77,21 @@ contract PermissionedStakeTableTest is Test { ) ); vm.prank(owner); - stakeTable.insert(stakers); + stakeTable.update(empty, stakers); } function testRemove() public { PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); vm.prank(owner); - stakeTable.insert(stakers); + stakeTable.update(empty, stakers); vm.prank(owner); vm.expectEmit(); - emit PermissionedStakeTable.Removed(stakers); + emit PermissionedStakeTable.StakersUpdated(stakers, empty); - stakeTable.remove(stakers); + stakeTable.update(stakers, empty); assertFalse(stakeTable.isStaker(stakers[0].blsVK)); } @@ -95,11 +99,12 @@ contract PermissionedStakeTableTest is Test { function testRemoveRevertsIfStakerNotFound() public { vm.prank(owner); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); vm.expectRevert( abi.encodeWithSelector(PermissionedStakeTable.StakerNotFound.selector, stakers[0].blsVK) ); // Attempt to remove a non-existent staker - stakeTable.remove(stakers); + stakeTable.update(stakers, empty); } function testNonOwnerCannotInsert() public { @@ -108,7 +113,8 @@ contract PermissionedStakeTableTest is Test { abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); - stakeTable.insert(stakers); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); + stakeTable.update(empty, stakers); } function testNonOwnerCannotRemove() public { @@ -117,6 +123,7 @@ contract PermissionedStakeTableTest is Test { abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(2)) ); PermissionedStakeTable.NodeInfo[] memory stakers = nodes(1, 1); - stakeTable.remove(stakers); + PermissionedStakeTable.NodeInfo[] memory empty = nodes(1, 0); + stakeTable.update(stakers, empty); } } From 927fef516d337317f2a310aa5e8c2980fbc92368 Mon Sep 17 00:00:00 2001 From: tbro Date: Thu, 5 Dec 2024 17:17:52 -0300 Subject: [PATCH 20/58] boilerplate Branched from #2325. Adds most everything from #2237. Main blocker now is to iron out `ChainConfig` versions. Then we can get into the actual stake table retrieval logic. --- sequencer/src/context.rs | 1 - sequencer/src/lib.rs | 15 +- types/src/v0/impls/instance_state.rs | 6 +- types/src/v0/impls/l1.rs | 52 ++++- types/src/v0/impls/mod.rs | 8 +- types/src/v0/impls/stake_table.rs | 324 +++++++++++++++++++++++++++ types/src/v0/impls/state.rs | 3 +- types/src/v0/v0_3/chain_config.rs | 175 +++++++++++++++ types/src/v0/v0_3/mod.rs | 2 + 9 files changed, 571 insertions(+), 15 deletions(-) create mode 100644 types/src/v0/impls/stake_table.rs create mode 100644 types/src/v0/v0_3/chain_config.rs diff --git a/sequencer/src/context.rs b/sequencer/src/context.rs index 06e27e3b1c..38077308e5 100644 --- a/sequencer/src/context.rs +++ b/sequencer/src/context.rs @@ -16,7 +16,6 @@ use futures::{ stream::{Stream, StreamExt}, }; use hotshot::{ - traits::election::static_committee::StaticCommittee, types::{Event, EventType, SystemContextHandle}, MarketplaceConfig, SystemContext, }; diff --git a/sequencer/src/lib.rs b/sequencer/src/lib.rs index bba6356ad3..cabc4418d3 100644 --- a/sequencer/src/lib.rs +++ b/sequencer/src/lib.rs @@ -20,7 +20,6 @@ use espresso_types::{ }; use futures::FutureExt; use genesis::L1Finalized; -use hotshot::traits::election::static_committee::StaticCommittee; use hotshot_types::traits::election::Membership; use std::sync::Arc; // Should move `STAKE_TABLE_CAPACITY` in the sequencer repo when we have variate stake table support @@ -386,12 +385,6 @@ pub async fn init_node( topics }; - // Create the HotShot membership - let membership = StaticCommittee::new( - network_config.config.known_nodes_with_stake.clone(), - network_config.config.known_nodes_with_stake.clone(), - ); - // Initialize the push CDN network (and perform the initial connection) let cdn_network = PushCdnNetwork::new( network_params.cdn_endpoint, @@ -517,6 +510,13 @@ pub async fn init_node( current_version: V::Base::VERSION, }; + // Create the HotShot membership + let membership = StaticCommittee::new_stake( + network_config.config.known_nodes_with_stake.clone(), + network_config.config.known_nodes_with_stake.clone(), + &instance_state, + ); + let mut ctx = SequencerContext::init( network_config, validator_config, @@ -954,6 +954,7 @@ pub mod testing { .with_upgrades(upgrades); // Create the HotShot membership + // TODO use our own implementation and pull from contract let membership = StaticCommittee::new( config.known_nodes_with_stake.clone(), config.known_nodes_with_stake.clone(), diff --git a/types/src/v0/impls/instance_state.rs b/types/src/v0/impls/instance_state.rs index 71a387bbcb..4e11787f00 100644 --- a/types/src/v0/impls/instance_state.rs +++ b/types/src/v0/impls/instance_state.rs @@ -1,5 +1,5 @@ use crate::v0::{ - traits::StateCatchup, v0_99::ChainConfig, GenesisHeader, L1BlockInfo, L1Client, PubKey, + traits::StateCatchup, v0_3::ChainConfig, GenesisHeader, L1BlockInfo, L1Client, PubKey, Timestamp, Upgrade, UpgradeMode, }; use hotshot_types::traits::states::InstanceState; @@ -17,7 +17,7 @@ use super::state::ValidatedState; #[derive(derive_more::Debug, Clone)] pub struct NodeState { pub node_id: u64, - pub chain_config: crate::v0_99::ChainConfig, + pub chain_config: crate::v0_3::ChainConfig, pub l1_client: L1Client, #[debug("{}", peers.name())] pub peers: Arc, @@ -46,7 +46,7 @@ pub struct NodeState { impl NodeState { pub fn new( node_id: u64, - chain_config: ChainConfig, + chain_config: crate::v0_3::ChainConfig, l1_client: L1Client, catchup: impl StateCatchup + 'static, current_version: Version, diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index aac8404d6b..238f1a9307 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -19,7 +19,11 @@ use futures::{ future::Future, stream::{self, StreamExt}, }; -use hotshot_types::traits::metrics::Metrics; +use hotshot::types::SignatureKey; +use hotshot_types::{ + stake_table::StakeTableEntry, + traits::{metrics::Metrics, node_implementation::NodeType}, +}; use lru::LruCache; use serde::{de::DeserializeOwned, Serialize}; use tokio::{ @@ -779,6 +783,17 @@ impl L1Client { }); events.flatten().map(FeeInfo::from).collect().await } + + /// Get `StakeTable` at block height. + pub async fn get_stake_table( + &self, + _block: u64, + _address: Address, + ) -> Vec<::StakeTableEntry> { + // TODO we either need address from configuration or contract-bindings. + // TODO epoch size may need to be passed in as well + unimplemented!(); + } } impl L1State { @@ -1246,4 +1261,39 @@ mod test { }; tracing::info!(?final_state, "state updated"); } + + #[tokio::test] + async fn test_get_stake_table() -> anyhow::Result<()> { + setup_test(); + + // how many deposits will we make + let deposits = 5; + let deploy_txn_count = 2; + + let anvil = Anvil::new().spawn(); + let wallet_address = anvil.addresses().first().cloned().unwrap(); + let l1_client = L1Client::new(anvil.endpoint().parse().unwrap()); + let wallet: LocalWallet = anvil.keys()[0].clone().into(); + + // In order to deposit we need a provider that can sign. + let provider = + Provider::::try_from(anvil.endpoint())?.interval(Duration::from_millis(10u64)); + let client = + SignerMiddleware::new(provider.clone(), wallet.with_chain_id(anvil.chain_id())); + let client = Arc::new(client); + + // Initialize a contract with some deposits + + // deploy the fee contract + let stake_table_contract = + contract_bindings::permissioned_stake_table::PermissionedStakeTable::deploy( + client.clone(), + (), + ) + .unwrap() + .send() + .await?; + + Ok(()) + } } diff --git a/types/src/v0/impls/mod.rs b/types/src/v0/impls/mod.rs index eb72ebb143..29fb39fb61 100644 --- a/types/src/v0/impls/mod.rs +++ b/types/src/v0/impls/mod.rs @@ -8,14 +8,18 @@ mod header; mod instance_state; mod l1; mod solver; +mod stake_table; mod state; mod transaction; pub use auction::SolverAuctionResultsProvider; pub use fee_info::{retain_accounts, FeeError}; pub use instance_state::NodeState; -pub use state::ProposalValidationError; -pub use state::{get_l1_deposits, BuilderValidationError, StateValidationError, ValidatedState}; +pub use stake_table::StaticCommittee; +pub use state::{ + get_l1_deposits, BuilderValidationError, ProposalValidationError, StateValidationError, + ValidatedState, +}; #[cfg(any(test, feature = "testing"))] pub use instance_state::mock; diff --git a/types/src/v0/impls/stake_table.rs b/types/src/v0/impls/stake_table.rs new file mode 100644 index 0000000000..16555fa665 --- /dev/null +++ b/types/src/v0/impls/stake_table.rs @@ -0,0 +1,324 @@ +use super::{L1Client, NodeState}; +use ethers::{abi::Address, types::U256}; +use hotshot::types::SignatureKey; +use hotshot_types::{ + traits::{ + election::Membership, node_implementation::NodeType, signature_key::StakeTableEntryType, + }, + PeerConfig, +}; +use std::{cmp::max, collections::BTreeMap, num::NonZeroU64, str::FromStr}; +use thiserror::Error; +use url::Url; + +#[derive(Clone, Debug)] +pub struct StaticCommittee { + /// The nodes eligible for leadership. + /// NOTE: This is currently a hack because the DA leader needs to be the quorum + /// leader but without voting rights. + eligible_leaders: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake + stake_table: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake + da_stake_table: Vec<::StakeTableEntry>, + + /// The nodes on the committee and their stake, indexed by public key + indexed_stake_table: + BTreeMap::StakeTableEntry>, + + /// The nodes on the committee and their stake, indexed by public key + indexed_da_stake_table: + BTreeMap::StakeTableEntry>, + + /// Number of blocks in an epoch + epoch_size: u64, + + /// Address of StakeTable contract (proxy address) + contract_address: Option
, + + /// L1 provider + provider: L1Client, +} + +impl StaticCommittee { + /// Updates `Self.stake_table` with stake_table for + /// `Self.contract_address` at `l1_block_height`. This is intended + /// to be called before calling `self.stake()` so that + /// `Self.stake_table` only needs to be updated once in a given + /// life-cycle but may be read from many times. + async fn update_stake_table(&mut self, l1_block_height: u64) { + let table: Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> = self + .provider + .get_stake_table::(l1_block_height, self.contract_address.unwrap()) + .await; + self.stake_table = table; + } + // We need a constructor to match our concrete type. + pub fn new_stake( + // TODO remove `new` from trait and rename this to `new`. + // https://github.com/EspressoSystems/HotShot/commit/fcb7d54a4443e29d643b3bbc53761856aef4de8b + committee_members: Vec::SignatureKey>>, + da_members: Vec::SignatureKey>>, + instance_state: &NodeState, + epoch_size: u64, + ) -> Self { + // For each eligible leader, get the stake table entry + let eligible_leaders: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let members: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let da_members: Vec<::StakeTableEntry> = da_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // Index the stake table by public key + let indexed_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + + // Index the stake table by public key + let indexed_da_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = da_members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + + Self { + eligible_leaders, + stake_table: members, + da_stake_table: da_members, + indexed_stake_table, + indexed_da_stake_table, + epoch_size, + provider: instance_state.l1_client.clone(), + contract_address: instance_state.chain_config.stake_table_contract, + } + } +} + +#[derive(Error, Debug)] +#[error("Could not lookup leader")] // TODO error variants? message? +pub struct LeaderLookupError; + +impl Membership for StaticCommittee { + type Error = LeaderLookupError; + + /// DO NOT USE. Dummy constructor to comply w/ trait. + fn new( + // TODO remove `new` from trait and remove this fn as well. + // https://github.com/EspressoSystems/HotShot/commit/fcb7d54a4443e29d643b3bbc53761856aef4de8b + committee_members: Vec::SignatureKey>>, + da_members: Vec::SignatureKey>>, + ) -> Self { + // For each eligible leader, get the stake table entry + let eligible_leaders: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let members: Vec<::StakeTableEntry> = + committee_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // For each member, get the stake table entry + let da_members: Vec<::StakeTableEntry> = da_members + .iter() + .map(|member| member.stake_table_entry.clone()) + .filter(|entry| entry.stake() > U256::zero()) + .collect(); + + // Index the stake table by public key + let indexed_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + + // Index the stake table by public key + let indexed_da_stake_table: BTreeMap< + TYPES::SignatureKey, + ::StakeTableEntry, + > = da_members + .iter() + .map(|entry| (TYPES::SignatureKey::public_key(entry), entry.clone())) + .collect(); + + Self { + eligible_leaders, + stake_table: members, + da_stake_table: da_members, + indexed_stake_table, + indexed_da_stake_table, + epoch_size: 12, // TODO get the real number from config (I think) + provider: L1Client::http(Url::from_str("http:://ab.b").unwrap()), + contract_address: None, + } + } + /// Get the stake table for the current view + fn stake_table( + &self, + _epoch: ::Epoch, + ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { + self.stake_table.clone() + } + /// Get the stake table for the current view + fn da_stake_table( + &self, + _epoch: ::Epoch, + ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { + self.da_stake_table.clone() + } + + /// Get all members of the committee for the current view + fn committee_members( + &self, + _view_number: ::View, + _epoch: ::Epoch, + ) -> std::collections::BTreeSet<::SignatureKey> { + self.stake_table + .iter() + .map(TYPES::SignatureKey::public_key) + .collect() + } + + /// Get all members of the committee for the current view + fn da_committee_members( + &self, + _view_number: ::View, + _epoch: ::Epoch, + ) -> std::collections::BTreeSet<::SignatureKey> { + self.da_stake_table + .iter() + .map(TYPES::SignatureKey::public_key) + .collect() + } + + /// Get all eligible leaders of the committee for the current view + fn committee_leaders( + &self, + _view_number: ::View, + _epoch: ::Epoch, + ) -> std::collections::BTreeSet<::SignatureKey> { + self.eligible_leaders + .iter() + .map(TYPES::SignatureKey::public_key) + .collect() + } + + /// Get the stake table entry for a public key + fn stake( + &self, + pub_key: &::SignatureKey, + _epoch: ::Epoch, + ) -> Option<::StakeTableEntry> { + // Only return the stake if it is above zero + self.indexed_stake_table.get(pub_key).cloned() + } + + /// Get the DA stake table entry for a public key + fn da_stake( + &self, + pub_key: &::SignatureKey, + _epoch: ::Epoch, + ) -> Option<::StakeTableEntry> { + // Only return the stake if it is above zero + self.indexed_da_stake_table.get(pub_key).cloned() + } + + /// Check if a node has stake in the committee + fn has_stake( + &self, + pub_key: &::SignatureKey, + _epoch: ::Epoch, + ) -> bool { + self.indexed_stake_table + .get(pub_key) + .is_some_and(|x| x.stake() > U256::zero()) + } + + /// Check if a node has stake in the committee + fn has_da_stake( + &self, + pub_key: &::SignatureKey, + _epoch: ::Epoch, + ) -> bool { + self.indexed_da_stake_table + .get(pub_key) + .is_some_and(|x| x.stake() > U256::zero()) + } + + /// Index the vector of public keys with the current view number + fn lookup_leader( + &self, + view_number: TYPES::View, + _epoch: ::Epoch, + ) -> Result { + let index = *view_number as usize % self.eligible_leaders.len(); + let res = self.eligible_leaders[index].clone(); + Ok(TYPES::SignatureKey::public_key(&res)) + } + + /// Get the total number of nodes in the committee + fn total_nodes(&self, _epoch: ::Epoch) -> usize { + self.stake_table.len() + } + + /// Get the total number of DA nodes in the committee + fn da_total_nodes(&self, _epoch: ::Epoch) -> usize { + self.da_stake_table.len() + } + + /// Get the voting success threshold for the committee + fn success_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { + NonZeroU64::new(((self.stake_table.len() as u64 * 2) / 3) + 1).unwrap() + } + + /// Get the voting success threshold for the committee + fn da_success_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { + NonZeroU64::new(((self.da_stake_table.len() as u64 * 2) / 3) + 1).unwrap() + } + + /// Get the voting failure threshold for the committee + fn failure_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { + NonZeroU64::new(((self.stake_table.len() as u64) / 3) + 1).unwrap() + } + + /// Get the voting upgrade threshold for the committee + fn upgrade_threshold(&self, _epoch: ::Epoch) -> NonZeroU64 { + NonZeroU64::new(max( + (self.stake_table.len() as u64 * 9) / 10, + ((self.stake_table.len() as u64 * 2) / 3) + 1, + )) + .unwrap() + } +} diff --git a/types/src/v0/impls/state.rs b/types/src/v0/impls/state.rs index 85fbb06146..71f56626be 100644 --- a/types/src/v0/impls/state.rs +++ b/types/src/v0/impls/state.rs @@ -31,7 +31,8 @@ use super::{ }; use crate::{ traits::StateCatchup, - v0_99::{ChainConfig, FullNetworkTx, IterableFeeInfo, ResolvableChainConfig}, + v0_3::{ChainConfig, ResolvableChainConfig}, + v0_99::{FullNetworkTx, IterableFeeInfo}, BlockMerkleTree, Delta, FeeAccount, FeeAmount, FeeInfo, FeeMerkleTree, Header, Leaf2, NsTableValidationError, PayloadByteLen, SeqTypes, UpgradeType, BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_HEIGHT, diff --git a/types/src/v0/v0_3/chain_config.rs b/types/src/v0/v0_3/chain_config.rs new file mode 100644 index 0000000000..3e26df4deb --- /dev/null +++ b/types/src/v0/v0_3/chain_config.rs @@ -0,0 +1,175 @@ +use crate::{v0_1, BlockSize, ChainId, FeeAccount, FeeAmount}; +use committable::{Commitment, Committable}; +use ethers::types::{Address, U256}; +use itertools::Either; +use serde::{Deserialize, Serialize}; + +/// Global variables for an Espresso blockchain. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ChainConfig { + /// Espresso chain ID + pub chain_id: ChainId, + + /// Maximum size in bytes of a block + pub max_block_size: BlockSize, + + /// Minimum fee in WEI per byte of payload + pub base_fee: FeeAmount, + + /// Fee contract address on L1. + /// + /// This is optional so that fees can easily be toggled on/off, with no need to deploy a + /// contract when they are off. In a future release, after fees are switched on and thoroughly + /// tested, this may be made mandatory. + pub fee_contract: Option
, + + /// Account that receives sequencing fees. + /// + /// This account in the Espresso fee ledger will always receive every fee paid in Espresso, + /// regardless of whether or not their is a `fee_contract` deployed. Once deployed, the fee + /// contract can decide what to do with tokens locked in this account in Espresso. + pub fee_recipient: FeeAccount, + + /// `StakeTable `(proxy) contract address on L1. + /// + /// This is optional so that stake can easily be toggled on/off, with no need to deploy a + /// contract when they are off. In a future release, after PoS is switched on and thoroughly + /// tested, this may be made mandatory. + pub stake_table_contract: Option
, +} + +#[derive(Clone, Debug, Copy, PartialEq, Deserialize, Serialize, Eq, Hash)] +pub struct ResolvableChainConfig { + pub(crate) chain_config: Either>, +} + +impl Committable for ChainConfig { + fn tag() -> String { + "CHAIN_CONFIG".to_string() + } + + fn commit(&self) -> Commitment { + let comm = committable::RawCommitmentBuilder::new(&Self::tag()) + .fixed_size_field("chain_id", &self.chain_id.to_fixed_bytes()) + .u64_field("max_block_size", *self.max_block_size) + .fixed_size_field("base_fee", &self.base_fee.to_fixed_bytes()) + .fixed_size_field("fee_recipient", &self.fee_recipient.to_fixed_bytes()); + let comm = if let Some(addr) = self.fee_contract { + comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0) + } else { + comm.u64_field("fee_contract", 0) + }; + // With `ChainConfig` upgrades we want commitments w/out + // fields added >= v0_3 to have the same commitment as <= v0_3 + // commitment. Therefore `None` values are simply ignored. + let comm = if let Some(addr) = self.stake_table_contract { + comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0) + } else { + comm + }; + + comm.finalize() + } +} + +impl ResolvableChainConfig { + pub fn commit(&self) -> Commitment { + match self.chain_config { + Either::Left(config) => config.commit(), + Either::Right(commitment) => commitment, + } + } + pub fn resolve(self) -> Option { + match self.chain_config { + Either::Left(config) => Some(config), + Either::Right(_) => None, + } + } +} + +impl From> for ResolvableChainConfig { + fn from(value: Commitment) -> Self { + Self { + chain_config: Either::Right(value), + } + } +} + +impl From for ResolvableChainConfig { + fn from(value: ChainConfig) -> Self { + Self { + chain_config: Either::Left(value), + } + } +} + +impl From<&v0_1::ResolvableChainConfig> for ResolvableChainConfig { + fn from( + &v0_1::ResolvableChainConfig { chain_config }: &v0_1::ResolvableChainConfig, + ) -> ResolvableChainConfig { + match chain_config { + Either::Left(chain_config) => ResolvableChainConfig { + chain_config: Either::Left(ChainConfig::from(chain_config)), + }, + Either::Right(c) => ResolvableChainConfig { + chain_config: Either::Right(Commitment::from_raw(*c.as_ref())), + }, + } + } +} + +impl From for ChainConfig { + fn from(chain_config: v0_1::ChainConfig) -> ChainConfig { + let v0_1::ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + .. + } = chain_config; + + ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + stake_table_contract: None, + } + } +} + +impl From for v0_1::ChainConfig { + fn from(chain_config: ChainConfig) -> v0_1::ChainConfig { + let ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + .. + } = chain_config; + + v0_1::ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + } + } +} + +impl Default for ChainConfig { + fn default() -> Self { + Self { + chain_id: U256::from(35353).into(), // arbitrarily chosen chain ID + max_block_size: 30720.into(), + base_fee: 0.into(), + fee_contract: None, + fee_recipient: Default::default(), + stake_table_contract: None, + } + } +} diff --git a/types/src/v0/v0_3/mod.rs b/types/src/v0/v0_3/mod.rs index 1a2e7efc9b..dac8e5270f 100644 --- a/types/src/v0/v0_3/mod.rs +++ b/types/src/v0/v0_3/mod.rs @@ -19,6 +19,8 @@ pub(crate) use super::v0_1::{ pub const VERSION: Version = Version { major: 0, minor: 3 }; +mod chain_config; mod stake_table; +pub use chain_config::*; pub use stake_table::CombinedStakeTable; From 271bd0eb7731a4e3950f05825e0a2b28aa05cebb Mon Sep 17 00:00:00 2001 From: tbro Date: Thu, 5 Dec 2024 17:38:34 -0300 Subject: [PATCH 21/58] add TODO --- types/src/v0/impls/stake_table.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/types/src/v0/impls/stake_table.rs b/types/src/v0/impls/stake_table.rs index 16555fa665..93b50c545c 100644 --- a/types/src/v0/impls/stake_table.rs +++ b/types/src/v0/impls/stake_table.rs @@ -19,9 +19,11 @@ pub struct StaticCommittee { eligible_leaders: Vec<::StakeTableEntry>, /// The nodes on the committee and their stake + // TODO I feel like this should be `HashSet` instead of `Vec` stake_table: Vec<::StakeTableEntry>, /// The nodes on the committee and their stake + // TODO I feel like this should be `HashSet` instead of `Vec` da_stake_table: Vec<::StakeTableEntry>, /// The nodes on the committee and their stake, indexed by public key From 27a8e7cffddc7fcc41819492692e4d549c84fd99 Mon Sep 17 00:00:00 2001 From: tbro Date: Thu, 5 Dec 2024 17:50:27 -0300 Subject: [PATCH 22/58] use `HashSet` --- types/src/v0/impls/stake_table.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/types/src/v0/impls/stake_table.rs b/types/src/v0/impls/stake_table.rs index 93b50c545c..39521c9537 100644 --- a/types/src/v0/impls/stake_table.rs +++ b/types/src/v0/impls/stake_table.rs @@ -7,7 +7,12 @@ use hotshot_types::{ }, PeerConfig, }; -use std::{cmp::max, collections::BTreeMap, num::NonZeroU64, str::FromStr}; +use std::{ + cmp::max, + collections::{BTreeMap, HashSet}, + num::NonZeroU64, + str::FromStr, +}; use thiserror::Error; use url::Url; @@ -20,11 +25,11 @@ pub struct StaticCommittee { /// The nodes on the committee and their stake // TODO I feel like this should be `HashSet` instead of `Vec` - stake_table: Vec<::StakeTableEntry>, + stake_table: HashSet<::StakeTableEntry>, /// The nodes on the committee and their stake // TODO I feel like this should be `HashSet` instead of `Vec` - da_stake_table: Vec<::StakeTableEntry>, + da_stake_table: HashSet<::StakeTableEntry>, /// The nodes on the committee and their stake, indexed by public key indexed_stake_table: @@ -55,7 +60,7 @@ impl StaticCommittee { .provider .get_stake_table::(l1_block_height, self.contract_address.unwrap()) .await; - self.stake_table = table; + self.stake_table = HashSet::from_iter(table); } // We need a constructor to match our concrete type. pub fn new_stake( @@ -109,8 +114,8 @@ impl StaticCommittee { Self { eligible_leaders, - stake_table: members, - da_stake_table: da_members, + stake_table: HashSet::from_iter(members), + da_stake_table: HashSet::from_iter(da_members), indexed_stake_table, indexed_da_stake_table, epoch_size, @@ -127,7 +132,7 @@ pub struct LeaderLookupError; impl Membership for StaticCommittee { type Error = LeaderLookupError; - /// DO NOT USE. Dummy constructor to comply w/ trait. + // DO NOT USE. Dummy constructor to comply w/ trait. fn new( // TODO remove `new` from trait and remove this fn as well. // https://github.com/EspressoSystems/HotShot/commit/fcb7d54a4443e29d643b3bbc53761856aef4de8b @@ -177,8 +182,8 @@ impl Membership for StaticCommittee { Self { eligible_leaders, - stake_table: members, - da_stake_table: da_members, + stake_table: HashSet::from_iter(members), + da_stake_table: HashSet::from_iter(da_members), indexed_stake_table, indexed_da_stake_table, epoch_size: 12, // TODO get the real number from config (I think) @@ -191,14 +196,14 @@ impl Membership for StaticCommittee { &self, _epoch: ::Epoch, ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { - self.stake_table.clone() + self.stake_table.clone().into_iter().collect() } /// Get the stake table for the current view fn da_stake_table( &self, _epoch: ::Epoch, ) -> Vec<<::SignatureKey as SignatureKey>::StakeTableEntry> { - self.da_stake_table.clone() + self.da_stake_table.clone().into_iter().collect() } /// Get all members of the committee for the current view From 45007636fe6c55058e2616530d3775f2004cc022 Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 12:35:55 -0300 Subject: [PATCH 23/58] some cleanup --- types/src/v0/impls/l1.rs | 4 ++-- types/src/v0/impls/stake_table.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index 238f1a9307..8aba381a90 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -1263,7 +1263,7 @@ mod test { } #[tokio::test] - async fn test_get_stake_table() -> anyhow::Result<()> { + async fn test_fetch_stake_table() -> anyhow::Result<()> { setup_test(); // how many deposits will we make @@ -1284,7 +1284,7 @@ mod test { // Initialize a contract with some deposits - // deploy the fee contract + // deploy the stake_table contract let stake_table_contract = contract_bindings::permissioned_stake_table::PermissionedStakeTable::deploy( client.clone(), diff --git a/types/src/v0/impls/stake_table.rs b/types/src/v0/impls/stake_table.rs index 39521c9537..b9f32f3724 100644 --- a/types/src/v0/impls/stake_table.rs +++ b/types/src/v0/impls/stake_table.rs @@ -24,11 +24,9 @@ pub struct StaticCommittee { eligible_leaders: Vec<::StakeTableEntry>, /// The nodes on the committee and their stake - // TODO I feel like this should be `HashSet` instead of `Vec` stake_table: HashSet<::StakeTableEntry>, /// The nodes on the committee and their stake - // TODO I feel like this should be `HashSet` instead of `Vec` da_stake_table: HashSet<::StakeTableEntry>, /// The nodes on the committee and their stake, indexed by public key From 44cbe8760e9085e2f25e432749ca4b240bd54e9e Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 14:10:54 -0300 Subject: [PATCH 24/58] Avoid re-exporting v1 chain config Also fix serialization --- types/src/v0/impls/chain_config.rs | 6 ++---- types/src/v0/v0_3/chain_config.rs | 3 ++- types/src/v0/v0_3/mod.rs | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/types/src/v0/impls/chain_config.rs b/types/src/v0/impls/chain_config.rs index 502f95a3d9..264c3361a1 100644 --- a/types/src/v0/impls/chain_config.rs +++ b/types/src/v0/impls/chain_config.rs @@ -1,13 +1,11 @@ +use super::parse_size; +use crate::{BlockSize, ChainId}; use ethers::types::U256; use sequencer_utils::{ impl_serde_from_string_or_integer, impl_to_fixed_bytes, ser::FromStringOrInteger, }; use std::str::FromStr; -use crate::{BlockSize, ChainId}; - -use super::parse_size; - impl_serde_from_string_or_integer!(ChainId); impl_to_fixed_bytes!(ChainId, U256); diff --git a/types/src/v0/v0_3/chain_config.rs b/types/src/v0/v0_3/chain_config.rs index 3e26df4deb..c00ec63c1b 100644 --- a/types/src/v0/v0_3/chain_config.rs +++ b/types/src/v0/v0_3/chain_config.rs @@ -63,7 +63,8 @@ impl Committable for ChainConfig { // fields added >= v0_3 to have the same commitment as <= v0_3 // commitment. Therefore `None` values are simply ignored. let comm = if let Some(addr) = self.stake_table_contract { - comm.u64_field("fee_contract", 1).fixed_size_bytes(&addr.0) + comm.u64_field("stake_table_contract", 1) + .fixed_size_bytes(&addr.0) } else { comm }; diff --git a/types/src/v0/v0_3/mod.rs b/types/src/v0/v0_3/mod.rs index dac8e5270f..cadf621436 100644 --- a/types/src/v0/v0_3/mod.rs +++ b/types/src/v0/v0_3/mod.rs @@ -2,16 +2,16 @@ use vbs::version::Version; // Re-export types which haven't changed since the last minor version. pub use super::v0_1::{ - AccountQueryData, BlockMerkleCommitment, BlockMerkleTree, BlockSize, BuilderSignature, - ChainConfig, ChainId, Delta, FeeAccount, FeeAccountProof, FeeAmount, FeeInfo, - FeeMerkleCommitment, FeeMerkleProof, FeeMerkleTree, Header, Index, Iter, L1BlockInfo, L1Client, - L1ClientOptions, L1Snapshot, NamespaceId, NsIndex, NsIter, NsPayload, NsPayloadBuilder, - NsPayloadByteLen, NsPayloadOwned, NsPayloadRange, NsProof, NsTable, NsTableBuilder, - NsTableValidationError, NumNss, NumTxs, NumTxsRange, NumTxsUnchecked, Payload, PayloadByteLen, - ResolvableChainConfig, TimeBasedUpgrade, Transaction, TxIndex, TxIter, TxPayload, - TxPayloadRange, TxProof, TxTableEntries, TxTableEntriesRange, Upgrade, UpgradeMode, - UpgradeType, ViewBasedUpgrade, BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_HEIGHT, - NS_ID_BYTE_LEN, NS_OFFSET_BYTE_LEN, NUM_NSS_BYTE_LEN, NUM_TXS_BYTE_LEN, TX_OFFSET_BYTE_LEN, + AccountQueryData, BlockMerkleCommitment, BlockMerkleTree, BlockSize, BuilderSignature, ChainId, + Delta, FeeAccount, FeeAccountProof, FeeAmount, FeeInfo, FeeMerkleCommitment, FeeMerkleProof, + FeeMerkleTree, Header, Index, Iter, L1BlockInfo, L1Client, L1ClientOptions, L1Snapshot, + NamespaceId, NsIndex, NsIter, NsPayload, NsPayloadBuilder, NsPayloadByteLen, NsPayloadOwned, + NsPayloadRange, NsProof, NsTable, NsTableBuilder, NsTableValidationError, NumNss, NumTxs, + NumTxsRange, NumTxsUnchecked, Payload, PayloadByteLen, ResolvableChainConfig, TimeBasedUpgrade, + Transaction, TxIndex, TxIter, TxPayload, TxPayloadRange, TxProof, TxTableEntries, + TxTableEntriesRange, Upgrade, UpgradeMode, UpgradeType, ViewBasedUpgrade, + BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_HEIGHT, NS_ID_BYTE_LEN, NS_OFFSET_BYTE_LEN, + NUM_NSS_BYTE_LEN, NUM_TXS_BYTE_LEN, TX_OFFSET_BYTE_LEN, }; pub(crate) use super::v0_1::{ L1ClientMetrics, L1Event, L1ReconnectTask, L1State, L1UpdateTask, RpcClient, From b108074584e2cac10b196462e471388b8e46a96c Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 14:11:43 -0300 Subject: [PATCH 25/58] add stake_table_address to v0_99 `ChainConfig` --- types/src/v0/v0_99/chain_config.rs | 42 +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/types/src/v0/v0_99/chain_config.rs b/types/src/v0/v0_99/chain_config.rs index 61cf46c36a..420580d7af 100644 --- a/types/src/v0/v0_99/chain_config.rs +++ b/types/src/v0/v0_99/chain_config.rs @@ -1,4 +1,4 @@ -use crate::{v0_1, BlockSize, ChainId, FeeAccount, FeeAmount}; +use crate::{v0_1, v0_3, BlockSize, ChainId, FeeAccount, FeeAmount}; use committable::{Commitment, Committable}; use ethers::types::{Address, U256}; use itertools::Either; @@ -30,6 +30,13 @@ pub struct ChainConfig { /// contract can decide what to do with tokens locked in this account in Espresso. pub fee_recipient: FeeAccount, + /// `StakeTable `(proxy) contract address on L1. + /// + /// This is optional so that stake can easily be toggled on/off, with no need to deploy a + /// contract when they are off. In a future release, after PoS is switched on and thoroughly + /// tested, this may be made mandatory. + pub stake_table_contract: Option
, + /// Account that receives sequencing bids. pub bid_recipient: Option, } @@ -57,6 +64,13 @@ impl Committable for ChainConfig { comm.u64_field("fee_contract", 0) }; + let comm = if let Some(addr) = self.stake_table_contract { + comm.u64_field("stake_table_contract", 1) + .fixed_size_bytes(&addr.0) + } else { + comm + }; + // With `ChainConfig` upgrades we want commitments w/out // fields added >= v0_99 to have the same commitment as <= v0_99 // commitment. Therefore `None` values are simply ignored. @@ -133,6 +147,31 @@ impl From for ChainConfig { base_fee, fee_contract, fee_recipient, + stake_table_contract: None, + bid_recipient: None, + } + } +} + +impl From for ChainConfig { + fn from(chain_config: v0_3::ChainConfig) -> ChainConfig { + let v0_3::ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + stake_table_contract, + .. + } = chain_config; + + ChainConfig { + chain_id, + max_block_size, + base_fee, + fee_contract, + fee_recipient, + stake_table_contract, bid_recipient: None, } } @@ -167,6 +206,7 @@ impl Default for ChainConfig { base_fee: 0.into(), fee_contract: None, fee_recipient: Default::default(), + stake_table_contract: None, bid_recipient: None, } } From dbaca7c08651573a623b740e1805c15c35f54b49 Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 14:55:28 -0300 Subject: [PATCH 26/58] export local `StaticCommittee` and move versions back --- types/src/v0/impls/instance_state.rs | 6 +++--- types/src/v0/impls/state.rs | 3 +-- types/src/v0/mod.rs | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/types/src/v0/impls/instance_state.rs b/types/src/v0/impls/instance_state.rs index 4e11787f00..71a387bbcb 100644 --- a/types/src/v0/impls/instance_state.rs +++ b/types/src/v0/impls/instance_state.rs @@ -1,5 +1,5 @@ use crate::v0::{ - traits::StateCatchup, v0_3::ChainConfig, GenesisHeader, L1BlockInfo, L1Client, PubKey, + traits::StateCatchup, v0_99::ChainConfig, GenesisHeader, L1BlockInfo, L1Client, PubKey, Timestamp, Upgrade, UpgradeMode, }; use hotshot_types::traits::states::InstanceState; @@ -17,7 +17,7 @@ use super::state::ValidatedState; #[derive(derive_more::Debug, Clone)] pub struct NodeState { pub node_id: u64, - pub chain_config: crate::v0_3::ChainConfig, + pub chain_config: crate::v0_99::ChainConfig, pub l1_client: L1Client, #[debug("{}", peers.name())] pub peers: Arc, @@ -46,7 +46,7 @@ pub struct NodeState { impl NodeState { pub fn new( node_id: u64, - chain_config: crate::v0_3::ChainConfig, + chain_config: ChainConfig, l1_client: L1Client, catchup: impl StateCatchup + 'static, current_version: Version, diff --git a/types/src/v0/impls/state.rs b/types/src/v0/impls/state.rs index 71f56626be..85fbb06146 100644 --- a/types/src/v0/impls/state.rs +++ b/types/src/v0/impls/state.rs @@ -31,8 +31,7 @@ use super::{ }; use crate::{ traits::StateCatchup, - v0_3::{ChainConfig, ResolvableChainConfig}, - v0_99::{FullNetworkTx, IterableFeeInfo}, + v0_99::{ChainConfig, FullNetworkTx, IterableFeeInfo, ResolvableChainConfig}, BlockMerkleTree, Delta, FeeAccount, FeeAmount, FeeInfo, FeeMerkleTree, Header, Leaf2, NsTableValidationError, PayloadByteLen, SeqTypes, UpgradeType, BLOCK_MERKLE_TREE_HEIGHT, FEE_MERKLE_TREE_HEIGHT, diff --git a/types/src/v0/mod.rs b/types/src/v0/mod.rs index bc588a3649..d87f1b2661 100644 --- a/types/src/v0/mod.rs +++ b/types/src/v0/mod.rs @@ -1,4 +1,3 @@ -use hotshot::traits::election::static_committee::StaticCommittee; use hotshot_types::{ data::{EpochNumber, ViewNumber}, signature_key::BLSPubKey, @@ -17,7 +16,7 @@ mod utils; pub use header::Header; pub use impls::{ get_l1_deposits, retain_accounts, BuilderValidationError, FeeError, ProposalValidationError, - StateValidationError, + StateValidationError, StaticCommittee, }; pub use utils::*; use vbs::version::{StaticVersion, StaticVersionType}; From 10cfe43effb5e537efcbafd1705a1f88e54be9fc Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 14:55:47 -0300 Subject: [PATCH 27/58] change instantiation order Compiles! --- sequencer/src/context.rs | 18 +++---- sequencer/src/lib.rs | 102 ++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/sequencer/src/context.rs b/sequencer/src/context.rs index 38077308e5..7b5a24a089 100644 --- a/sequencer/src/context.rs +++ b/sequencer/src/context.rs @@ -1,5 +1,3 @@ -use std::{fmt::Display, sync::Arc}; - use anyhow::Context; use async_broadcast::{broadcast, Receiver, Sender}; use async_lock::RwLock; @@ -9,7 +7,7 @@ use derivative::Derivative; use espresso_types::{ parse_duration, v0::traits::{EventConsumer as PersistenceEventConsumer, SequencerPersistence}, - NodeState, PubKey, Transaction, ValidatedState, + NodeState, PubKey, StaticCommittee, Transaction, ValidatedState, }; use futures::{ future::{join_all, Future}, @@ -20,13 +18,6 @@ use hotshot::{ MarketplaceConfig, SystemContext, }; use hotshot_events_service::events_source::{EventConsumer, EventsStreamer}; -use parking_lot::Mutex; -use tokio::{ - spawn, - task::JoinHandle, - time::{sleep, timeout}, -}; - use hotshot_orchestrator::client::OrchestratorClient; use hotshot_types::{ consensus::ConsensusMetricsValue, @@ -41,7 +32,14 @@ use hotshot_types::{ utils::{View, ViewInner}, PeerConfig, ValidatorConfig, }; +use parking_lot::Mutex; use std::time::Duration; +use std::{fmt::Display, sync::Arc}; +use tokio::{ + spawn, + task::JoinHandle, + time::{sleep, timeout}, +}; use tracing::{Instrument, Level}; use url::Url; diff --git a/sequencer/src/lib.rs b/sequencer/src/lib.rs index cabc4418d3..cc336984f8 100644 --- a/sequencer/src/lib.rs +++ b/sequencer/src/lib.rs @@ -14,6 +14,7 @@ mod message_compat_tests; use anyhow::Context; use catchup::StatePeers; use context::{ProposalFetcherConfig, SequencerContext}; +use espresso_types::StaticCommittee; use espresso_types::{ traits::EventConsumer, BackoffParams, L1ClientOptions, NodeState, PubKey, SeqTypes, SolverAuctionResultsProvider, ValidatedState, @@ -427,55 +428,6 @@ pub async fn init_node( response_size_maximum: network_params.libp2p_max_direct_transmit_size, }; - // Initialize the Libp2p network - let network = { - let p2p_network = Libp2pNetwork::from_config( - network_config.clone(), - membership.clone(), - gossip_config, - request_response_config, - libp2p_bind_address, - &validator_config.public_key, - // We need the private key so we can derive our Libp2p keypair - // (using https://docs.rs/blake3/latest/blake3/fn.derive_key.html) - &validator_config.private_key, - hotshot::traits::implementations::Libp2pMetricsValue::new(metrics), - ) - .await - .with_context(|| { - format!( - "Failed to create libp2p network on node {node_index}; binding to {:?}", - network_params.libp2p_bind_address - ) - })?; - - tracing::warn!("Waiting for at least one connection to be initialized"); - futures::select! { - _ = cdn_network.wait_for_ready().fuse() => { - tracing::warn!("CDN connection initialized"); - }, - _ = p2p_network.wait_for_ready().fuse() => { - tracing::warn!("P2P connection initialized"); - }, - }; - - // Combine the CDN and P2P networks - Arc::from(CombinedNetworks::new( - cdn_network, - p2p_network, - Some(Duration::from_secs(1)), - )) - }; - - let mut genesis_state = ValidatedState { - chain_config: genesis.chain_config.into(), - ..Default::default() - }; - for (address, amount) in genesis.accounts { - tracing::info!(%address, %amount, "Prefunding account for demo"); - genesis_state.prefund_account(address, amount); - } - let l1_client = l1_params .options .with_metrics(metrics) @@ -491,6 +443,16 @@ pub async fn init_node( .await } }; + + let mut genesis_state = ValidatedState { + chain_config: genesis.chain_config.into(), + ..Default::default() + }; + for (address, amount) in genesis.accounts { + tracing::info!(%address, %amount, "Prefunding account for demo"); + genesis_state.prefund_account(address, amount); + } + let instance_state = NodeState { chain_config: genesis.chain_config, l1_client, @@ -515,8 +477,49 @@ pub async fn init_node( network_config.config.known_nodes_with_stake.clone(), network_config.config.known_nodes_with_stake.clone(), &instance_state, + Default::default(), ); + // Initialize the Libp2p network + let network = { + let p2p_network = Libp2pNetwork::from_config( + network_config.clone(), + membership.clone(), + gossip_config, + request_response_config, + libp2p_bind_address, + &validator_config.public_key, + // We need the private key so we can derive our Libp2p keypair + // (using https://docs.rs/blake3/latest/blake3/fn.derive_key.html) + &validator_config.private_key, + hotshot::traits::implementations::Libp2pMetricsValue::new(metrics), + ) + .await + .with_context(|| { + format!( + "Failed to create libp2p network on node {node_index}; binding to {:?}", + network_params.libp2p_bind_address + ) + })?; + + tracing::warn!("Waiting for at least one connection to be initialized"); + futures::select! { + _ = cdn_network.wait_for_ready().fuse() => { + tracing::warn!("CDN connection initialized"); + }, + _ = p2p_network.wait_for_ready().fuse() => { + tracing::warn!("P2P connection initialized"); + }, + }; + + // Combine the CDN and P2P networks + Arc::from(CombinedNetworks::new( + cdn_network, + p2p_network, + Some(Duration::from_secs(1)), + )) + }; + let mut ctx = SequencerContext::init( network_config, validator_config, @@ -954,7 +957,6 @@ pub mod testing { .with_upgrades(upgrades); // Create the HotShot membership - // TODO use our own implementation and pull from contract let membership = StaticCommittee::new( config.known_nodes_with_stake.clone(), config.known_nodes_with_stake.clone(), From 0adfa821b0fbfb8dbe7fe59eb1b83cdaa7337a3d Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 15:58:33 -0300 Subject: [PATCH 28/58] successfully deploy stake_table contract for test --- sequencer/src/genesis.rs | 4 +++- sequencer/src/message_compat_tests.rs | 3 +-- types/src/reference_tests.rs | 1 + types/src/v0/impls/l1.rs | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sequencer/src/genesis.rs b/sequencer/src/genesis.rs index 9c9f6c4d60..ed21d03e63 100644 --- a/sequencer/src/genesis.rs +++ b/sequencer/src/genesis.rs @@ -417,7 +417,8 @@ mod test { base_fee: 1.into(), fee_recipient: FeeAccount::default(), fee_contract: Some(Address::default()), - bid_recipient: None + bid_recipient: None, + stake_table_contract: Some(Address::default()) } ); assert_eq!( @@ -489,6 +490,7 @@ mod test { fee_recipient: FeeAccount::default(), bid_recipient: None, fee_contract: None, + stake_table_contract: None, } ); assert_eq!( diff --git a/sequencer/src/message_compat_tests.rs b/sequencer/src/message_compat_tests.rs index 9500a6fc85..8cc44bf8ad 100755 --- a/sequencer/src/message_compat_tests.rs +++ b/sequencer/src/message_compat_tests.rs @@ -18,7 +18,6 @@ use std::path::Path; use committable::Committable; use espresso_types::{NodeState, PubKey, ValidatedState}; -use hotshot::traits::election::static_committee::StaticCommittee; use hotshot_types::{ data::{ DaProposal, EpochNumber, QuorumProposal, UpgradeProposal, VidDisperse, VidDisperseShare, @@ -53,7 +52,7 @@ use vbs::{ #[cfg(feature = "testing")] async fn test_message_compat(_ver: Ver) { - use espresso_types::{Leaf, Payload, SeqTypes, Transaction}; + use espresso_types::{Leaf, Payload, SeqTypes, StaticCommittee, Transaction}; use hotshot_example_types::node_types::TestVersions; use hotshot_types::PeerConfig; diff --git a/types/src/reference_tests.rs b/types/src/reference_tests.rs index 5d77e13fd0..96ac43e320 100755 --- a/types/src/reference_tests.rs +++ b/types/src/reference_tests.rs @@ -101,6 +101,7 @@ fn reference_chain_config() -> crate::v0_99::ChainConfig { fee_contract: Some(Default::default()), fee_recipient: Default::default(), bid_recipient: Some(Default::default()), + stake_table_contract: Some(Default::default()), } } diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index 8aba381a90..1ed34f2b7c 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -1283,12 +1283,12 @@ mod test { let client = Arc::new(client); // Initialize a contract with some deposits - + let v: Vec = Vec::new(); // deploy the stake_table contract let stake_table_contract = contract_bindings::permissioned_stake_table::PermissionedStakeTable::deploy( client.clone(), - (), + v, ) .unwrap() .send() From 85339789b341f64f3a07d949c6540109f26a2970 Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 15:59:20 -0300 Subject: [PATCH 29/58] cleanup --- types/src/v0/impls/l1.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index 1ed34f2b7c..28bbb9f958 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -1266,10 +1266,6 @@ mod test { async fn test_fetch_stake_table() -> anyhow::Result<()> { setup_test(); - // how many deposits will we make - let deposits = 5; - let deploy_txn_count = 2; - let anvil = Anvil::new().spawn(); let wallet_address = anvil.addresses().first().cloned().unwrap(); let l1_client = L1Client::new(anvil.endpoint().parse().unwrap()); From b1179bfaa337d00036c22d6bed4f7f8cc2327c7f Mon Sep 17 00:00:00 2001 From: Alysia Tech Date: Fri, 6 Dec 2024 10:17:07 -0500 Subject: [PATCH 30/58] update comment to match implementation (#2282) * align comment with implementation * added more clarity * comment format * clearer comment * update comment to make it clear that there may be outdated elements in the state history --- contracts/src/LightClient.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/contracts/src/LightClient.sol b/contracts/src/LightClient.sol index fcb5ad4985..c38a422672 100644 --- a/contracts/src/LightClient.sol +++ b/contracts/src/LightClient.sol @@ -306,13 +306,16 @@ contract LightClient is Initializable, OwnableUpgradeable, UUPSUpgradeable { } /// @notice Updates the `stateHistoryCommitments` array when a new finalized state is added - /// and ensures that the array does not retain states older than the + /// and prunes the most outdated element starting from the first element if they fall outside + /// the /// `stateHistoryRetentionPeriod`. /// @dev the block timestamp is used to determine if the stateHistoryCommitments array /// should be pruned, based on the stateHistoryRetentionPeriod (seconds). - /// @dev a FIFO approach is used to delete elements from the start of the array, - /// ensuring that only the most recent states that only recent states are kept within - /// the retention window. + /// @dev A FIFO approach is used to remove the most outdated element from the start of the + /// array. + /// However, only one outdated element is removed per invocation of this function, even if + /// multiple elements exceed the retention period. As a result, some outdated elements may + /// remain in the array temporarily until subsequent invocations of this function. /// @dev the `delete` method does not reduce the array length but resets the value at the /// specified index to zero. the stateHistoryFirstIndex variable acts as an offset to indicate /// the starting point for reading the array, since the length of the array is not reduced @@ -426,8 +429,8 @@ contract LightClient is Initializable, OwnableUpgradeable, UUPSUpgradeable { revert InvalidHotShotBlockForCommitmentCheck(); } for (uint256 i = stateHistoryFirstIndex; i < commitmentsHeight; i++) { - // The first commitment greater than the provided height is the root of the tree - // that leaf at that HotShot height + // Finds and returns the first HotShot commitment whose height is greater than + // or equal to the specified HotShot height. if (stateHistoryCommitments[i].hotShotBlockHeight >= hotShotBlockHeight) { return ( stateHistoryCommitments[i].hotShotBlockCommRoot, From 53274f2d3221ccb3808111a492a10cbea9aaf43a Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 00:15:26 +0500 Subject: [PATCH 31/58] update query-service --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 762c0790cd..a544cf3705 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4239,7 +4239,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#5e2c984d19da3826f4cc8d80c5cf1a84dcd377f7" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#31ab748ab89f64b65ded54793825520f297d0dba" dependencies = [ "anyhow", "ark-serialize", @@ -7577,7 +7577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.87", From 6f68c0b9ca355f45d52c8bba64f8ca26bbaa5426 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 01:15:36 +0500 Subject: [PATCH 32/58] db max connections = 25 for dev node tests --- sequencer/src/bin/espresso-dev-node.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sequencer/src/bin/espresso-dev-node.rs b/sequencer/src/bin/espresso-dev-node.rs index 1280c87315..3a91d92598 100644 --- a/sequencer/src/bin/espresso-dev-node.rs +++ b/sequencer/src/bin/espresso-dev-node.rs @@ -604,6 +604,7 @@ mod tests { "ESPRESSO_SEQUENCER_STORAGE_PATH", tmp_dir.path().as_os_str(), ) + .env("ESPRESSO_SEQUENCER_DATABASE_MAX_CONNECTIONS", "25") .spawn() .unwrap(); @@ -910,6 +911,7 @@ mod tests { "ESPRESSO_SEQUENCER_STORAGE_PATH", tmp_dir.path().as_os_str(), ) + .env("ESPRESSO_SEQUENCER_DATABASE_MAX_CONNECTIONS", "25") .spawn() .unwrap(); From 3be360680fb75045f2d9a05cef8ade44228b9e09 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 03:05:19 +0500 Subject: [PATCH 33/58] update query-service --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a544cf3705..b9e749d6b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4239,7 +4239,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#31ab748ab89f64b65ded54793825520f297d0dba" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#ab55db87ab86b78e40ef420537192d213c52008d" dependencies = [ "anyhow", "ark-serialize", @@ -7577,7 +7577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.87", From 66d1590863577dfc0ed3b4f67d0eef02d0ccd12b Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Dec 2024 02:37:50 +0100 Subject: [PATCH 34/58] Fix no-storage decides --- sequencer/src/persistence/no_storage.rs | 37 +++++++++++-------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/sequencer/src/persistence/no_storage.rs b/sequencer/src/persistence/no_storage.rs index 0b1e4cd44f..f7b34aeb1a 100644 --- a/sequencer/src/persistence/no_storage.rs +++ b/sequencer/src/persistence/no_storage.rs @@ -57,28 +57,23 @@ impl SequencerPersistence for NoStorage { leaves: impl IntoIterator, QuorumCertificate2)> + Send, consumer: &impl EventConsumer, ) -> anyhow::Result<()> { - let (mut leaf_chain, mut qcs): (Vec<_>, Vec<_>) = leaves + let leaves = leaves .into_iter() - .map(|(info, qc)| (info.clone(), qc)) - .unzip(); - - // Put in reverse chronological order, as expected from Decide events. - leaf_chain.reverse(); - qcs.reverse(); - - // Generate decide event for the consumer. - let final_qc = qcs.pop().unwrap(); - - consumer - .handle_event(&Event { - view_number, - event: EventType::Decide { - leaf_chain: Arc::new(leaf_chain), - qc: Arc::new(final_qc), - block_size: None, - }, - }) - .await + .map(|(info_ref, qc)| (info_ref.clone(), qc)) + .collect::>(); + for (leaf_info, qc) in leaves { + consumer + .handle_event(&Event { + view_number, + event: EventType::Decide { + leaf_chain: Arc::new(vec![leaf_info.clone()]), + qc: Arc::new(qc), + block_size: None, + }, + }) + .await?; + } + Ok(()) } async fn load_latest_acted_view(&self) -> anyhow::Result> { From 4a2cd0336e735942dd7fb289a62ffe744efcc5d4 Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Dec 2024 03:26:43 +0100 Subject: [PATCH 35/58] Branches -> tags --- Cargo.lock | 45 +++++++++------------------------------------ Cargo.toml | 8 ++++---- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b9e749d6b7..c7805b7b43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1267,7 +1267,7 @@ dependencies = [ "hotshot", "hotshot-builder-api", "hotshot-builder-core", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-state-prover", "hotshot-types", "jf-signature 0.2.0", @@ -4054,7 +4054,7 @@ dependencies = [ [[package]] name = "hotshot-builder-core" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -4132,33 +4132,6 @@ dependencies = [ "vbs", ] -[[package]] -name = "hotshot-events-service" -version = "0.1.56" -source = "git+https://github.com/EspressoSystems/hotshot-events-service.git?branch=hotshot%2F0.5.82#f7b6da149c2aa3c15996ece0a07d30039f540680" -dependencies = [ - "async-broadcast", - "async-lock 2.8.0", - "async-trait", - "clap", - "derivative", - "derive_more 0.99.18", - "either", - "futures", - "hotshot-types", - "libp2p-identity", - "rand 0.8.5", - "serde", - "snafu 0.8.5", - "tagged-base64", - "tide-disco", - "tokio", - "toml 0.8.19", - "tracing", - "tracing-test", - "vbs", -] - [[package]] name = "hotshot-example-types" version = "0.5.79" @@ -4239,7 +4212,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#ab55db87ab86b78e40ef420537192d213c52008d" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?tag=v0.1.75#dffefa160f441a663723a67bc54efedb11a88b02" dependencies = [ "anyhow", "ark-serialize", @@ -6211,7 +6184,7 @@ dependencies = [ "futures", "hotshot", "hotshot-builder-api", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-orchestrator", "hotshot-query-service", "hotshot-stake-table", @@ -6237,7 +6210,7 @@ dependencies = [ [[package]] name = "marketplace-builder-core" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -6263,7 +6236,7 @@ dependencies = [ [[package]] name = "marketplace-builder-shared" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -6278,7 +6251,7 @@ dependencies = [ "hex", "hotshot", "hotshot-builder-api", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?branch=hotshot%2F0.5.82)", + "hotshot-events-service", "hotshot-example-types", "hotshot-task-impls", "hotshot-testing", @@ -6309,7 +6282,7 @@ dependencies = [ "espresso-types", "futures", "hotshot", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-query-service", "hotshot-types", "marketplace-solver", @@ -8652,7 +8625,7 @@ dependencies = [ "futures", "hotshot", "hotshot-contract-adapter", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-example-types", "hotshot-orchestrator", "hotshot-query-service", diff --git a/Cargo.toml b/Cargo.toml index 2e6ef2c62c..011701805d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,12 +67,12 @@ tokio = { version = "1", default-features = false, features = [ hotshot = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } # Hotshot imports hotshot-builder-api = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } -hotshot-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } -marketplace-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } -marketplace-builder-shared = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } +hotshot-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } +marketplace-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } +marketplace-builder-shared = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } hotshot-events-service = { git = "https://github.com/EspressoSystems/hotshot-events-service.git", tag = "0.1.56" } hotshot-orchestrator = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } -hotshot-query-service = { git = "https://github.com/EspressoSystems/hotshot-query-service", branch = "hotshot/0.5.82" } +hotshot-query-service = { git = "https://github.com/EspressoSystems/hotshot-query-service", tag = "v0.1.75" } hotshot-stake-table = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } hotshot-state-prover = { version = "0.1.0", path = "hotshot-state-prover" } hotshot-task = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } From 53810bdd2d3faa83130d2e36958884b46870a5b2 Mon Sep 17 00:00:00 2001 From: Alysia Tech Date: Fri, 6 Dec 2024 13:51:18 -0500 Subject: [PATCH 36/58] 2368 stake table registration with fixed stake (#2365) * add stake table tests * remove stake types * verify token allowance, balance and reprioritize verification order on registration * set the fixed stake amount, added related tests, updated data types * add more verification checks to the withdraw function * updated errror types * added TODO statements in comments to be explicit about outdated functions that need to be updated to the new spec --- contracts/src/StakeTable.sol | 152 +++++++--- .../src/interfaces/AbstractStakeTable.sol | 29 +- contracts/test/StakeTable.t.sol | 262 ++++++++++++++++++ 3 files changed, 385 insertions(+), 58 deletions(-) create mode 100644 contracts/test/StakeTable.t.sol diff --git a/contracts/src/StakeTable.sol b/contracts/src/StakeTable.sol index 6a809e0c7a..1bff92ea27 100644 --- a/contracts/src/StakeTable.sol +++ b/contracts/src/StakeTable.sol @@ -21,6 +21,9 @@ contract StakeTable is AbstractStakeTable { /// account. error NodeAlreadyRegistered(); + /// Error raised when a user tries to withdraw funds from a node that is not registered. + error NodeNotRegistered(); + /// Error raised when a user tries to make a deposit or request an exit but does not control the /// node public key. error Unauthenticated(); @@ -37,14 +40,24 @@ contract StakeTable is AbstractStakeTable { // Error raised when a user tries to withdraw funds before the exit escrow period is over. error PrematureWithdrawal(); + // Error raised when this contract does not have the sufficient allowance on the stake ERC20 + // token + error InsufficientAllowance(uint256, uint256); + + // Error raised when the staker does not have the sufficient balance on the stake ERC20 token + error InsufficientBalance(uint256); + + // Error raised when the staker does not have the sufficient stake balance to withdraw + error InsufficientStakeBalance(uint256); + + // Error raised when the staker does not register with the correct stakeAmount + error InsufficientStakeAmount(uint256); + /// Mapping from a hash of a BLS key to a node struct defined in the abstract contract. mapping(bytes32 keyHash => Node node) public nodes; - /// Total native stake locked for the latest stake table (HEAD). - uint256 public totalNativeStake; - - /// Total restaked stake locked for the latest stake table (HEAD). - uint256 public totalRestakedStake; + /// Total stake locked; + uint256 public totalStake; /// Address of the native token contract. address public tokenAddress; @@ -97,18 +110,11 @@ contract StakeTable is AbstractStakeTable { return 0; } - /// @notice Total stakes of the registered keys in the latest stake table (Head). - /// @dev Given that the current implementation does not support restaking, the second value of - /// the output is set to 0. - /// @return The total stake for native token and restaked token respectively. - function totalStake() external view override returns (uint256, uint256) { - return (totalNativeStake, totalRestakedStake); - } - /// @notice Look up the balance of `blsVK` /// @param blsVK BLS public key controlled by the user. /// @return Current balance owned by the user. - function lookupStake(BN254.G2Point memory blsVK) external view override returns (uint64) { + /// TODO modify this according to the current spec + function lookupStake(BN254.G2Point memory blsVK) external view override returns (uint256) { Node memory node = this.lookupNode(blsVK); return node.balance; } @@ -117,11 +123,13 @@ contract StakeTable is AbstractStakeTable { /// @dev The lookup is achieved by hashing first the four field elements of blsVK using /// keccak256. /// @return Node indexed by blsVK + /// TODO modify this according to the current spec function lookupNode(BN254.G2Point memory blsVK) external view override returns (Node memory) { return nodes[_hashBlsKey(blsVK)]; } /// @notice Get the next available epoch and queue size in that epoch + /// TODO modify this according to the current spec function nextRegistrationEpoch() external view override returns (uint64, uint64) { uint64 epoch; uint64 queueSize; @@ -143,17 +151,20 @@ contract StakeTable is AbstractStakeTable { // @param epoch next available registration epoch // @param queueSize current size of the registration queue (after insertion of new element in // the queue) + /// TODO modify this according to the current spec function appendRegistrationQueue(uint64 epoch, uint64 queueSize) private { firstAvailableRegistrationEpoch = epoch; _numPendingRegistrations = queueSize + 1; } /// @notice Get the number of pending registration requests in the waiting queue + /// TODO modify this according to the current spec function numPendingRegistrations() external view override returns (uint64) { return _numPendingRegistrations; } /// @notice Get the next available epoch for exit and queue size in that epoch + /// TODO modify this according to the current spec function nextExitEpoch() external view override returns (uint64, uint64) { uint64 epoch; uint64 queueSize; @@ -174,12 +185,14 @@ contract StakeTable is AbstractStakeTable { // @notice Update the exit queue // @param epoch next available exit epoch // @param queueSize current size of the exit queue (after insertion of new element in the queue) + /// TODO modify this according to the current spec function appendExitQueue(uint64 epoch, uint64 queueSize) private { firstAvailableExitEpoch = epoch; _numPendingExits = queueSize + 1; } /// @notice Get the number of pending exit requests in the waiting queue + /// TODO modify this according to the current spec function numPendingExits() external view override returns (uint64) { return _numPendingExits; } @@ -198,6 +211,7 @@ contract StakeTable is AbstractStakeTable { /// withdraw. /// @param node node which is assigned an exit escrow period. /// @return Number of epochs post exit after which funds can be withdrawn. + /// TODO modify this according to the current spec function exitEscrowPeriod(Node memory node) public pure returns (uint64) { if (node.balance > 100) { return 10; @@ -211,29 +225,56 @@ contract StakeTable is AbstractStakeTable { /// @param blsVK The BLS verification key /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register - /// @param stakeType The type of staking (native or restaking) /// @param blsSig The BLS signature that authenticates the ethereum account this function is /// called from /// @param validUntilEpoch The maximum epoch the sender is willing to wait to be included /// (cannot be smaller than the current epoch) /// - /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, - /// the contract only treat it as auxiliary info submitted by `blsVK`. - /// @dev `blsSig` field is necessary to prevent "rogue public-key attack". + /// @dev The function will revert if the sender does not have the correct stake amount. + /// @dev The function will revert if the sender does not have the correct allowance. + /// @dev The function will revert if the sender does not have the correct balance. + /// @dev The function will revert if the sender does not have the correct BLS signature. + /// `blsSig` field is necessary to prevent "rogue public-key attack". /// The signature is over the caller address of the function to ensure that each message is /// unique. + /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, + /// the contract only treat it as auxiliary info submitted by `blsVK`. + /// @dev The function will revert if the sender does not have the correct registration epoch. function register( BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK, - uint64 amount, - StakeType stakeType, + uint256 amount, BN254.G1Point memory blsSig, uint64 validUntilEpoch ) external override { - if (stakeType != StakeType.Native) { - revert RestakingNotImplemented(); + uint256 fixedStakeAmount = minStakeAmount(); + + // Verify that the sender amount is the minStakeAmount + if (amount < fixedStakeAmount) { + revert InsufficientStakeAmount(amount); } + bytes32 key = _hashBlsKey(blsVK); + Node memory node = nodes[key]; + + // Verify that the node is not already registered. + if (node.account != address(0x0)) { + revert NodeAlreadyRegistered(); + } + + // Verify that this contract has permissions to access the validator's stake token. + uint256 allowance = ERC20(tokenAddress).allowance(msg.sender, address(this)); + if (allowance < fixedStakeAmount) { + revert InsufficientAllowance(allowance, fixedStakeAmount); + } + + // Verify that the validator has the balance for this stake token. + uint256 balance = ERC20(tokenAddress).balanceOf(msg.sender); + if (balance < fixedStakeAmount) { + revert InsufficientBalance(balance); + } + + // Verify that the validator can sign for that blsVK bytes memory message = abi.encode(msg.sender); BLSSig.verifyBlsSig(message, blsSig, blsVK); @@ -247,42 +288,36 @@ contract StakeTable is AbstractStakeTable { } appendRegistrationQueue(registerEpoch, queueSize); - bytes32 key = _hashBlsKey(blsVK); - Node memory node = nodes[key]; + // Transfer the stake amount of ERC20 tokens from the sender to this contract. + SafeTransferLib.safeTransferFrom( + ERC20(tokenAddress), msg.sender, address(this), fixedStakeAmount + ); - // The node must not already be registered. - if (node.account != address(0x0)) { - revert NodeAlreadyRegistered(); - } + // Update the total staked amount + totalStake += fixedStakeAmount; // Create an entry for the node. node.account = msg.sender; - node.balance = amount; - node.stakeType = stakeType; + node.balance = fixedStakeAmount; node.schnorrVK = schnorrVK; node.registerEpoch = registerEpoch; nodes[key] = node; - // Lock the deposited tokens in this contract. - if (stakeType == StakeType.Native) { - totalNativeStake += amount; - SafeTransferLib.safeTransferFrom(ERC20(tokenAddress), msg.sender, address(this), amount); - } // Other case will be implemented when we support restaking - - emit Registered(key, registerEpoch, stakeType, amount); + emit Registered(key, registerEpoch, fixedStakeAmount); } /// @notice Deposit more stakes to registered keys /// @dev TODO this implementation will be revisited later. See /// https://github.com/EspressoSystems/espresso-sequencer/issues/806 + /// @dev TODO modify this according to the current spec /// @param blsVK The BLS verification key /// @param amount The amount to deposit /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function deposit(BN254.G2Point memory blsVK, uint64 amount) + function deposit(BN254.G2Point memory blsVK, uint256 amount) external override - returns (uint64, uint64) + returns (uint256, uint64) { bytes32 key = _hashBlsKey(blsVK); Node memory node = nodes[key]; @@ -315,6 +350,7 @@ contract StakeTable is AbstractStakeTable { /// @notice Request to exit from the stake table, not immediately withdrawable! /// + /// @dev TODO modify this according to the current spec /// @param blsVK The BLS verification key to exit function requestExit(BN254.G2Point memory blsVK) external override { bytes32 key = _hashBlsKey(blsVK); @@ -349,19 +385,53 @@ contract StakeTable is AbstractStakeTable { /// withdraw past their `exitEpoch`. /// /// @param blsVK The BLS verification key to withdraw + /// @param blsSig The BLS signature that authenticates the ethereum account this function is + /// called from the caller /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdrawFunds(BN254.G2Point memory blsVK) external override returns (uint64) { + /// TODO: This function should be tested + /// TODO modify this according to the current spec + + function withdrawFunds(BN254.G2Point memory blsVK, BN254.G1Point memory blsSig) + external + override + returns (uint256) + { bytes32 key = _hashBlsKey(blsVK); Node memory node = nodes[key]; + // Verify that the node is already registered. + if (node.account == address(0)) { + revert NodeNotRegistered(); + } + + // Verify that the balance is greater than zero + uint256 balance = node.balance; + if (balance == 0) { + revert InsufficientStakeBalance(0); + } + + // Verify that the validator can sign for that blsVK + bytes memory message = abi.encode(msg.sender); + BLSSig.verifyBlsSig(message, blsSig, blsVK); + + // Verify that the exit escrow period is over. if (currentEpoch() < node.exitEpoch + exitEscrowPeriod(node)) { revert PrematureWithdrawal(); } - uint64 balance = node.balance; + + // Delete the node from the stake table. delete nodes[key]; + // Transfer the balance to the node's account. SafeTransferLib.safeTransfer(ERC20(tokenAddress), node.account, balance); return balance; } + + /// @notice Minimum stake amount + /// @return Minimum stake amount + /// TODO: This value should be a variable modifiable by admin + function minStakeAmount() public pure returns (uint256) { + return 10 ether; + } } diff --git a/contracts/src/interfaces/AbstractStakeTable.sol b/contracts/src/interfaces/AbstractStakeTable.sol index d5a37ba099..62ff0fc5e3 100644 --- a/contracts/src/interfaces/AbstractStakeTable.sol +++ b/contracts/src/interfaces/AbstractStakeTable.sol @@ -26,11 +26,8 @@ abstract contract AbstractStakeTable { /// @notice Signals a registration of a BLS public key. /// @param blsVKhash hash of the BLS public key that is registered. /// @param registerEpoch epoch when the registration becomes effective. - /// @param stakeType native or restake token. /// @param amountDeposited amount deposited when registering the new node. - event Registered( - bytes32 blsVKhash, uint64 registerEpoch, StakeType stakeType, uint256 amountDeposited - ); + event Registered(bytes32 blsVKhash, uint64 registerEpoch, uint256 amountDeposited); /// @notice Signals an exit request has been granted. /// @param blsVKhash hash of the BLS public key owned by the user who requested to exit. @@ -55,15 +52,13 @@ abstract contract AbstractStakeTable { /// @notice Represents a HotShot validator node /// In the dual-staking model, a HotShot validator could have multiple `Node` entries. /// @param account The Ethereum account of the validator. - /// @param stakeType The type of token staked. /// @param balance The amount of token staked. /// @param registerEpoch The starting epoch for the validator. /// @param exitEpoch The ending epoch for the validator. /// @param schnorrVK The Schnorr verification key associated. struct Node { address account; - StakeType stakeType; - uint64 balance; + uint256 balance; uint64 registerEpoch; uint64 exitEpoch; EdOnBN254.EdOnBN254Point schnorrVK; @@ -71,11 +66,8 @@ abstract contract AbstractStakeTable { // === Table State & Stats === - /// @notice Total stakes of the registered keys in the latest stake table (Head). - /// @return The total stake for native token and restaked token respectively. - function totalStake() external view virtual returns (uint256, uint256); /// @notice Look up the balance of `blsVK` - function lookupStake(BN254.G2Point memory blsVK) external view virtual returns (uint64); + function lookupStake(BN254.G2Point memory blsVK) external view virtual returns (uint256); /// @notice Look up the full `Node` state associated with `blsVK` function lookupNode(BN254.G2Point memory blsVK) external view virtual returns (Node memory); @@ -97,7 +89,6 @@ abstract contract AbstractStakeTable { /// @param blsVK The BLS verification key /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register - /// @param stakeType The type of staking (native or restaking) /// @param blsSig The BLS signature that authenticates the ethereum account this function is /// called from /// @param validUntilEpoch The maximum epoch the sender is willing to wait to be included @@ -110,8 +101,7 @@ abstract contract AbstractStakeTable { function register( BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK, - uint64 amount, - StakeType stakeType, + uint256 amount, BN254.G1Point memory blsSig, uint64 validUntilEpoch ) external virtual; @@ -121,10 +111,10 @@ abstract contract AbstractStakeTable { /// @param blsVK The BLS verification key /// @param amount The amount to deposit /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function deposit(BN254.G2Point memory blsVK, uint64 amount) + function deposit(BN254.G2Point memory blsVK, uint256 amount) external virtual - returns (uint64, uint64); + returns (uint256, uint64); /// @notice Request to exit from the stake table, not immediately withdrawable! /// @@ -135,6 +125,11 @@ abstract contract AbstractStakeTable { /// withdraw past their `exitEpoch`. /// /// @param blsVK The BLS verification key to withdraw + /// @param blsSig The BLS signature that authenticates the ethereum account this function is + /// called from the caller /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdrawFunds(BN254.G2Point memory blsVK) external virtual returns (uint64); + function withdrawFunds(BN254.G2Point memory blsVK, BN254.G1Point memory blsSig) + external + virtual + returns (uint256); } diff --git a/contracts/test/StakeTable.t.sol b/contracts/test/StakeTable.t.sol new file mode 100644 index 0000000000..53154850f6 --- /dev/null +++ b/contracts/test/StakeTable.t.sol @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; +// import {console} from "forge-std/console.sol"; + +using stdStorage for StdStorage; + +import { ERC20 } from "solmate/utils/SafeTransferLib.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { BLSSig } from "../src/libraries/BLSSig.sol"; +import { EdOnBN254 } from "../src/libraries/EdOnBn254.sol"; +import { AbstractStakeTable } from "../src/interfaces/AbstractStakeTable.sol"; +import { LightClient } from "../src/LightClient.sol"; +import { LightClientMock } from "../test/mocks/LightClientMock.sol"; + +// Token contract +import { ExampleToken } from "../src/ExampleToken.sol"; + +// Target contract +import { StakeTable as S } from "../src/StakeTable.sol"; + +contract StakeTable_register_Test is Test { + event Registered(bytes32, uint64, uint256); + + S public stakeTable; + ExampleToken public token; + LightClientMock public lcMock; + uint256 public constant INITIAL_BALANCE = 10 ether; + address public exampleTokenCreator; + + function genClientWallet(address sender) + private + returns (BN254.G2Point memory, EdOnBN254.EdOnBN254Point memory, BN254.G1Point memory) + { + // Generate a BLS signature and other values using rust code + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "gen-client-wallet"; + cmds[2] = vm.toString(sender); + cmds[3] = "123"; + + bytes memory result = vm.ffi(cmds); + ( + BN254.G1Point memory blsSig, + BN254.G2Point memory blsVK, + uint256 schnorrVKx, + uint256 schnorrVKy, + ) = abi.decode(result, (BN254.G1Point, BN254.G2Point, uint256, uint256, address)); + + return ( + blsVK, // blsVK + EdOnBN254.EdOnBN254Point(schnorrVKx, schnorrVKy), // schnorrVK + blsSig // sig + ); + } + + function setUp() public { + exampleTokenCreator = makeAddr("tokenCreator"); + vm.prank(exampleTokenCreator); + token = new ExampleToken(INITIAL_BALANCE); + + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "mock-genesis"; + cmds[2] = "5"; + + bytes memory result = vm.ffi(cmds); + ( + LightClientMock.LightClientState memory state, + LightClientMock.StakeTableState memory stakeState + ) = abi.decode(result, (LightClient.LightClientState, LightClient.StakeTableState)); + LightClientMock.LightClientState memory genesis = state; + LightClientMock.StakeTableState memory genesisStakeTableState = stakeState; + + lcMock = new LightClientMock(genesis, genesisStakeTableState, 864000); + address lightClientAddress = address(lcMock); + stakeTable = new S(address(token), lightClientAddress, 10); + } + + function testFuzz_RevertWhen_InvalidBLSSig(uint256 scalar) external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + (BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK,) = + genClientWallet(exampleTokenCreator); + + // Prepare for the token transfer + vm.startPrank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Ensure the scalar is valid + // Note: Apparently BN254.scalarMul is not well defined when the scalar is 0 + scalar = bound(scalar, 1, BN254.R_MOD - 1); + BN254.validateScalarField(BN254.ScalarField.wrap(scalar)); + BN254.G1Point memory badSig = BN254.scalarMul(BN254.P1(), BN254.ScalarField.wrap(scalar)); + BN254.validateG1Point(badSig); + + // Failed signature verification + vm.expectRevert(BLSSig.BLSSigVerificationFailed.selector); + stakeTable.register(blsVK, schnorrVK, depositAmount, badSig, validUntilEpoch); + vm.stopPrank(); + } + + // commenting out epoch related tests for now + // function testFuzz_RevertWhen_InvalidNextRegistrationEpoch(uint64 rand) external { + // LCMock.setCurrentEpoch(3); + // uint64 currentEpoch = stakeTable.currentEpoch(); + + // uint64 depositAmount = 10 ether; + // vm.prank(exampleTokenCreator); + // token.approve(address(stakeTable), depositAmount); + + // ( + // BN254.G2Point memory blsVK, + // EdOnBN254.EdOnBN254Point memory schnorrVK, + // BN254.G1Point memory sig + // ) = genClientWallet(exampleTokenCreator); + + // // Invalid next registration epoch + // uint64 validUntilEpoch = uint64(bound(rand, 0, currentEpoch - 1)); + // vm.prank(exampleTokenCreator); + // vm.expectRevert( + // abi.encodeWithSelector( + // S.InvalidNextRegistrationEpoch.selector, currentEpoch + 1, validUntilEpoch + // ) + // ); + // stakeTable.register( + // blsVK, + // schnorrVK, + // depositAmount, + // sig, + // validUntilEpoch + // ); + + // // Valid next registration epoch + // validUntilEpoch = uint64(bound(rand, currentEpoch + 1, type(uint64).max)); + // vm.prank(exampleTokenCreator); + // stakeTable.register( + // blsVK, + // schnorrVK, + // depositAmount, + // sig, + // validUntilEpoch + // ); + // } + + function test_RevertWhen_NodeAlreadyRegistered() external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + // Prepare for the token transfer + vm.prank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Successful call to register + vm.prank(exampleTokenCreator); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // The node is already registered + vm.prank(exampleTokenCreator); + vm.expectRevert(S.NodeAlreadyRegistered.selector); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + } + + function test_RevertWhen_NoTokenAllowanceOrBalance() external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 10; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + assertEq(ERC20(token).balanceOf(exampleTokenCreator), INITIAL_BALANCE); + vm.prank(exampleTokenCreator); + // The call to register is expected to fail because the depositAmount has not been approved + // and thus the stake table contract cannot lock the stake. + vm.expectRevert(abi.encodeWithSelector(S.InsufficientAllowance.selector, 0, depositAmount)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // A user with 0 balance cannot register either + address newUser = makeAddr("New user with zero balance"); + (blsVK, schnorrVK, sig) = genClientWallet(newUser); + + vm.startPrank(newUser); + // Prepare for the token transfer by giving the StakeTable contract the required allowance + token.approve(address(stakeTable), depositAmount); + vm.expectRevert(abi.encodeWithSelector(S.InsufficientBalance.selector, 0)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + vm.stopPrank(); + } + + function test_RevertWhen_WrongStakeAmount() external { + uint64 depositAmount = 5 ether; + uint64 validUntilEpoch = 10; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + assertEq(ERC20(token).balanceOf(exampleTokenCreator), INITIAL_BALANCE); + vm.prank(exampleTokenCreator); + // The call to register is expected to fail because the depositAmount has not been approved + // and thus the stake table contract cannot lock the stake. + vm.expectRevert(abi.encodeWithSelector(S.InsufficientStakeAmount.selector, depositAmount)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + } + + /// @dev Tests a correct registration + function test_Registration_succeeds() external { + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + // Prepare for the token transfer + vm.prank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Balances before registration + assertEq(token.balanceOf(exampleTokenCreator), INITIAL_BALANCE); + + uint256 totalStakeAmount; + totalStakeAmount = stakeTable.totalStake(); + assertEq(totalStakeAmount, 0); + + AbstractStakeTable.Node memory node; + node.account = exampleTokenCreator; + node.balance = depositAmount; + node.schnorrVK = schnorrVK; + node.registerEpoch = 1; + + // Check event is emitted after calling successfully `register` + vm.expectEmit(false, false, false, true, address(stakeTable)); + emit Registered(stakeTable._hashBlsKey(blsVK), node.registerEpoch, node.balance); + vm.prank(exampleTokenCreator); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // Balance after registration + assertEq(token.balanceOf(exampleTokenCreator), INITIAL_BALANCE - depositAmount); + totalStakeAmount = stakeTable.totalStake(); + assertEq(totalStakeAmount, depositAmount); + } +} From 36b319e92aa9e6dade4d5a74faba2a31b0ab8ead Mon Sep 17 00:00:00 2001 From: Alysia Tech Date: Fri, 6 Dec 2024 10:17:07 -0500 Subject: [PATCH 37/58] update comment to match implementation (#2282) * align comment with implementation * added more clarity * comment format * clearer comment * update comment to make it clear that there may be outdated elements in the state history --- contracts/src/LightClient.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/contracts/src/LightClient.sol b/contracts/src/LightClient.sol index fcb5ad4985..c38a422672 100644 --- a/contracts/src/LightClient.sol +++ b/contracts/src/LightClient.sol @@ -306,13 +306,16 @@ contract LightClient is Initializable, OwnableUpgradeable, UUPSUpgradeable { } /// @notice Updates the `stateHistoryCommitments` array when a new finalized state is added - /// and ensures that the array does not retain states older than the + /// and prunes the most outdated element starting from the first element if they fall outside + /// the /// `stateHistoryRetentionPeriod`. /// @dev the block timestamp is used to determine if the stateHistoryCommitments array /// should be pruned, based on the stateHistoryRetentionPeriod (seconds). - /// @dev a FIFO approach is used to delete elements from the start of the array, - /// ensuring that only the most recent states that only recent states are kept within - /// the retention window. + /// @dev A FIFO approach is used to remove the most outdated element from the start of the + /// array. + /// However, only one outdated element is removed per invocation of this function, even if + /// multiple elements exceed the retention period. As a result, some outdated elements may + /// remain in the array temporarily until subsequent invocations of this function. /// @dev the `delete` method does not reduce the array length but resets the value at the /// specified index to zero. the stateHistoryFirstIndex variable acts as an offset to indicate /// the starting point for reading the array, since the length of the array is not reduced @@ -426,8 +429,8 @@ contract LightClient is Initializable, OwnableUpgradeable, UUPSUpgradeable { revert InvalidHotShotBlockForCommitmentCheck(); } for (uint256 i = stateHistoryFirstIndex; i < commitmentsHeight; i++) { - // The first commitment greater than the provided height is the root of the tree - // that leaf at that HotShot height + // Finds and returns the first HotShot commitment whose height is greater than + // or equal to the specified HotShot height. if (stateHistoryCommitments[i].hotShotBlockHeight >= hotShotBlockHeight) { return ( stateHistoryCommitments[i].hotShotBlockCommRoot, From fb71704e58bdb507da9610858da9568db85b96ed Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 00:15:26 +0500 Subject: [PATCH 38/58] update query-service --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 762c0790cd..a544cf3705 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4239,7 +4239,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#5e2c984d19da3826f4cc8d80c5cf1a84dcd377f7" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#31ab748ab89f64b65ded54793825520f297d0dba" dependencies = [ "anyhow", "ark-serialize", @@ -7577,7 +7577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.12.1", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.87", From b8fdaf83aad028fb7b956a71d1e565d017b69c15 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 01:15:36 +0500 Subject: [PATCH 39/58] db max connections = 25 for dev node tests --- sequencer/src/bin/espresso-dev-node.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sequencer/src/bin/espresso-dev-node.rs b/sequencer/src/bin/espresso-dev-node.rs index 1280c87315..3a91d92598 100644 --- a/sequencer/src/bin/espresso-dev-node.rs +++ b/sequencer/src/bin/espresso-dev-node.rs @@ -604,6 +604,7 @@ mod tests { "ESPRESSO_SEQUENCER_STORAGE_PATH", tmp_dir.path().as_os_str(), ) + .env("ESPRESSO_SEQUENCER_DATABASE_MAX_CONNECTIONS", "25") .spawn() .unwrap(); @@ -910,6 +911,7 @@ mod tests { "ESPRESSO_SEQUENCER_STORAGE_PATH", tmp_dir.path().as_os_str(), ) + .env("ESPRESSO_SEQUENCER_DATABASE_MAX_CONNECTIONS", "25") .spawn() .unwrap(); From ac5429777ac497d69f147d92b5e733e53b964b99 Mon Sep 17 00:00:00 2001 From: imabdulbasit Date: Fri, 6 Dec 2024 03:05:19 +0500 Subject: [PATCH 40/58] update query-service --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a544cf3705..b9e749d6b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4239,7 +4239,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#31ab748ab89f64b65ded54793825520f297d0dba" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#ab55db87ab86b78e40ef420537192d213c52008d" dependencies = [ "anyhow", "ark-serialize", @@ -7577,7 +7577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.87", From 97ff37f52e274811f7aeb699888552cfab2858e2 Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Dec 2024 02:37:50 +0100 Subject: [PATCH 41/58] Fix no-storage decides --- sequencer/src/persistence/no_storage.rs | 37 +++++++++++-------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/sequencer/src/persistence/no_storage.rs b/sequencer/src/persistence/no_storage.rs index 0b1e4cd44f..f7b34aeb1a 100644 --- a/sequencer/src/persistence/no_storage.rs +++ b/sequencer/src/persistence/no_storage.rs @@ -57,28 +57,23 @@ impl SequencerPersistence for NoStorage { leaves: impl IntoIterator, QuorumCertificate2)> + Send, consumer: &impl EventConsumer, ) -> anyhow::Result<()> { - let (mut leaf_chain, mut qcs): (Vec<_>, Vec<_>) = leaves + let leaves = leaves .into_iter() - .map(|(info, qc)| (info.clone(), qc)) - .unzip(); - - // Put in reverse chronological order, as expected from Decide events. - leaf_chain.reverse(); - qcs.reverse(); - - // Generate decide event for the consumer. - let final_qc = qcs.pop().unwrap(); - - consumer - .handle_event(&Event { - view_number, - event: EventType::Decide { - leaf_chain: Arc::new(leaf_chain), - qc: Arc::new(final_qc), - block_size: None, - }, - }) - .await + .map(|(info_ref, qc)| (info_ref.clone(), qc)) + .collect::>(); + for (leaf_info, qc) in leaves { + consumer + .handle_event(&Event { + view_number, + event: EventType::Decide { + leaf_chain: Arc::new(vec![leaf_info.clone()]), + qc: Arc::new(qc), + block_size: None, + }, + }) + .await?; + } + Ok(()) } async fn load_latest_acted_view(&self) -> anyhow::Result> { From 266027a5d48dca3330c78068e6fa77c52c99b786 Mon Sep 17 00:00:00 2001 From: Artemii Gerasimovich Date: Fri, 6 Dec 2024 03:26:43 +0100 Subject: [PATCH 42/58] Branches -> tags --- Cargo.lock | 45 +++++++++------------------------------------ Cargo.toml | 8 ++++---- 2 files changed, 13 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b9e749d6b7..c7805b7b43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1267,7 +1267,7 @@ dependencies = [ "hotshot", "hotshot-builder-api", "hotshot-builder-core", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-state-prover", "hotshot-types", "jf-signature 0.2.0", @@ -4054,7 +4054,7 @@ dependencies = [ [[package]] name = "hotshot-builder-core" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -4132,33 +4132,6 @@ dependencies = [ "vbs", ] -[[package]] -name = "hotshot-events-service" -version = "0.1.56" -source = "git+https://github.com/EspressoSystems/hotshot-events-service.git?branch=hotshot%2F0.5.82#f7b6da149c2aa3c15996ece0a07d30039f540680" -dependencies = [ - "async-broadcast", - "async-lock 2.8.0", - "async-trait", - "clap", - "derivative", - "derive_more 0.99.18", - "either", - "futures", - "hotshot-types", - "libp2p-identity", - "rand 0.8.5", - "serde", - "snafu 0.8.5", - "tagged-base64", - "tide-disco", - "tokio", - "toml 0.8.19", - "tracing", - "tracing-test", - "vbs", -] - [[package]] name = "hotshot-example-types" version = "0.5.79" @@ -4239,7 +4212,7 @@ dependencies = [ [[package]] name = "hotshot-query-service" version = "0.1.75" -source = "git+https://github.com/EspressoSystems/hotshot-query-service?branch=hotshot%2F0.5.82#ab55db87ab86b78e40ef420537192d213c52008d" +source = "git+https://github.com/EspressoSystems/hotshot-query-service?tag=v0.1.75#dffefa160f441a663723a67bc54efedb11a88b02" dependencies = [ "anyhow", "ark-serialize", @@ -6211,7 +6184,7 @@ dependencies = [ "futures", "hotshot", "hotshot-builder-api", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-orchestrator", "hotshot-query-service", "hotshot-stake-table", @@ -6237,7 +6210,7 @@ dependencies = [ [[package]] name = "marketplace-builder-core" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -6263,7 +6236,7 @@ dependencies = [ [[package]] name = "marketplace-builder-shared" version = "0.1.57" -source = "git+https://github.com/EspressoSystems/marketplace-builder-core?branch=hotshot%2F0.5.82#be5ab81e83127b665af026ec18dfa48b9aba3bb1" +source = "git+https://github.com/EspressoSystems/marketplace-builder-core?tag=0.1.57#cf9d2cbf154809a31bcf2dccc1218ee9c6875f1e" dependencies = [ "anyhow", "async-broadcast", @@ -6278,7 +6251,7 @@ dependencies = [ "hex", "hotshot", "hotshot-builder-api", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?branch=hotshot%2F0.5.82)", + "hotshot-events-service", "hotshot-example-types", "hotshot-task-impls", "hotshot-testing", @@ -6309,7 +6282,7 @@ dependencies = [ "espresso-types", "futures", "hotshot", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-query-service", "hotshot-types", "marketplace-solver", @@ -8652,7 +8625,7 @@ dependencies = [ "futures", "hotshot", "hotshot-contract-adapter", - "hotshot-events-service 0.1.56 (git+https://github.com/EspressoSystems/hotshot-events-service.git?tag=0.1.56)", + "hotshot-events-service", "hotshot-example-types", "hotshot-orchestrator", "hotshot-query-service", diff --git a/Cargo.toml b/Cargo.toml index 2e6ef2c62c..011701805d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,12 +67,12 @@ tokio = { version = "1", default-features = false, features = [ hotshot = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } # Hotshot imports hotshot-builder-api = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } -hotshot-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } -marketplace-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } -marketplace-builder-shared = { git = "https://github.com/EspressoSystems/marketplace-builder-core", branch = "hotshot/0.5.82" } +hotshot-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } +marketplace-builder-core = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } +marketplace-builder-shared = { git = "https://github.com/EspressoSystems/marketplace-builder-core", tag = "0.1.57" } hotshot-events-service = { git = "https://github.com/EspressoSystems/hotshot-events-service.git", tag = "0.1.56" } hotshot-orchestrator = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } -hotshot-query-service = { git = "https://github.com/EspressoSystems/hotshot-query-service", branch = "hotshot/0.5.82" } +hotshot-query-service = { git = "https://github.com/EspressoSystems/hotshot-query-service", tag = "v0.1.75" } hotshot-stake-table = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } hotshot-state-prover = { version = "0.1.0", path = "hotshot-state-prover" } hotshot-task = { git = "https://github.com/EspressoSystems/hotshot", tag = "0.5.82" } From f68aed02eb73b3703b9c425b69419aab5e7b064b Mon Sep 17 00:00:00 2001 From: Alysia Tech Date: Fri, 6 Dec 2024 13:51:18 -0500 Subject: [PATCH 43/58] 2368 stake table registration with fixed stake (#2365) * add stake table tests * remove stake types * verify token allowance, balance and reprioritize verification order on registration * set the fixed stake amount, added related tests, updated data types * add more verification checks to the withdraw function * updated errror types * added TODO statements in comments to be explicit about outdated functions that need to be updated to the new spec --- contracts/src/StakeTable.sol | 152 +++++++--- .../src/interfaces/AbstractStakeTable.sol | 29 +- contracts/test/StakeTable.t.sol | 262 ++++++++++++++++++ 3 files changed, 385 insertions(+), 58 deletions(-) create mode 100644 contracts/test/StakeTable.t.sol diff --git a/contracts/src/StakeTable.sol b/contracts/src/StakeTable.sol index 6a809e0c7a..1bff92ea27 100644 --- a/contracts/src/StakeTable.sol +++ b/contracts/src/StakeTable.sol @@ -21,6 +21,9 @@ contract StakeTable is AbstractStakeTable { /// account. error NodeAlreadyRegistered(); + /// Error raised when a user tries to withdraw funds from a node that is not registered. + error NodeNotRegistered(); + /// Error raised when a user tries to make a deposit or request an exit but does not control the /// node public key. error Unauthenticated(); @@ -37,14 +40,24 @@ contract StakeTable is AbstractStakeTable { // Error raised when a user tries to withdraw funds before the exit escrow period is over. error PrematureWithdrawal(); + // Error raised when this contract does not have the sufficient allowance on the stake ERC20 + // token + error InsufficientAllowance(uint256, uint256); + + // Error raised when the staker does not have the sufficient balance on the stake ERC20 token + error InsufficientBalance(uint256); + + // Error raised when the staker does not have the sufficient stake balance to withdraw + error InsufficientStakeBalance(uint256); + + // Error raised when the staker does not register with the correct stakeAmount + error InsufficientStakeAmount(uint256); + /// Mapping from a hash of a BLS key to a node struct defined in the abstract contract. mapping(bytes32 keyHash => Node node) public nodes; - /// Total native stake locked for the latest stake table (HEAD). - uint256 public totalNativeStake; - - /// Total restaked stake locked for the latest stake table (HEAD). - uint256 public totalRestakedStake; + /// Total stake locked; + uint256 public totalStake; /// Address of the native token contract. address public tokenAddress; @@ -97,18 +110,11 @@ contract StakeTable is AbstractStakeTable { return 0; } - /// @notice Total stakes of the registered keys in the latest stake table (Head). - /// @dev Given that the current implementation does not support restaking, the second value of - /// the output is set to 0. - /// @return The total stake for native token and restaked token respectively. - function totalStake() external view override returns (uint256, uint256) { - return (totalNativeStake, totalRestakedStake); - } - /// @notice Look up the balance of `blsVK` /// @param blsVK BLS public key controlled by the user. /// @return Current balance owned by the user. - function lookupStake(BN254.G2Point memory blsVK) external view override returns (uint64) { + /// TODO modify this according to the current spec + function lookupStake(BN254.G2Point memory blsVK) external view override returns (uint256) { Node memory node = this.lookupNode(blsVK); return node.balance; } @@ -117,11 +123,13 @@ contract StakeTable is AbstractStakeTable { /// @dev The lookup is achieved by hashing first the four field elements of blsVK using /// keccak256. /// @return Node indexed by blsVK + /// TODO modify this according to the current spec function lookupNode(BN254.G2Point memory blsVK) external view override returns (Node memory) { return nodes[_hashBlsKey(blsVK)]; } /// @notice Get the next available epoch and queue size in that epoch + /// TODO modify this according to the current spec function nextRegistrationEpoch() external view override returns (uint64, uint64) { uint64 epoch; uint64 queueSize; @@ -143,17 +151,20 @@ contract StakeTable is AbstractStakeTable { // @param epoch next available registration epoch // @param queueSize current size of the registration queue (after insertion of new element in // the queue) + /// TODO modify this according to the current spec function appendRegistrationQueue(uint64 epoch, uint64 queueSize) private { firstAvailableRegistrationEpoch = epoch; _numPendingRegistrations = queueSize + 1; } /// @notice Get the number of pending registration requests in the waiting queue + /// TODO modify this according to the current spec function numPendingRegistrations() external view override returns (uint64) { return _numPendingRegistrations; } /// @notice Get the next available epoch for exit and queue size in that epoch + /// TODO modify this according to the current spec function nextExitEpoch() external view override returns (uint64, uint64) { uint64 epoch; uint64 queueSize; @@ -174,12 +185,14 @@ contract StakeTable is AbstractStakeTable { // @notice Update the exit queue // @param epoch next available exit epoch // @param queueSize current size of the exit queue (after insertion of new element in the queue) + /// TODO modify this according to the current spec function appendExitQueue(uint64 epoch, uint64 queueSize) private { firstAvailableExitEpoch = epoch; _numPendingExits = queueSize + 1; } /// @notice Get the number of pending exit requests in the waiting queue + /// TODO modify this according to the current spec function numPendingExits() external view override returns (uint64) { return _numPendingExits; } @@ -198,6 +211,7 @@ contract StakeTable is AbstractStakeTable { /// withdraw. /// @param node node which is assigned an exit escrow period. /// @return Number of epochs post exit after which funds can be withdrawn. + /// TODO modify this according to the current spec function exitEscrowPeriod(Node memory node) public pure returns (uint64) { if (node.balance > 100) { return 10; @@ -211,29 +225,56 @@ contract StakeTable is AbstractStakeTable { /// @param blsVK The BLS verification key /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register - /// @param stakeType The type of staking (native or restaking) /// @param blsSig The BLS signature that authenticates the ethereum account this function is /// called from /// @param validUntilEpoch The maximum epoch the sender is willing to wait to be included /// (cannot be smaller than the current epoch) /// - /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, - /// the contract only treat it as auxiliary info submitted by `blsVK`. - /// @dev `blsSig` field is necessary to prevent "rogue public-key attack". + /// @dev The function will revert if the sender does not have the correct stake amount. + /// @dev The function will revert if the sender does not have the correct allowance. + /// @dev The function will revert if the sender does not have the correct balance. + /// @dev The function will revert if the sender does not have the correct BLS signature. + /// `blsSig` field is necessary to prevent "rogue public-key attack". /// The signature is over the caller address of the function to ensure that each message is /// unique. + /// @dev No validity check on `schnorrVK`, as it's assumed to be sender's responsibility, + /// the contract only treat it as auxiliary info submitted by `blsVK`. + /// @dev The function will revert if the sender does not have the correct registration epoch. function register( BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK, - uint64 amount, - StakeType stakeType, + uint256 amount, BN254.G1Point memory blsSig, uint64 validUntilEpoch ) external override { - if (stakeType != StakeType.Native) { - revert RestakingNotImplemented(); + uint256 fixedStakeAmount = minStakeAmount(); + + // Verify that the sender amount is the minStakeAmount + if (amount < fixedStakeAmount) { + revert InsufficientStakeAmount(amount); } + bytes32 key = _hashBlsKey(blsVK); + Node memory node = nodes[key]; + + // Verify that the node is not already registered. + if (node.account != address(0x0)) { + revert NodeAlreadyRegistered(); + } + + // Verify that this contract has permissions to access the validator's stake token. + uint256 allowance = ERC20(tokenAddress).allowance(msg.sender, address(this)); + if (allowance < fixedStakeAmount) { + revert InsufficientAllowance(allowance, fixedStakeAmount); + } + + // Verify that the validator has the balance for this stake token. + uint256 balance = ERC20(tokenAddress).balanceOf(msg.sender); + if (balance < fixedStakeAmount) { + revert InsufficientBalance(balance); + } + + // Verify that the validator can sign for that blsVK bytes memory message = abi.encode(msg.sender); BLSSig.verifyBlsSig(message, blsSig, blsVK); @@ -247,42 +288,36 @@ contract StakeTable is AbstractStakeTable { } appendRegistrationQueue(registerEpoch, queueSize); - bytes32 key = _hashBlsKey(blsVK); - Node memory node = nodes[key]; + // Transfer the stake amount of ERC20 tokens from the sender to this contract. + SafeTransferLib.safeTransferFrom( + ERC20(tokenAddress), msg.sender, address(this), fixedStakeAmount + ); - // The node must not already be registered. - if (node.account != address(0x0)) { - revert NodeAlreadyRegistered(); - } + // Update the total staked amount + totalStake += fixedStakeAmount; // Create an entry for the node. node.account = msg.sender; - node.balance = amount; - node.stakeType = stakeType; + node.balance = fixedStakeAmount; node.schnorrVK = schnorrVK; node.registerEpoch = registerEpoch; nodes[key] = node; - // Lock the deposited tokens in this contract. - if (stakeType == StakeType.Native) { - totalNativeStake += amount; - SafeTransferLib.safeTransferFrom(ERC20(tokenAddress), msg.sender, address(this), amount); - } // Other case will be implemented when we support restaking - - emit Registered(key, registerEpoch, stakeType, amount); + emit Registered(key, registerEpoch, fixedStakeAmount); } /// @notice Deposit more stakes to registered keys /// @dev TODO this implementation will be revisited later. See /// https://github.com/EspressoSystems/espresso-sequencer/issues/806 + /// @dev TODO modify this according to the current spec /// @param blsVK The BLS verification key /// @param amount The amount to deposit /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function deposit(BN254.G2Point memory blsVK, uint64 amount) + function deposit(BN254.G2Point memory blsVK, uint256 amount) external override - returns (uint64, uint64) + returns (uint256, uint64) { bytes32 key = _hashBlsKey(blsVK); Node memory node = nodes[key]; @@ -315,6 +350,7 @@ contract StakeTable is AbstractStakeTable { /// @notice Request to exit from the stake table, not immediately withdrawable! /// + /// @dev TODO modify this according to the current spec /// @param blsVK The BLS verification key to exit function requestExit(BN254.G2Point memory blsVK) external override { bytes32 key = _hashBlsKey(blsVK); @@ -349,19 +385,53 @@ contract StakeTable is AbstractStakeTable { /// withdraw past their `exitEpoch`. /// /// @param blsVK The BLS verification key to withdraw + /// @param blsSig The BLS signature that authenticates the ethereum account this function is + /// called from the caller /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdrawFunds(BN254.G2Point memory blsVK) external override returns (uint64) { + /// TODO: This function should be tested + /// TODO modify this according to the current spec + + function withdrawFunds(BN254.G2Point memory blsVK, BN254.G1Point memory blsSig) + external + override + returns (uint256) + { bytes32 key = _hashBlsKey(blsVK); Node memory node = nodes[key]; + // Verify that the node is already registered. + if (node.account == address(0)) { + revert NodeNotRegistered(); + } + + // Verify that the balance is greater than zero + uint256 balance = node.balance; + if (balance == 0) { + revert InsufficientStakeBalance(0); + } + + // Verify that the validator can sign for that blsVK + bytes memory message = abi.encode(msg.sender); + BLSSig.verifyBlsSig(message, blsSig, blsVK); + + // Verify that the exit escrow period is over. if (currentEpoch() < node.exitEpoch + exitEscrowPeriod(node)) { revert PrematureWithdrawal(); } - uint64 balance = node.balance; + + // Delete the node from the stake table. delete nodes[key]; + // Transfer the balance to the node's account. SafeTransferLib.safeTransfer(ERC20(tokenAddress), node.account, balance); return balance; } + + /// @notice Minimum stake amount + /// @return Minimum stake amount + /// TODO: This value should be a variable modifiable by admin + function minStakeAmount() public pure returns (uint256) { + return 10 ether; + } } diff --git a/contracts/src/interfaces/AbstractStakeTable.sol b/contracts/src/interfaces/AbstractStakeTable.sol index d5a37ba099..62ff0fc5e3 100644 --- a/contracts/src/interfaces/AbstractStakeTable.sol +++ b/contracts/src/interfaces/AbstractStakeTable.sol @@ -26,11 +26,8 @@ abstract contract AbstractStakeTable { /// @notice Signals a registration of a BLS public key. /// @param blsVKhash hash of the BLS public key that is registered. /// @param registerEpoch epoch when the registration becomes effective. - /// @param stakeType native or restake token. /// @param amountDeposited amount deposited when registering the new node. - event Registered( - bytes32 blsVKhash, uint64 registerEpoch, StakeType stakeType, uint256 amountDeposited - ); + event Registered(bytes32 blsVKhash, uint64 registerEpoch, uint256 amountDeposited); /// @notice Signals an exit request has been granted. /// @param blsVKhash hash of the BLS public key owned by the user who requested to exit. @@ -55,15 +52,13 @@ abstract contract AbstractStakeTable { /// @notice Represents a HotShot validator node /// In the dual-staking model, a HotShot validator could have multiple `Node` entries. /// @param account The Ethereum account of the validator. - /// @param stakeType The type of token staked. /// @param balance The amount of token staked. /// @param registerEpoch The starting epoch for the validator. /// @param exitEpoch The ending epoch for the validator. /// @param schnorrVK The Schnorr verification key associated. struct Node { address account; - StakeType stakeType; - uint64 balance; + uint256 balance; uint64 registerEpoch; uint64 exitEpoch; EdOnBN254.EdOnBN254Point schnorrVK; @@ -71,11 +66,8 @@ abstract contract AbstractStakeTable { // === Table State & Stats === - /// @notice Total stakes of the registered keys in the latest stake table (Head). - /// @return The total stake for native token and restaked token respectively. - function totalStake() external view virtual returns (uint256, uint256); /// @notice Look up the balance of `blsVK` - function lookupStake(BN254.G2Point memory blsVK) external view virtual returns (uint64); + function lookupStake(BN254.G2Point memory blsVK) external view virtual returns (uint256); /// @notice Look up the full `Node` state associated with `blsVK` function lookupNode(BN254.G2Point memory blsVK) external view virtual returns (Node memory); @@ -97,7 +89,6 @@ abstract contract AbstractStakeTable { /// @param blsVK The BLS verification key /// @param schnorrVK The Schnorr verification key (as the auxiliary info) /// @param amount The amount to register - /// @param stakeType The type of staking (native or restaking) /// @param blsSig The BLS signature that authenticates the ethereum account this function is /// called from /// @param validUntilEpoch The maximum epoch the sender is willing to wait to be included @@ -110,8 +101,7 @@ abstract contract AbstractStakeTable { function register( BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK, - uint64 amount, - StakeType stakeType, + uint256 amount, BN254.G1Point memory blsSig, uint64 validUntilEpoch ) external virtual; @@ -121,10 +111,10 @@ abstract contract AbstractStakeTable { /// @param blsVK The BLS verification key /// @param amount The amount to deposit /// @return (newBalance, effectiveEpoch) the new balance effective at a future epoch - function deposit(BN254.G2Point memory blsVK, uint64 amount) + function deposit(BN254.G2Point memory blsVK, uint256 amount) external virtual - returns (uint64, uint64); + returns (uint256, uint64); /// @notice Request to exit from the stake table, not immediately withdrawable! /// @@ -135,6 +125,11 @@ abstract contract AbstractStakeTable { /// withdraw past their `exitEpoch`. /// /// @param blsVK The BLS verification key to withdraw + /// @param blsSig The BLS signature that authenticates the ethereum account this function is + /// called from the caller /// @return The total amount withdrawn, equal to `Node.balance` associated with `blsVK` - function withdrawFunds(BN254.G2Point memory blsVK) external virtual returns (uint64); + function withdrawFunds(BN254.G2Point memory blsVK, BN254.G1Point memory blsSig) + external + virtual + returns (uint256); } diff --git a/contracts/test/StakeTable.t.sol b/contracts/test/StakeTable.t.sol new file mode 100644 index 0000000000..53154850f6 --- /dev/null +++ b/contracts/test/StakeTable.t.sol @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; +// import {console} from "forge-std/console.sol"; + +using stdStorage for StdStorage; + +import { ERC20 } from "solmate/utils/SafeTransferLib.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { BLSSig } from "../src/libraries/BLSSig.sol"; +import { EdOnBN254 } from "../src/libraries/EdOnBn254.sol"; +import { AbstractStakeTable } from "../src/interfaces/AbstractStakeTable.sol"; +import { LightClient } from "../src/LightClient.sol"; +import { LightClientMock } from "../test/mocks/LightClientMock.sol"; + +// Token contract +import { ExampleToken } from "../src/ExampleToken.sol"; + +// Target contract +import { StakeTable as S } from "../src/StakeTable.sol"; + +contract StakeTable_register_Test is Test { + event Registered(bytes32, uint64, uint256); + + S public stakeTable; + ExampleToken public token; + LightClientMock public lcMock; + uint256 public constant INITIAL_BALANCE = 10 ether; + address public exampleTokenCreator; + + function genClientWallet(address sender) + private + returns (BN254.G2Point memory, EdOnBN254.EdOnBN254Point memory, BN254.G1Point memory) + { + // Generate a BLS signature and other values using rust code + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "gen-client-wallet"; + cmds[2] = vm.toString(sender); + cmds[3] = "123"; + + bytes memory result = vm.ffi(cmds); + ( + BN254.G1Point memory blsSig, + BN254.G2Point memory blsVK, + uint256 schnorrVKx, + uint256 schnorrVKy, + ) = abi.decode(result, (BN254.G1Point, BN254.G2Point, uint256, uint256, address)); + + return ( + blsVK, // blsVK + EdOnBN254.EdOnBN254Point(schnorrVKx, schnorrVKy), // schnorrVK + blsSig // sig + ); + } + + function setUp() public { + exampleTokenCreator = makeAddr("tokenCreator"); + vm.prank(exampleTokenCreator); + token = new ExampleToken(INITIAL_BALANCE); + + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "mock-genesis"; + cmds[2] = "5"; + + bytes memory result = vm.ffi(cmds); + ( + LightClientMock.LightClientState memory state, + LightClientMock.StakeTableState memory stakeState + ) = abi.decode(result, (LightClient.LightClientState, LightClient.StakeTableState)); + LightClientMock.LightClientState memory genesis = state; + LightClientMock.StakeTableState memory genesisStakeTableState = stakeState; + + lcMock = new LightClientMock(genesis, genesisStakeTableState, 864000); + address lightClientAddress = address(lcMock); + stakeTable = new S(address(token), lightClientAddress, 10); + } + + function testFuzz_RevertWhen_InvalidBLSSig(uint256 scalar) external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + (BN254.G2Point memory blsVK, EdOnBN254.EdOnBN254Point memory schnorrVK,) = + genClientWallet(exampleTokenCreator); + + // Prepare for the token transfer + vm.startPrank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Ensure the scalar is valid + // Note: Apparently BN254.scalarMul is not well defined when the scalar is 0 + scalar = bound(scalar, 1, BN254.R_MOD - 1); + BN254.validateScalarField(BN254.ScalarField.wrap(scalar)); + BN254.G1Point memory badSig = BN254.scalarMul(BN254.P1(), BN254.ScalarField.wrap(scalar)); + BN254.validateG1Point(badSig); + + // Failed signature verification + vm.expectRevert(BLSSig.BLSSigVerificationFailed.selector); + stakeTable.register(blsVK, schnorrVK, depositAmount, badSig, validUntilEpoch); + vm.stopPrank(); + } + + // commenting out epoch related tests for now + // function testFuzz_RevertWhen_InvalidNextRegistrationEpoch(uint64 rand) external { + // LCMock.setCurrentEpoch(3); + // uint64 currentEpoch = stakeTable.currentEpoch(); + + // uint64 depositAmount = 10 ether; + // vm.prank(exampleTokenCreator); + // token.approve(address(stakeTable), depositAmount); + + // ( + // BN254.G2Point memory blsVK, + // EdOnBN254.EdOnBN254Point memory schnorrVK, + // BN254.G1Point memory sig + // ) = genClientWallet(exampleTokenCreator); + + // // Invalid next registration epoch + // uint64 validUntilEpoch = uint64(bound(rand, 0, currentEpoch - 1)); + // vm.prank(exampleTokenCreator); + // vm.expectRevert( + // abi.encodeWithSelector( + // S.InvalidNextRegistrationEpoch.selector, currentEpoch + 1, validUntilEpoch + // ) + // ); + // stakeTable.register( + // blsVK, + // schnorrVK, + // depositAmount, + // sig, + // validUntilEpoch + // ); + + // // Valid next registration epoch + // validUntilEpoch = uint64(bound(rand, currentEpoch + 1, type(uint64).max)); + // vm.prank(exampleTokenCreator); + // stakeTable.register( + // blsVK, + // schnorrVK, + // depositAmount, + // sig, + // validUntilEpoch + // ); + // } + + function test_RevertWhen_NodeAlreadyRegistered() external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + // Prepare for the token transfer + vm.prank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Successful call to register + vm.prank(exampleTokenCreator); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // The node is already registered + vm.prank(exampleTokenCreator); + vm.expectRevert(S.NodeAlreadyRegistered.selector); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + } + + function test_RevertWhen_NoTokenAllowanceOrBalance() external { + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 10; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + assertEq(ERC20(token).balanceOf(exampleTokenCreator), INITIAL_BALANCE); + vm.prank(exampleTokenCreator); + // The call to register is expected to fail because the depositAmount has not been approved + // and thus the stake table contract cannot lock the stake. + vm.expectRevert(abi.encodeWithSelector(S.InsufficientAllowance.selector, 0, depositAmount)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // A user with 0 balance cannot register either + address newUser = makeAddr("New user with zero balance"); + (blsVK, schnorrVK, sig) = genClientWallet(newUser); + + vm.startPrank(newUser); + // Prepare for the token transfer by giving the StakeTable contract the required allowance + token.approve(address(stakeTable), depositAmount); + vm.expectRevert(abi.encodeWithSelector(S.InsufficientBalance.selector, 0)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + vm.stopPrank(); + } + + function test_RevertWhen_WrongStakeAmount() external { + uint64 depositAmount = 5 ether; + uint64 validUntilEpoch = 10; + + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + assertEq(ERC20(token).balanceOf(exampleTokenCreator), INITIAL_BALANCE); + vm.prank(exampleTokenCreator); + // The call to register is expected to fail because the depositAmount has not been approved + // and thus the stake table contract cannot lock the stake. + vm.expectRevert(abi.encodeWithSelector(S.InsufficientStakeAmount.selector, depositAmount)); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + } + + /// @dev Tests a correct registration + function test_Registration_succeeds() external { + ( + BN254.G2Point memory blsVK, + EdOnBN254.EdOnBN254Point memory schnorrVK, + BN254.G1Point memory sig + ) = genClientWallet(exampleTokenCreator); + + uint64 depositAmount = 10 ether; + uint64 validUntilEpoch = 5; + + // Prepare for the token transfer + vm.prank(exampleTokenCreator); + token.approve(address(stakeTable), depositAmount); + + // Balances before registration + assertEq(token.balanceOf(exampleTokenCreator), INITIAL_BALANCE); + + uint256 totalStakeAmount; + totalStakeAmount = stakeTable.totalStake(); + assertEq(totalStakeAmount, 0); + + AbstractStakeTable.Node memory node; + node.account = exampleTokenCreator; + node.balance = depositAmount; + node.schnorrVK = schnorrVK; + node.registerEpoch = 1; + + // Check event is emitted after calling successfully `register` + vm.expectEmit(false, false, false, true, address(stakeTable)); + emit Registered(stakeTable._hashBlsKey(blsVK), node.registerEpoch, node.balance); + vm.prank(exampleTokenCreator); + stakeTable.register(blsVK, schnorrVK, depositAmount, sig, validUntilEpoch); + + // Balance after registration + assertEq(token.balanceOf(exampleTokenCreator), INITIAL_BALANCE - depositAmount); + totalStakeAmount = stakeTable.totalStake(); + assertEq(totalStakeAmount, depositAmount); + } +} From 624f5ca6ed2a0595db047670644910388760a427 Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 16:29:52 -0300 Subject: [PATCH 44/58] add TODO --- types/src/v0/impls/l1.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index 28bbb9f958..c981a61b08 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -792,6 +792,7 @@ impl L1Client { ) -> Vec<::StakeTableEntry> { // TODO we either need address from configuration or contract-bindings. // TODO epoch size may need to be passed in as well + // TODO here or in memberships check if we have fetched table this epoch unimplemented!(); } } From a6afc752ff1b0113210e3e96dbcf3d25520bfd64 Mon Sep 17 00:00:00 2001 From: tbro Date: Fri, 6 Dec 2024 19:02:16 -0300 Subject: [PATCH 45/58] fetch events from l1 --- types/src/v0/impls/l1.rs | 56 ++++++++++++++++++++++--------- types/src/v0/impls/stake_table.rs | 24 +++++++++++-- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/types/src/v0/impls/l1.rs b/types/src/v0/impls/l1.rs index c981a61b08..2279a1ff3c 100644 --- a/types/src/v0/impls/l1.rs +++ b/types/src/v0/impls/l1.rs @@ -10,7 +10,10 @@ use anyhow::{bail, Context}; use async_trait::async_trait; use clap::Parser; use committable::{Commitment, Committable, RawCommitmentBuilder}; -use contract_bindings::fee_contract::FeeContract; +use contract_bindings::{ + fee_contract::FeeContract, + permissioned_stake_table::{NodeInfo, PermissionedStakeTable, StakersUpdatedFilter}, +}; use ethers::{ prelude::{Address, BlockNumber, Middleware, Provider, H256, U256}, providers::{Http, JsonRpcClient, ProviderError, PubsubClient, Ws, WsClientError}, @@ -20,6 +23,7 @@ use futures::{ stream::{self, StreamExt}, }; use hotshot::types::SignatureKey; +use hotshot_contract_adapter::stake_table::NodeInfoJf; use hotshot_types::{ stake_table::StakeTableEntry, traits::{metrics::Metrics, node_implementation::NodeType}, @@ -34,7 +38,7 @@ use tokio::{ use tracing::Instrument; use url::Url; -use super::{L1BlockInfo, L1ClientMetrics, L1State, L1UpdateTask, RpcClient}; +use super::{L1BlockInfo, L1ClientMetrics, L1State, L1UpdateTask, PubKey, RpcClient, SeqTypes}; use crate::{FeeInfo, L1Client, L1ClientOptions, L1Event, L1ReconnectTask, L1Snapshot}; impl PartialOrd for L1BlockInfo { @@ -788,12 +792,20 @@ impl L1Client { pub async fn get_stake_table( &self, _block: u64, - _address: Address, - ) -> Vec<::StakeTableEntry> { - // TODO we either need address from configuration or contract-bindings. + address: Address, + ) -> Vec { // TODO epoch size may need to be passed in as well // TODO here or in memberships check if we have fetched table this epoch - unimplemented!(); + dbg!(&address); + let stake_table_contract = PermissionedStakeTable::new(address, self.provider.clone()); + + let events = stake_table_contract + .stakers_updated_filter() + .query() + .await + .unwrap(); + dbg!(&events); + events } } @@ -852,7 +864,10 @@ async fn get_finalized_block(rpc: &Provider) -> anyhow::Result