From bb6a407fb9b89a66f7ea60108ebe76e72b75ce7c Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 10 Jun 2023 21:48:54 +1000 Subject: [PATCH 01/58] add unnamed using flipper template --- dapps/xcm/unnamed/.gitignore | 9 +++ dapps/xcm/unnamed/Cargo.toml | 27 +++++++ dapps/xcm/unnamed/lib.rs | 142 +++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100755 dapps/xcm/unnamed/.gitignore create mode 100755 dapps/xcm/unnamed/Cargo.toml create mode 100755 dapps/xcm/unnamed/lib.rs diff --git a/dapps/xcm/unnamed/.gitignore b/dapps/xcm/unnamed/.gitignore new file mode 100755 index 0000000..8de8f87 --- /dev/null +++ b/dapps/xcm/unnamed/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/dapps/xcm/unnamed/Cargo.toml b/dapps/xcm/unnamed/Cargo.toml new file mode 100755 index 0000000..4b6cceb --- /dev/null +++ b/dapps/xcm/unnamed/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "unnamed" +version = "0.1.0" +authors = ["[your_name] <[your_email]>"] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs new file mode 100755 index 0000000..15c10cc --- /dev/null +++ b/dapps/xcm/unnamed/lib.rs @@ -0,0 +1,142 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod unnamed { + + /// Defines the storage of your contract. + /// Add new fields to the below struct in order + /// to add new static storage fields to your contract. + #[ink(storage)] + pub struct Unnamed { + /// Stores a single `bool` value on the storage. + value: bool, + } + + impl Unnamed { + /// Constructor that initializes the `bool` value to the given `init_value`. + #[ink(constructor)] + pub fn new(init_value: bool) -> Self { + Self { value: init_value } + } + + /// Constructor that initializes the `bool` value to `false`. + /// + /// Constructors can delegate to other constructors. + #[ink(constructor)] + pub fn default() -> Self { + Self::new(Default::default()) + } + + /// A message that can be called on instantiated contracts. + /// This one flips the value of the stored `bool` from `true` + /// to `false` and vice versa. + #[ink(message)] + pub fn flip(&mut self) { + self.value = !self.value; + } + + /// Simply returns the current value of our `bool`. + #[ink(message)] + pub fn get(&self) -> bool { + self.value + } + } + + /// Unit tests in Rust are normally defined within such a `#[cfg(test)]` + /// module and test functions are marked with a `#[test]` attribute. + /// The below code is technically just normal Rust code. + #[cfg(test)] + mod tests { + /// Imports all the definitions from the outer scope so we can use them here. + use super::*; + + /// We test if the default constructor does its job. + #[ink::test] + fn default_works() { + let unnamed = Unnamed::default(); + assert_eq!(unnamed.get(), false); + } + + /// We test a simple use case of our contract. + #[ink::test] + fn it_works() { + let mut unnamed = Unnamed::new(false); + assert_eq!(unnamed.get(), false); + unnamed.flip(); + assert_eq!(unnamed.get(), true); + } + } + + + /// This is how you'd write end-to-end (E2E) or integration tests for ink! contracts. + /// + /// When running these you need to make sure that you: + /// - Compile the tests with the `e2e-tests` feature flag enabled (`--features e2e-tests`) + /// - Are running a Substrate node which contains `pallet-contracts` in the background + #[cfg(all(test, feature = "e2e-tests"))] + mod e2e_tests { + /// Imports all the definitions from the outer scope so we can use them here. + use super::*; + + /// A helper function used for calling contract messages. + use ink_e2e::build_message; + + /// The End-to-End test `Result` type. + type E2EResult = std::result::Result>; + + /// We test that we can upload and instantiate the contract using its default constructor. + #[ink_e2e::test] + async fn default_works(mut client: ink_e2e::Client) -> E2EResult<()> { + // Given + let constructor = UnnamedRef::default(); + + // When + let contract_account_id = client + .instantiate("unnamed", &ink_e2e::alice(), constructor, 0, None) + .await + .expect("instantiate failed") + .account_id; + + // Then + let get = build_message::(contract_account_id.clone()) + .call(|unnamed| unnamed.get()); + let get_result = client.call_dry_run(&ink_e2e::alice(), &get, 0, None).await; + assert!(matches!(get_result.return_value(), false)); + + Ok(()) + } + + /// We test that we can read and write a value from the on-chain contract contract. + #[ink_e2e::test] + async fn it_works(mut client: ink_e2e::Client) -> E2EResult<()> { + // Given + let constructor = UnnamedRef::new(false); + let contract_account_id = client + .instantiate("unnamed", &ink_e2e::bob(), constructor, 0, None) + .await + .expect("instantiate failed") + .account_id; + + let get = build_message::(contract_account_id.clone()) + .call(|unnamed| unnamed.get()); + let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; + assert!(matches!(get_result.return_value(), false)); + + // When + let flip = build_message::(contract_account_id.clone()) + .call(|unnamed| unnamed.flip()); + let _flip_result = client + .call(&ink_e2e::bob(), flip, 0, None) + .await + .expect("flip failed"); + + // Then + let get = build_message::(contract_account_id.clone()) + .call(|unnamed| unnamed.get()); + let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; + assert!(matches!(get_result.return_value(), true)); + + Ok(()) + } + } +} From 231d7ae066cc09a3d233f7741dd4d2f7e16f1b39 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 11 Jun 2023 20:49:12 +1000 Subject: [PATCH 02/58] wip --- dapps/xcm/unnamed/README.md | 0 dapps/xcm/unnamed/lib.rs | 30 ++++- dapps/xcm/unnamed/oracle_contract/.gitignore | 9 ++ dapps/xcm/unnamed/oracle_contract/Cargo.toml | 27 ++++ dapps/xcm/unnamed/oracle_contract/lib.rs | 130 +++++++++++++++++++ 5 files changed, 193 insertions(+), 3 deletions(-) create mode 100644 dapps/xcm/unnamed/README.md create mode 100644 dapps/xcm/unnamed/oracle_contract/.gitignore create mode 100644 dapps/xcm/unnamed/oracle_contract/Cargo.toml create mode 100644 dapps/xcm/unnamed/oracle_contract/lib.rs diff --git a/dapps/xcm/unnamed/README.md b/dapps/xcm/unnamed/README.md new file mode 100644 index 0000000..e69de29 diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 15c10cc..60195d5 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -2,6 +2,7 @@ #[ink::contract] mod unnamed { + use oracle_contract::OracleContractRef; /// Defines the storage of your contract. /// Add new fields to the below struct in order @@ -10,13 +11,29 @@ mod unnamed { pub struct Unnamed { /// Stores a single `bool` value on the storage. value: bool, + /// Store a reference to the `OracleContract`. + oracle_contract: OracleContractRef, } impl Unnamed { - /// Constructor that initializes the `bool` value to the given `init_value`. + /// Constructor that: + /// * Instantiates the OracleContract using its uploaded `code_hash` + /// * Initializes the `bool` value to the given `init_value`. #[ink(constructor)] - pub fn new(init_value: bool) -> Self { - Self { value: init_value } + pub fn new( + oracle_contract_code_hash: Hash, + init_value: bool + ) -> Self { + let oracle_contract = OracleContractRef::new(true) + .code_hash(oracle_contract_code_hash) + .endowment(0) + .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) + .instantiate(); + + Self { + oracle_contract, + value: init_value, + } } /// Constructor that initializes the `bool` value to `false`. @@ -40,6 +57,13 @@ mod unnamed { pub fn get(&self) -> bool { self.value } + + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` + #[ink(message)] + pub fn flip_and_get(&mut self) -> bool { + self.oracle_contract.flip(); + self.oracle_contract.get() + } } /// Unit tests in Rust are normally defined within such a `#[cfg(test)]` diff --git a/dapps/xcm/unnamed/oracle_contract/.gitignore b/dapps/xcm/unnamed/oracle_contract/.gitignore new file mode 100644 index 0000000..8de8f87 --- /dev/null +++ b/dapps/xcm/unnamed/oracle_contract/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/dapps/xcm/unnamed/oracle_contract/Cargo.toml b/dapps/xcm/unnamed/oracle_contract/Cargo.toml new file mode 100644 index 0000000..f942b47 --- /dev/null +++ b/dapps/xcm/unnamed/oracle_contract/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "oracle_contract" +version = "0.1.0" +authors = ["[your_name] <[your_email]>"] +edition = "2021" + +[dependencies] +ink = { version = "4.2.0", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = "4.2.0" + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs new file mode 100644 index 0000000..4723e31 --- /dev/null +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -0,0 +1,130 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +pub use self::oracle_contract::OracleContractRef; + +#[ink::contract] +mod oracle_contract { + use ink::prelude::vec::Vec; + use ink::storage::{ + Lazy, + Mapping, + traits::ManualKey, + }; + + /// A block number. + pub type BlockNumber = u64; + pub type MarketGuessId = String; + pub type OracleOwner = AccountId; + pub type BlockNumberEntropy = BlockNumber; + + pub enum Status { + Pending, + Finalized, + } + + pub struct MarketGuess { + /// Market guess id. + id_market: MarketGuessId, + /// Block number when market guesses were made. + block_number_guessed: BlockNumber, + /// Block number in the future to use the block hash of for entropy. + block_number_entropy: BlockNumber, + /// Block hash associated with `block_number_entropy` when finalized + /// to use for entropy. + block_hash_entropy: Hash, + /// Market guess period end block number + block_number_end: BlockNumber, + /// Market guess finalization status. + status: Status, + } + + #[derive(Default)] + #[ink(storage)] + pub struct OracleContract { + /// Assign an owner and block number for entropy to every market guess id. + market_data: Mapping>, + /// Enforce non-`Packed` storage layout since vector may get large + /// and expensive to work with. + /// Lazy fields like `market_guesses` provide `get()` and `set()` + /// storage operators. + market_guesses: Lazy>, + } + + impl OracleContract { + #[ink(constructor)] + pub fn new( + id_market: MarketGuessId, + block_number_guessed: BlockNumber, + block_number_entropy: BlockNumber, + block_number_end: BlockNumber, + ) -> Self { + let mut instance = Self::default(); + let caller: OracleOwner = Self.env().caller(); + let market_data = Mapping::default(); + assert!(self.exists_market_data_for_id, "unable to find market data for given id"); + let block_number_current: Self::env().block_number(); + // TODO - we need to verify that the block hash exists for the block number + // when they say guessing occurred + assert!( + block_number_current > block_number_guessed, + "block number when guessing occurred must be before the current block number" + ); + // TODO - 100 is a magic number + assert!( + block_number_entropy - block_number_current > 100, + "block used for entropy must allow sufficient block confirmations after the current \ + block and block when guessing occurred for assurance that epoch gets finalized \ + incase head susceptible to reorganization for safety" + ); + // TODO - 200 is a magic number + assert!( + block_number_end - block_number_entropy > 200, + "block when market ends must be allow sufficient block confirmations after the \ + block used for entropy" + ); + + instance.market_data.insert(&id_market, (&caller, &block_number_entropy))); + let new_market_guess = MarketGuess { + id_market, + block_number_guessed, + block_number_entropy, + block_hash_entropy: Default::default(), + block_number_end, + status: Status::Pending, + }; + let mut market_guesses = self.market_guesses.get_or_default(); + market_guesses.push(new_market_guess); + self.market_guesses.set(&market_guesses); + instance + } + + // #[ink(message)] + // pub fn set_block_number_guessed(&mut self, block_number) { + // self.block_number_guessed = block_number; + // } + // #[ink(message)] + // pub fn get_block_number_guessed(&self) -> BlockNumber { + // self.block_number_guessed + // } + // assert!(caller == owner, "caller is not owner") + + #[ink(message)] + pub fn set_block_hash_entropy_for_market_id( + &mut self, + id_market: MarketGuessId, + block_hash_entropy: Hash, + ) { + self.block_number_guessed = block_number; + } + + #[ink(message)] + pub fn get_block_hash_entropy_for_market_id(&self, id_market) -> BlockNumber { + self.block_number_guessed + } + + // helper methods + fn exists_market_data_for_id(id_market: MarketGuessId) -> bool { + self.market_data.get(id_market).is_some() + } + } +} From 8fdf3bb07abde18fcf2124cd5835bb061d68a4ad Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 12 Jun 2023 03:38:42 +1000 Subject: [PATCH 03/58] wip --- Cargo.lock | 21 +++ Cargo.toml | 1 + .../wasm-flipper/contract/flipper/Cargo.toml | 2 +- dapps/xcm/unnamed/Cargo.toml | 6 +- dapps/xcm/unnamed/README.md | 5 + dapps/xcm/unnamed/lib.rs | 16 +- dapps/xcm/unnamed/oracle_contract/Cargo.toml | 5 +- dapps/xcm/unnamed/oracle_contract/lib.rs | 170 +++++++++++++----- 8 files changed, 161 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4af7305..90698e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2267,6 +2267,16 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "oracle_contract" +version = "0.1.0" +dependencies = [ + "ink", + "ink_e2e", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-contracts-primitives" version = "23.0.0" @@ -4093,6 +4103,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unnamed" +version = "0.1.0" +dependencies = [ + "ink", + "ink_e2e", + "oracle_contract", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "untrusted" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index 861f543..cb11d89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ exclude = [] members = [ "dapps/ink-rust/wasm-flipper/contract/flipper", + "dapps/xcm/unnamed", ] diff --git a/dapps/ink-rust/wasm-flipper/contract/flipper/Cargo.toml b/dapps/ink-rust/wasm-flipper/contract/flipper/Cargo.toml index 3802f2d..61dd1c0 100755 --- a/dapps/ink-rust/wasm-flipper/contract/flipper/Cargo.toml +++ b/dapps/ink-rust/wasm-flipper/contract/flipper/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" # https://github.com/paritytech/ink/releases ink = { version = "4.2.0", default-features = false } -scale = { package = "parity-scale-codec", version = "3.4.0", default-features = false, features = ["derive"] } +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } [dev-dependencies] diff --git a/dapps/xcm/unnamed/Cargo.toml b/dapps/xcm/unnamed/Cargo.toml index 4b6cceb..111f562 100755 --- a/dapps/xcm/unnamed/Cargo.toml +++ b/dapps/xcm/unnamed/Cargo.toml @@ -7,8 +7,10 @@ edition = "2021" [dependencies] ink = { version = "4.2.0", default-features = false } -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } + +oracle_contract = { path = "oracle_contract", default-features = false, features = ["ink-as-dependency"] } [dev-dependencies] ink_e2e = "4.2.0" diff --git a/dapps/xcm/unnamed/README.md b/dapps/xcm/unnamed/README.md index e69de29..c4114c5 100644 --- a/dapps/xcm/unnamed/README.md +++ b/dapps/xcm/unnamed/README.md @@ -0,0 +1,5 @@ +``` +rustup update +rustup default stable +rustup show +``` \ No newline at end of file diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 60195d5..fe4e1f0 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -9,20 +9,15 @@ mod unnamed { /// to add new static storage fields to your contract. #[ink(storage)] pub struct Unnamed { - /// Stores a single `bool` value on the storage. - value: bool, /// Store a reference to the `OracleContract`. oracle_contract: OracleContractRef, } impl Unnamed { - /// Constructor that: - /// * Instantiates the OracleContract using its uploaded `code_hash` - /// * Initializes the `bool` value to the given `init_value`. + /// Constructor that instantiates the OracleContract using its uploaded `code_hash` #[ink(constructor)] pub fn new( oracle_contract_code_hash: Hash, - init_value: bool ) -> Self { let oracle_contract = OracleContractRef::new(true) .code_hash(oracle_contract_code_hash) @@ -32,18 +27,9 @@ mod unnamed { Self { oracle_contract, - value: init_value, } } - /// Constructor that initializes the `bool` value to `false`. - /// - /// Constructors can delegate to other constructors. - #[ink(constructor)] - pub fn default() -> Self { - Self::new(Default::default()) - } - /// A message that can be called on instantiated contracts. /// This one flips the value of the stored `bool` from `true` /// to `false` and vice versa. diff --git a/dapps/xcm/unnamed/oracle_contract/Cargo.toml b/dapps/xcm/unnamed/oracle_contract/Cargo.toml index f942b47..a8d28c1 100644 --- a/dapps/xcm/unnamed/oracle_contract/Cargo.toml +++ b/dapps/xcm/unnamed/oracle_contract/Cargo.toml @@ -6,9 +6,10 @@ edition = "2021" [dependencies] ink = { version = "4.2.0", default-features = false } +# hex = { version = "0.4.3", default-features = false } -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true } +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } [dev-dependencies] ink_e2e = "4.2.0" diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 4723e31..c562d57 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -4,27 +4,66 @@ pub use self::oracle_contract::OracleContractRef; #[ink::contract] mod oracle_contract { + use ink::prelude::string::String; use ink::prelude::vec::Vec; use ink::storage::{ Lazy, Mapping, - traits::ManualKey, + // traits::ManualKey, }; + use ink::storage::traits::{ + StorableHint, + StorageKey, + Storable, + }; + // use core::str; + // use hex; - /// A block number. - pub type BlockNumber = u64; - pub type MarketGuessId = String; + pub type MarketGuessId = Vec; pub type OracleOwner = AccountId; - pub type BlockNumberEntropy = BlockNumber; - pub enum Status { - Pending, - Finalized, + /// Emitted when create new market guess for market id. + #[ink(event)] + pub struct NewOracleMarketGuessForMarketId { + #[ink(topic)] + id_market: MarketGuessId, + #[ink(topic)] + oracle_owner: OracleOwner, + #[ink(topic)] + block_number_guessed: BlockNumber, + #[ink(topic)] + block_number_entropy: BlockNumber, + // #[ink(topic)] + block_number_end: BlockNumber, } + /// Emitted when set block hash entropy for market id. + #[ink(event)] + pub struct SetBlockHashEntropyForMarketId { + #[ink(topic)] + id_market: MarketGuessId, + oracle_owner: OracleOwner, + #[ink(topic)] + block_number_entropy: BlockNumber, + #[ink(topic)] + block_hash_entropy: Hash, + } + + // https://docs.rs/ink/latest/ink/attr.storage_item.html + // Non-packed types like `Mapping` require calculating the storage key during compilation + // and it is best to rely on automatic storage key calculation via `ink::storage_item` + // and must be called before `derive` + #[derive(scale::Decode, scale::Encode)] + #[cfg_attr( + feature = "std", + derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout) + )] + #[derive(Default, Debug)] pub struct MarketGuess { /// Market guess id. id_market: MarketGuessId, + /// Oracle account owner + oracle_owner: OracleOwner, /// Block number when market guesses were made. block_number_guessed: BlockNumber, /// Block number in the future to use the block hash of for entropy. @@ -34,22 +73,28 @@ mod oracle_contract { block_hash_entropy: Hash, /// Market guess period end block number block_number_end: BlockNumber, - /// Market guess finalization status. - status: Status, } #[derive(Default)] #[ink(storage)] pub struct OracleContract { /// Assign an owner and block number for entropy to every market guess id. - market_data: Mapping>, - /// Enforce non-`Packed` storage layout since vector may get large - /// and expensive to work with. - /// Lazy fields like `market_guesses` provide `get()` and `set()` - /// storage operators. - market_guesses: Lazy>, + market_data: Mapping, // , ManualKey<123> + } + + /// Errors that can occur upon calling this contract. + #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] + #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] + pub enum Error { + /// Returned if the no data exists for given market guess id. + NoDataForMarketGuessId, + /// Returned if caller is not oracle owner of market guess id. + CallerIsNotOracleOwner, } + /// Type alias for the contract's result type. + pub type Result = core::result::Result; + impl OracleContract { #[ink(constructor)] pub fn new( @@ -59,72 +104,107 @@ mod oracle_contract { block_number_end: BlockNumber, ) -> Self { let mut instance = Self::default(); - let caller: OracleOwner = Self.env().caller(); + let oracle_owner: OracleOwner = instance.env().caller(); let market_data = Mapping::default(); - assert!(self.exists_market_data_for_id, "unable to find market data for given id"); - let block_number_current: Self::env().block_number(); + assert!(instance.exists_market_data_for_id(id_market), "unable to find market data for given id"); + let block_number_current = Self::env().block_number(); // TODO - we need to verify that the block hash exists for the block number // when they say guessing occurred assert!( block_number_current > block_number_guessed, "block number when guessing occurred must be before the current block number" ); - // TODO - 100 is a magic number + // TODO - 100 and 200 are magic numbers, need something more meaningful assert!( block_number_entropy - block_number_current > 100, "block used for entropy must allow sufficient block confirmations after the current \ block and block when guessing occurred for assurance that epoch gets finalized \ incase head susceptible to reorganization for safety" ); - // TODO - 200 is a magic number assert!( block_number_end - block_number_entropy > 200, "block when market ends must be allow sufficient block confirmations after the \ block used for entropy" ); - - instance.market_data.insert(&id_market, (&caller, &block_number_entropy))); let new_market_guess = MarketGuess { id_market, + oracle_owner, block_number_guessed, block_number_entropy, block_hash_entropy: Default::default(), block_number_end, - status: Status::Pending, }; - let mut market_guesses = self.market_guesses.get_or_default(); - market_guesses.push(new_market_guess); - self.market_guesses.set(&market_guesses); + instance.market_data.insert(&id_market, &new_market_guess); + self.env().emit_event(NewOracleMarketGuessForMarketId { + id_market, + oracle_owner, + block_number_guessed, + block_number_entropy, + block_number_end, + }); instance } - // #[ink(message)] - // pub fn set_block_number_guessed(&mut self, block_number) { - // self.block_number_guessed = block_number; - // } - // #[ink(message)] - // pub fn get_block_number_guessed(&self) -> BlockNumber { - // self.block_number_guessed - // } - // assert!(caller == owner, "caller is not owner") - #[ink(message)] pub fn set_block_hash_entropy_for_market_id( &mut self, id_market: MarketGuessId, block_hash_entropy: Hash, - ) { - self.block_number_guessed = block_number; + ) -> Result<()> { + let caller: AccountId = self.env().caller(); + // assert!(self.exists_market_data_for_id(id_market), "unable to find market data for given id"); + let market_guess = match self.market_data.get(id_market) { + Some(data) => data, + None => return Err(Error::NoDataForMarketGuessId), + }; + // singleton change of block hash entropy from the default value set at instantiation of the contract + assert!(market_guess.block_hash_entropy == Default::default(), "unable to set block hash entropy for market id once"); + if market_guess.oracle_owner != caller { + return Err(Error::CallerIsNotOracleOwner) + } + let new_market_guess = MarketGuess { + block_hash_entropy, + ..market_guess + }; + self.market_data.insert(&id_market, &new_market_guess); + self.env().emit_event(SetBlockHashEntropyForMarketId { + id_market, + oracle_owner: caller, + block_number_entropy: market_guess.block_number_entropy, + block_hash_entropy, + }); + Ok(()) } - #[ink(message)] - pub fn get_block_hash_entropy_for_market_id(&self, id_market) -> BlockNumber { - self.block_number_guessed - } + // #[ink(message)] + // // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber, ????) { + // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber) { + // let market_guess = match self.market_data.get(id_market) { + // Some(data) => data, + // None => return Err(Error::NoDataForMarketGuessId), + // }; + // assert!(market_guess.block_hash_entropy != Default::default(), "block hash entropy must be set prior to obtaining entropy"); + // let block_number_entropy = market_guess.block_number_entropy; + // let block_hash_entropy = market_guess.block_hash_entropy; + + // let entropy = block_hash_entropy.replace(&["0x"][..], ""); + // let str = decode(entropy); + // let buffer = <[u8; 12]>::from_hex(entropy)?; + // let str = str::from_utf8(&buffer).expect("invalid buffer length"); + // let sub = &str[..5]; + // ink::env::debug_println!("sub: {}\n", sub); + + // generate random number from block hash + // don't allow them to use the default value for the random number, they need to have set the + // block hash entropy to a block hash + + // (block_number_entropy, block_hash_entropy, ???) + // (block_number_entropy, block_hash_entropy) + // } // helper methods - fn exists_market_data_for_id(id_market: MarketGuessId) -> bool { - self.market_data.get(id_market).is_some() + fn exists_market_data_for_id(&self, id_market: MarketGuessId) -> bool { + self.market_data.contains(id_market) } } } From 3faf53ee587db183cd165b48e5f55004af73fddd Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 12 Jun 2023 05:31:16 +1000 Subject: [PATCH 04/58] resolve some errors --- dapps/xcm/unnamed/lib.rs | 59 ++++++++++++++++-------- dapps/xcm/unnamed/oracle_contract/lib.rs | 34 ++++++++------ 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index fe4e1f0..d86449f 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -4,51 +4,70 @@ mod unnamed { use oracle_contract::OracleContractRef; + use ink::prelude::vec::Vec; + + // refactor into types file + pub type MarketGuessId = Vec; + pub type OracleOwner = AccountId; + /// Defines the storage of your contract. /// Add new fields to the below struct in order /// to add new static storage fields to your contract. + #[derive(Default)] #[ink(storage)] pub struct Unnamed { /// Store a reference to the `OracleContract`. - oracle_contract: OracleContractRef, + oracle_contract: Option, + owner: Option, + } + + /// Errors that can occur upon calling this contract. + #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] + #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] + pub enum Error { + /// Returned if not oracle contract address exists. + NoOracleContractAddress, } + /// Type alias for the contract's result type. + pub type Result = core::result::Result; + impl Unnamed { /// Constructor that instantiates the OracleContract using its uploaded `code_hash` #[ink(constructor)] pub fn new( oracle_contract_code_hash: Hash, + id_market: MarketGuessId, + block_number_guessed: BlockNumber, + block_number_entropy: BlockNumber, + block_number_end: BlockNumber, ) -> Self { - let oracle_contract = OracleContractRef::new(true) + let instance = Self::default(); + let caller = instance.env().caller(); + let oracle_contract = OracleContractRef::new( + id_market, + block_number_guessed, + block_number_entropy, + block_number_end, + ) .code_hash(oracle_contract_code_hash) .endowment(0) .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); Self { - oracle_contract, + oracle_contract: Some(oracle_contract), + owner: Some(caller), } } - /// A message that can be called on instantiated contracts. - /// This one flips the value of the stored `bool` from `true` - /// to `false` and vice versa. - #[ink(message)] - pub fn flip(&mut self) { - self.value = !self.value; - } - - /// Simply returns the current value of our `bool`. - #[ink(message)] - pub fn get(&self) -> bool { - self.value - } - /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] - pub fn flip_and_get(&mut self) -> bool { - self.oracle_contract.flip(); - self.oracle_contract.get() + pub fn get_oracle_contract_address(&self) -> Result { + match &self.oracle_contract { + Some(c) => Ok(c.get_oracle_contract_address()), + None => return Err(Error::NoOracleContractAddress), + } } } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index c562d57..320e3a2 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -19,6 +19,7 @@ mod oracle_contract { // use core::str; // use hex; + // refactor into types file pub type MarketGuessId = Vec; pub type OracleOwner = AccountId; @@ -63,7 +64,7 @@ mod oracle_contract { /// Market guess id. id_market: MarketGuessId, /// Oracle account owner - oracle_owner: OracleOwner, + oracle_owner: Option, /// Block number when market guesses were made. block_number_guessed: BlockNumber, /// Block number in the future to use the block hash of for entropy. @@ -104,9 +105,8 @@ mod oracle_contract { block_number_end: BlockNumber, ) -> Self { let mut instance = Self::default(); - let oracle_owner: OracleOwner = instance.env().caller(); - let market_data = Mapping::default(); - assert!(instance.exists_market_data_for_id(id_market), "unable to find market data for given id"); + let caller = instance.env().caller(); + assert!(instance.exists_market_data_for_id(id_market.clone()), "unable to find market data for given id"); let block_number_current = Self::env().block_number(); // TODO - we need to verify that the block hash exists for the block number // when they say guessing occurred @@ -127,17 +127,19 @@ mod oracle_contract { block used for entropy" ); let new_market_guess = MarketGuess { - id_market, - oracle_owner, + id_market: id_market.clone(), + // must be set to Option to avoid error: + // the trait `Default` is not implemented for `ink::ink_primitives::AccountId` + oracle_owner: Some(caller), block_number_guessed, block_number_entropy, block_hash_entropy: Default::default(), block_number_end, }; instance.market_data.insert(&id_market, &new_market_guess); - self.env().emit_event(NewOracleMarketGuessForMarketId { - id_market, - oracle_owner, + instance.env().emit_event(NewOracleMarketGuessForMarketId { + id_market: id_market.clone(), + oracle_owner: caller, block_number_guessed, block_number_entropy, block_number_end, @@ -153,22 +155,23 @@ mod oracle_contract { ) -> Result<()> { let caller: AccountId = self.env().caller(); // assert!(self.exists_market_data_for_id(id_market), "unable to find market data for given id"); - let market_guess = match self.market_data.get(id_market) { + // TODO - convert Vec to &str to avoid use of .clone() + let market_guess = match self.market_data.get(id_market.clone()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; // singleton change of block hash entropy from the default value set at instantiation of the contract assert!(market_guess.block_hash_entropy == Default::default(), "unable to set block hash entropy for market id once"); - if market_guess.oracle_owner != caller { + if market_guess.oracle_owner != Some(caller) { return Err(Error::CallerIsNotOracleOwner) } let new_market_guess = MarketGuess { block_hash_entropy, ..market_guess }; - self.market_data.insert(&id_market, &new_market_guess); + self.market_data.insert(id_market.clone(), &new_market_guess); self.env().emit_event(SetBlockHashEntropyForMarketId { - id_market, + id_market: id_market.clone(), oracle_owner: caller, block_number_entropy: market_guess.block_number_entropy, block_hash_entropy, @@ -176,6 +179,11 @@ mod oracle_contract { Ok(()) } + #[ink(message)] + pub fn get_oracle_contract_address(&self) -> AccountId { + self.env().account_id() + } + // #[ink(message)] // // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber, ????) { // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber) { From e5e7720cf81c80bfa78f70a103d1f0b9341a9915 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 12 Jun 2023 11:07:09 +1000 Subject: [PATCH 05/58] fix all errors --- dapps/xcm/unnamed/Cargo.toml | 5 +++++ dapps/xcm/unnamed/README.md | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/dapps/xcm/unnamed/Cargo.toml b/dapps/xcm/unnamed/Cargo.toml index 111f562..7fa05f9 100755 --- a/dapps/xcm/unnamed/Cargo.toml +++ b/dapps/xcm/unnamed/Cargo.toml @@ -24,6 +24,11 @@ std = [ "ink/std", "scale/std", "scale-info/std", + + # Note: The metadata generation step requires `std`. If we don't specify this the metadata + # generation for our contract will fail with error: + # the trait bound `OracleContractRef: StorageLayout` is not satisfied + "oracle_contract/std", ] ink-as-dependency = [] e2e-tests = [] diff --git a/dapps/xcm/unnamed/README.md b/dapps/xcm/unnamed/README.md index c4114c5..af380dd 100644 --- a/dapps/xcm/unnamed/README.md +++ b/dapps/xcm/unnamed/README.md @@ -1,5 +1,16 @@ +* Install latest Cargo Contract version +* Install Rustup 1.69. See https://github.com/paritytech/cargo-contract/blob/master/.github/workflows/ci.yml#L185. If you do not use 1.69 you will get error `ERROR: Loading of original wasm failed` when running `cargo contract build` ``` rustup update rustup default stable +rustup install 1.69 +rustup default 1.69 +rustup override set 1.69 +rustup component add rust-src --toolchain 1.69 +rustup toolchain list rustup show +``` +* Run +``` +cargo contract build --manifest-path ./dapps/xcm/unnamed/Cargo.toml ``` \ No newline at end of file From 14b04a5d917721bb7c5e8d843de1b51c9e8c869e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 12 Jun 2023 20:12:59 +1000 Subject: [PATCH 06/58] use raw bytes instead of hash type so can access length of block hash --- dapps/xcm/unnamed/oracle_contract/lib.rs | 89 +++++++++++++++--------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 320e3a2..aef8be2 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -47,7 +47,7 @@ mod oracle_contract { #[ink(topic)] block_number_entropy: BlockNumber, #[ink(topic)] - block_hash_entropy: Hash, + block_hash_entropy: Option<[u8; 32]>, // Hash } // https://docs.rs/ink/latest/ink/attr.storage_item.html @@ -71,7 +71,7 @@ mod oracle_contract { block_number_entropy: BlockNumber, /// Block hash associated with `block_number_entropy` when finalized /// to use for entropy. - block_hash_entropy: Hash, + block_hash_entropy: Option<[u8; 32]>, // Hash /// Market guess period end block number block_number_end: BlockNumber, } @@ -133,7 +133,7 @@ mod oracle_contract { oracle_owner: Some(caller), block_number_guessed, block_number_entropy, - block_hash_entropy: Default::default(), + block_hash_entropy: None, block_number_end, }; instance.market_data.insert(&id_market, &new_market_guess); @@ -151,7 +151,7 @@ mod oracle_contract { pub fn set_block_hash_entropy_for_market_id( &mut self, id_market: MarketGuessId, - block_hash_entropy: Hash, + block_hash_entropy: [u8; 32], // Hash ) -> Result<()> { let caller: AccountId = self.env().caller(); // assert!(self.exists_market_data_for_id(id_market), "unable to find market data for given id"); @@ -161,12 +161,15 @@ mod oracle_contract { None => return Err(Error::NoDataForMarketGuessId), }; // singleton change of block hash entropy from the default value set at instantiation of the contract - assert!(market_guess.block_hash_entropy == Default::default(), "unable to set block hash entropy for market id once"); + assert!( + market_guess.block_hash_entropy == None, + "unable to set block hash entropy for market id more than once" + ); if market_guess.oracle_owner != Some(caller) { return Err(Error::CallerIsNotOracleOwner) } let new_market_guess = MarketGuess { - block_hash_entropy, + block_hash_entropy: Some(block_hash_entropy), ..market_guess }; self.market_data.insert(id_market.clone(), &new_market_guess); @@ -174,7 +177,7 @@ mod oracle_contract { id_market: id_market.clone(), oracle_owner: caller, block_number_entropy: market_guess.block_number_entropy, - block_hash_entropy, + block_hash_entropy: Some(block_hash_entropy), }); Ok(()) } @@ -184,31 +187,53 @@ mod oracle_contract { self.env().account_id() } - // #[ink(message)] - // // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber, ????) { - // pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> (BlockNumber, BlockNumber) { - // let market_guess = match self.market_data.get(id_market) { - // Some(data) => data, - // None => return Err(Error::NoDataForMarketGuessId), - // }; - // assert!(market_guess.block_hash_entropy != Default::default(), "block hash entropy must be set prior to obtaining entropy"); - // let block_number_entropy = market_guess.block_number_entropy; - // let block_hash_entropy = market_guess.block_hash_entropy; - - // let entropy = block_hash_entropy.replace(&["0x"][..], ""); - // let str = decode(entropy); - // let buffer = <[u8; 12]>::from_hex(entropy)?; - // let str = str::from_utf8(&buffer).expect("invalid buffer length"); - // let sub = &str[..5]; - // ink::env::debug_println!("sub: {}\n", sub); - - // generate random number from block hash - // don't allow them to use the default value for the random number, they need to have set the - // block hash entropy to a block hash - - // (block_number_entropy, block_hash_entropy, ???) - // (block_number_entropy, block_hash_entropy) - // } + #[ink(message)] + pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> Result<(BlockNumber, [u8; 32], i16, i16)> { + let market_guess = match self.market_data.get(id_market) { + Some(data) => data, + None => return Err(Error::NoDataForMarketGuessId), + }; + assert!( + market_guess.block_hash_entropy != None, + "block hash entropy must be set prior to obtaining entropy" + ); + let block_number_entropy = market_guess.block_number_entropy; + // e."0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" + // note: Hash is [u8; 32] 32 bytes (&[u8]) without 0x prefix and 64 symbols, 32 bytes, 256 bits + let block_hash_entropy: [u8; 32] = market_guess.block_hash_entropy.unwrap(); + // let block_hash_entropy: &[u8] = + // "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".as_bytes(); + // note: changed `block_hash_entropy` to `[u8; 32]` instead of `Hash` so we can get the `.len()` + assert!(block_hash_entropy.len() == 64, "block hash should be a 256 bit block hash"); + ink::env::debug_println!("block_hash_entropy: {:?}\n", block_hash_entropy); + // https://peterlyons.com/problog/2017/12/rust-converting-bytes-chars-and-strings/ + let (c1_u8a, c2_u8a): (&[u8], &[u8]) = self.last_bytes(&block_hash_entropy); + ink::env::debug_println!("c1_u8a: {:?}\n", c1_u8a); + ink::env::debug_println!("c2_u8a: {:?}\n", c2_u8a); + let c1_hex = String::from_utf8_lossy(&c1_u8a); + let c2_hex = String::from_utf8_lossy(&c2_u8a); + ink::env::debug_println!("c1_hex: {:?}", c1_hex); + ink::env::debug_println!("c2_hex: {:?}", c2_hex); + // use u16 since max value 65535 + // let without_prefix = hex.trim_start_matches("0x"); + let c1_decimal = i16::from_str_radix(&c1_hex, 16).unwrap(); + let c2_decimal = i16::from_str_radix(&c2_hex, 16).unwrap(); + ink::env::debug_println!("c1_decimal {:?}", c1_decimal); + ink::env::debug_println!("c2_decimal {:?}", c2_decimal); + // remainders are 0 or 1 and represent the random side the coin flipped on + let c1_rem = c1_decimal % 2i16; + let c2_rem = c2_decimal % 2i16; + ink::env::debug_println!("c1_rem {:?}", c1_rem); + ink::env::debug_println!("c2_rem {:?}", c2_rem); + + Ok((block_number_entropy, block_hash_entropy, c1_rem, c2_rem)) + } + + // get symbols 61-64 for coin1 and 57-60 for coin2 fro the block hash + fn last_bytes<'a>(&'a self, slice: &'a [u8; 32]) -> (&[u8], &[u8]) { + let bytes = slice.split_at(slice.len() - 8).1; + (bytes.split_at(bytes.len() - 4).0, bytes.split_at(bytes.len() - 4).1) + } // helper methods fn exists_market_data_for_id(&self, id_market: MarketGuessId) -> bool { From 7d035fe62584af523c77db921242a0f5f9d762b2 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 13 Jun 2023 06:02:16 +1000 Subject: [PATCH 07/58] save and emit entropy of coin1 and coin2 --- dapps/xcm/unnamed/oracle_contract/lib.rs | 120 ++++++++++++++++++++--- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index aef8be2..c913dd4 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -34,7 +34,6 @@ mod oracle_contract { block_number_guessed: BlockNumber, #[ink(topic)] block_number_entropy: BlockNumber, - // #[ink(topic)] block_number_end: BlockNumber, } @@ -50,6 +49,32 @@ mod oracle_contract { block_hash_entropy: Option<[u8; 32]>, // Hash } + /// Emitted when set entropy for market id. + #[ink(event)] + pub struct SetEntropyForMarketId { + #[ink(topic)] + id_market: MarketGuessId, + oracle_owner: OracleOwner, + #[ink(topic)] + block_number_entropy: BlockNumber, + block_hash_entropy: Option<[u8; 32]>, // Hash + c1_entropy: i16, + c2_entropy: i16 + } + + /// Emitted when set block hash entropy for market id. + #[ink(event)] + pub struct GeneratedEntropyForMarketId { + #[ink(topic)] + id_market: MarketGuessId, + oracle_owner: OracleOwner, + #[ink(topic)] + block_number_entropy: BlockNumber, + block_hash_entropy: Option<[u8; 32]>, // Hash + c1_entropy: i16, + c2_entropy: i16, + } + // https://docs.rs/ink/latest/ink/attr.storage_item.html // Non-packed types like `Mapping` require calculating the storage key during compilation // and it is best to rely on automatic storage key calculation via `ink::storage_item` @@ -74,6 +99,10 @@ mod oracle_contract { block_hash_entropy: Option<[u8; 32]>, // Hash /// Market guess period end block number block_number_end: BlockNumber, + /// Entropy random number for coin 1 + c1_entropy: Option, + /// Entropy random number for coin 2 + c2_entropy: Option, } #[derive(Default)] @@ -135,6 +164,8 @@ mod oracle_contract { block_number_entropy, block_hash_entropy: None, block_number_end, + c1_entropy: None, + c2_entropy: None, }; instance.market_data.insert(&id_market, &new_market_guess); instance.env().emit_event(NewOracleMarketGuessForMarketId { @@ -148,9 +179,10 @@ mod oracle_contract { } #[ink(message)] - pub fn set_block_hash_entropy_for_market_id( + pub fn set_block_for_entropy_for_market_id( &mut self, id_market: MarketGuessId, + block_number_entropy: BlockNumber, // always require this even though it may not have changed block_hash_entropy: [u8; 32], // Hash ) -> Result<()> { let caller: AccountId = self.env().caller(); @@ -160,15 +192,25 @@ mod oracle_contract { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; - // singleton change of block hash entropy from the default value set at instantiation of the contract + // note: oracle_owner may need to run this function more than once incase entropy block number missed or chain reorg + // // singleton change of block hash entropy from the value set at instantiation of the contract + // assert!( + // market_guess.block_hash_entropy == None, + // "unable to set block hash entropy for market id more than once" + // ); + assert!( - market_guess.block_hash_entropy == None, - "unable to set block hash entropy for market id more than once" + block_number_entropy - market_guess.block_number_entropy > 128, + "unable to update block number entropy for market id again until after \ + waiting sufficient blocks after previous so guarantee of waiting until \ + validators change after a certain amount of epochs" ); + if market_guess.oracle_owner != Some(caller) { return Err(Error::CallerIsNotOracleOwner) } let new_market_guess = MarketGuess { + block_number_entropy, block_hash_entropy: Some(block_hash_entropy), ..market_guess }; @@ -176,8 +218,50 @@ mod oracle_contract { self.env().emit_event(SetBlockHashEntropyForMarketId { id_market: id_market.clone(), oracle_owner: caller, - block_number_entropy: market_guess.block_number_entropy, + block_number_entropy, + block_hash_entropy: Some(block_hash_entropy), + }); + Ok(()) + } + + #[ink(message)] + pub fn set_entropy_for_market_id( + &mut self, + id_market: MarketGuessId, + block_number_entropy: BlockNumber, // always require this even though it may not have changed + block_hash_entropy: [u8; 32], // Hash + c1_entropy: i16, + c2_entropy: i16, + ) -> Result<()> { + let caller: AccountId = self.env().caller(); + let market_guess = match self.market_data.get(id_market.clone()) { + Some(data) => data, + None => return Err(Error::NoDataForMarketGuessId), + }; + if market_guess.oracle_owner != Some(caller) { + return Err(Error::CallerIsNotOracleOwner) + } + assert!( + block_number_entropy == market_guess.block_number_entropy && + block_hash_entropy == market_guess.block_hash_entropy.unwrap(), + "block_number entropy and block hash storage must be set prior to setting entropy for the market" + ); + assert!(self.exists_market_data_for_id(id_market.clone()), "unable to find market data for given id"); + let new_market_guess = MarketGuess { + block_number_entropy, block_hash_entropy: Some(block_hash_entropy), + c1_entropy: Some(c1_entropy), + c2_entropy: Some(c2_entropy), + ..market_guess + }; + self.market_data.insert(id_market.clone(), &new_market_guess); + self.env().emit_event(SetEntropyForMarketId { + id_market: id_market.clone(), + oracle_owner: caller, + block_number_entropy, + block_hash_entropy: Some(block_hash_entropy), + c1_entropy, + c2_entropy, }); Ok(()) } @@ -189,14 +273,19 @@ mod oracle_contract { #[ink(message)] pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> Result<(BlockNumber, [u8; 32], i16, i16)> { - let market_guess = match self.market_data.get(id_market) { + let caller: AccountId = self.env().caller(); + let market_guess = match self.market_data.get(id_market.clone()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; - assert!( - market_guess.block_hash_entropy != None, - "block hash entropy must be set prior to obtaining entropy" - ); + if market_guess.oracle_owner != Some(caller) { + return Err(Error::CallerIsNotOracleOwner) + } + // note: oracle_owner may need to run this function more than once incase entropy block number missed or chain reorg + // assert!( + // market_guess.block_hash_entropy != None, + // "block hash entropy must be set prior to obtaining entropy" + // ); let block_number_entropy = market_guess.block_number_entropy; // e."0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" // note: Hash is [u8; 32] 32 bytes (&[u8]) without 0x prefix and 64 symbols, 32 bytes, 256 bits @@ -226,6 +315,15 @@ mod oracle_contract { ink::env::debug_println!("c1_rem {:?}", c1_rem); ink::env::debug_println!("c2_rem {:?}", c2_rem); + self.env().emit_event(GeneratedEntropyForMarketId { + id_market: id_market.clone(), + oracle_owner: caller, + block_number_entropy: market_guess.block_number_entropy, + block_hash_entropy: Some(block_hash_entropy), + c1_entropy: c1_rem, + c2_entropy: c2_rem, + }); + Ok((block_number_entropy, block_hash_entropy, c1_rem, c2_rem)) } From f1b5c55afe89934180658e48c2c30c7939aeb8f3 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 13 Jun 2023 15:10:13 +1000 Subject: [PATCH 08/58] wip stuck stubbing blocknumber from ink environment --- Cargo.lock | 343 ++++++++++++++++++- dapps/xcm/unnamed/README.md | 4 +- dapps/xcm/unnamed/lib.rs | 112 +++--- dapps/xcm/unnamed/oracle_contract/Cargo.toml | 1 + dapps/xcm/unnamed/oracle_contract/lib.rs | 89 ++++- 5 files changed, 490 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90698e5..807feb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,6 +202,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -223,6 +235,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base58" version = "0.2.0" @@ -241,6 +259,12 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "beef" version = "0.5.2" @@ -383,6 +407,9 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] [[package]] name = "camino" @@ -512,6 +539,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + [[package]] name = "constant_time_eq" version = "0.2.5" @@ -636,6 +669,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -771,6 +816,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "derivative" version = "2.2.0" @@ -820,6 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] @@ -857,13 +913,27 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" +[[package]] +name = "ecdsa" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.1.0", + "spki", +] + [[package]] name = "ed25519" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", ] [[package]] @@ -898,6 +968,25 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -938,6 +1027,81 @@ dependencies = [ "libc", ] +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers-core" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da5fa198af0d3be20c19192df2bd9590b92ce09a8421e793bec8851270f1b05" +dependencies = [ + "arrayvec 0.7.2", + "bytes", + "chrono", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "hex", + "k256", + "num_enum", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "tempfile", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -965,6 +1129,16 @@ dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -1133,6 +1307,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1175,6 +1350,17 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.3.19" @@ -1431,6 +1617,15 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + [[package]] name = "impl-serde" version = "0.3.2" @@ -1949,6 +2144,19 @@ dependencies = [ "jsonrpsee-types 0.17.1", ] +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.6", +] + [[package]] name = "keccak" version = "0.1.4" @@ -2222,6 +2430,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.16", +] + [[package]] name = "object" version = "0.29.0" @@ -2261,6 +2490,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.2", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2271,6 +2525,7 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" name = "oracle_contract" version = "0.1.0" dependencies = [ + "ethers-core", "ink", "ink_e2e", "parity-scale-codec", @@ -2409,6 +2664,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2423,6 +2688,7 @@ checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", + "impl-rlp", "impl-serde 0.4.0", "scale-info", "uint", @@ -2636,6 +2902,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -2657,6 +2933,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rlp-derive", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2957,6 +3255,20 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secp256k1" version = "0.24.3" @@ -3148,6 +3460,16 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "slab" version = "0.4.8" @@ -3535,6 +3857,16 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" version = "1.40.0" @@ -3806,6 +4138,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/dapps/xcm/unnamed/README.md b/dapps/xcm/unnamed/README.md index af380dd..cf6ec85 100644 --- a/dapps/xcm/unnamed/README.md +++ b/dapps/xcm/unnamed/README.md @@ -13,4 +13,6 @@ rustup show * Run ``` cargo contract build --manifest-path ./dapps/xcm/unnamed/Cargo.toml -``` \ No newline at end of file +``` + +* TODO - use rand-extension to get random number on-chain diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index d86449f..414e611 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -79,21 +79,21 @@ mod unnamed { /// Imports all the definitions from the outer scope so we can use them here. use super::*; - /// We test if the default constructor does its job. - #[ink::test] - fn default_works() { - let unnamed = Unnamed::default(); - assert_eq!(unnamed.get(), false); - } - - /// We test a simple use case of our contract. - #[ink::test] - fn it_works() { - let mut unnamed = Unnamed::new(false); - assert_eq!(unnamed.get(), false); - unnamed.flip(); - assert_eq!(unnamed.get(), true); - } + // /// We test if the default constructor does its job. + // #[ink::test] + // fn default_works() { + // let unnamed = Unnamed::default(); + // assert_eq!(unnamed.get(), false); + // } + + // /// We test a simple use case of our contract. + // #[ink::test] + // fn it_works() { + // let mut unnamed = Unnamed::new(false); + // assert_eq!(unnamed.get(), false); + // unnamed.flip(); + // assert_eq!(unnamed.get(), true); + // } } @@ -116,21 +116,21 @@ mod unnamed { /// We test that we can upload and instantiate the contract using its default constructor. #[ink_e2e::test] async fn default_works(mut client: ink_e2e::Client) -> E2EResult<()> { - // Given - let constructor = UnnamedRef::default(); - - // When - let contract_account_id = client - .instantiate("unnamed", &ink_e2e::alice(), constructor, 0, None) - .await - .expect("instantiate failed") - .account_id; - - // Then - let get = build_message::(contract_account_id.clone()) - .call(|unnamed| unnamed.get()); - let get_result = client.call_dry_run(&ink_e2e::alice(), &get, 0, None).await; - assert!(matches!(get_result.return_value(), false)); + // // Given + // let constructor = UnnamedRef::default(); + + // // When + // let contract_account_id = client + // .instantiate("unnamed", &ink_e2e::alice(), constructor, 0, None) + // .await + // .expect("instantiate failed") + // .account_id; + + // // Then + // let get = build_message::(contract_account_id.clone()) + // .call(|unnamed| unnamed.get()); + // let get_result = client.call_dry_run(&ink_e2e::alice(), &get, 0, None).await; + // assert!(matches!(get_result.return_value(), false)); Ok(()) } @@ -138,32 +138,32 @@ mod unnamed { /// We test that we can read and write a value from the on-chain contract contract. #[ink_e2e::test] async fn it_works(mut client: ink_e2e::Client) -> E2EResult<()> { - // Given - let constructor = UnnamedRef::new(false); - let contract_account_id = client - .instantiate("unnamed", &ink_e2e::bob(), constructor, 0, None) - .await - .expect("instantiate failed") - .account_id; - - let get = build_message::(contract_account_id.clone()) - .call(|unnamed| unnamed.get()); - let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; - assert!(matches!(get_result.return_value(), false)); - - // When - let flip = build_message::(contract_account_id.clone()) - .call(|unnamed| unnamed.flip()); - let _flip_result = client - .call(&ink_e2e::bob(), flip, 0, None) - .await - .expect("flip failed"); - - // Then - let get = build_message::(contract_account_id.clone()) - .call(|unnamed| unnamed.get()); - let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; - assert!(matches!(get_result.return_value(), true)); + // // Given + // let constructor = UnnamedRef::new(false); + // let contract_account_id = client + // .instantiate("unnamed", &ink_e2e::bob(), constructor, 0, None) + // .await + // .expect("instantiate failed") + // .account_id; + + // let get = build_message::(contract_account_id.clone()) + // .call(|unnamed| unnamed.get()); + // let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; + // assert!(matches!(get_result.return_value(), false)); + + // // When + // let flip = build_message::(contract_account_id.clone()) + // .call(|unnamed| unnamed.flip()); + // let _flip_result = client + // .call(&ink_e2e::bob(), flip, 0, None) + // .await + // .expect("flip failed"); + + // // Then + // let get = build_message::(contract_account_id.clone()) + // .call(|unnamed| unnamed.get()); + // let get_result = client.call_dry_run(&ink_e2e::bob(), &get, 0, None).await; + // assert!(matches!(get_result.return_value(), true)); Ok(()) } diff --git a/dapps/xcm/unnamed/oracle_contract/Cargo.toml b/dapps/xcm/unnamed/oracle_contract/Cargo.toml index a8d28c1..1aacb3f 100644 --- a/dapps/xcm/unnamed/oracle_contract/Cargo.toml +++ b/dapps/xcm/unnamed/oracle_contract/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] ink = { version = "4.2.0", default-features = false } # hex = { version = "0.4.3", default-features = false } +ethers-core = { version = "2.0.7" } scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index c913dd4..65bbe43 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -135,7 +135,7 @@ mod oracle_contract { ) -> Self { let mut instance = Self::default(); let caller = instance.env().caller(); - assert!(instance.exists_market_data_for_id(id_market.clone()), "unable to find market data for given id"); + assert!(!instance.exists_market_data_for_id(id_market.clone()), "market data for given id already exists"); let block_number_current = Self::env().block_number(); // TODO - we need to verify that the block hash exists for the block number // when they say guessing occurred @@ -339,3 +339,90 @@ mod oracle_contract { } } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::oracle_contract::OracleContract; + // use ethers::core::types::H256; + use ethers_core::types::{H256}; + use std::str::FromStr; + // use ink::primitives::{Hash}; + + use ink::env::{ + Environment, + DefaultEnvironment, + }; + + #[ink::chain_extension] + pub trait CustomBlocknumberExtension { + type ErrorCode = CustomBlocknumberError; + + #[ink(extension = 0x1111)] + fn fake_current_block_number() -> Result { + // TODO - figure out how to stub the ink! environment functions + // See https://substrate.stackexchange.com/questions/8867/how-to-stub-ink-contract-environment-to-produce-fake-values-for-use-in-tests + }; + } + + /// An environment using default ink environment types + #[derive(Debug, Clone, PartialEq, Eq)] + #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] + pub enum CustomEnvironment {} + + impl Environment for CustomEnvironment { + const MAX_EVENT_TOPICS: usize = + ::MAX_EVENT_TOPICS; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Hash = ::Hash; + type Timestamp = ::Timestamp; + type BlockNumber = ::BlockNumber; + + type ChainExtension = crate::CustomBlocknumberExtension; + } + + /// We test a simple use case of our contract. + #[ink::test(env = crate::CustomEnvironment)] + fn it_works() { + assert!(self.env().extension().fake_current_block_number(), 200); + let id_market: Vec = String::from_utf8("my_id".into()).unwrap().into(); + let block_number_guessed = 100; + let block_number_entropy = 228; + let block_number_end = 300; + let mut oracle_contract = OracleContract::new( + id_market.clone(), + block_number_guessed.clone(), + block_number_entropy.clone(), + block_number_end.clone(), + ); + let str_block_hash_entropy: String = + "0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".to_string(); + + let hash_block_hash_entropy: H256 = str_block_hash_entropy.as_str().parse::().unwrap(); + let bytes_block_hash_entropy: [u8; 32] = hash_block_hash_entropy.to_fixed_bytes(); + assert_eq!(oracle_contract.set_block_for_entropy_for_market_id( + id_market.clone(), + block_number_entropy.clone(), + bytes_block_hash_entropy.clone(), + ), Ok(())); + + let oracle_contract_address = oracle_contract.get_oracle_contract_address(); + + let c1_entropy = 0i16; + let c2_entropy = 0i16; + assert_eq!( + oracle_contract.get_entropy_for_market_id( + id_market.clone(), + ).unwrap(), + ( + block_number_entropy.clone(), + bytes_block_hash_entropy.clone(), + c1_entropy.clone(), + c2_entropy.clone(), + ) + ); + } +} \ No newline at end of file From 56aaa29f103f2948c303df5f41d7ea357c5aaf88 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 13 Jun 2023 19:07:16 +1000 Subject: [PATCH 09/58] use set_block_number from pr to upstream working --- Cargo.lock | 285 ++++++++++++++++--- dapps/xcm/unnamed/Cargo.toml | 3 +- dapps/xcm/unnamed/oracle_contract/Cargo.toml | 3 +- dapps/xcm/unnamed/oracle_contract/lib.rs | 59 ++-- 4 files changed, 271 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 807feb7..17a38fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1155,7 +1155,7 @@ dependencies = [ name = "flipper" version = "0.1.0" dependencies = [ - "ink", + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_e2e", "parity-scale-codec", "scale-info", @@ -1673,12 +1673,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b374fcb3c9b91f8293bdc93d69292e2ec6ea19e97e00725806d79bf563fa5e55" dependencies = [ "derive_more", - "ink_env", - "ink_macro", - "ink_metadata", - "ink_prelude", - "ink_primitives", - "ink_storage", + "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_macro 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_storage 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", +] + +[[package]] +name = "ink" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "derive_more", + "ink_env 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_macro 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_storage 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", ] @@ -1691,6 +1706,14 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ink_allocator" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "ink_codegen" version = "4.2.0" @@ -1703,8 +1726,8 @@ dependencies = [ "env_logger", "heck", "impl-serde 0.4.0", - "ink_ir", - "ink_primitives", + "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools", "log", "parity-scale-codec", @@ -1715,6 +1738,27 @@ dependencies = [ "syn 2.0.16", ] +[[package]] +name = "ink_codegen" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "blake2", + "derive_more", + "either", + "heck", + "impl-serde 0.4.0", + "ink_ir 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "itertools", + "parity-scale-codec", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.16", +] + [[package]] name = "ink_e2e" version = "4.2.0" @@ -1724,10 +1768,10 @@ dependencies = [ "env_logger", "funty", "impl-serde 0.3.2", - "ink", + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_e2e_macro", - "ink_env", - "ink_primitives", + "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpsee 0.17.1", "log", "pallet-contracts-primitives", @@ -1752,7 +1796,7 @@ dependencies = [ "contract-build", "derive_more", "env_logger", - "ink_ir", + "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log", "proc-macro2", "quote", @@ -1769,7 +1813,21 @@ checksum = "77c4af49e092a93e65d1161ce31d23c2e57d724462c96a8944acd647a52787f0" dependencies = [ "blake2", "derive_more", - "ink_primitives", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "secp256k1 0.27.0", + "sha2 0.10.6", + "sha3", +] + +[[package]] +name = "ink_engine" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "blake2", + "derive_more", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "secp256k1 0.27.0", "sha2 0.10.6", @@ -1786,11 +1844,38 @@ dependencies = [ "blake2", "cfg-if", "derive_more", - "ink_allocator", - "ink_engine", - "ink_prelude", - "ink_primitives", - "ink_storage_traits", + "ink_allocator 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_engine 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_storage_traits 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits", + "parity-scale-codec", + "paste", + "rlibc", + "scale-decode", + "scale-encode", + "scale-info", + "secp256k1 0.27.0", + "sha2 0.10.6", + "sha3", + "static_assertions", +] + +[[package]] +name = "ink_env" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "arrayref", + "blake2", + "cfg-if", + "derive_more", + "ink_allocator 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_engine 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_storage_traits 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "num-traits", "parity-scale-codec", "paste", @@ -1818,15 +1903,44 @@ dependencies = [ "syn 2.0.16", ] +[[package]] +name = "ink_ir" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "blake2", + "either", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.16", +] + [[package]] name = "ink_macro" version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15abf802e89909c65b6c15d0c655beb3c7ab86309626effb5d9b330d97308114" dependencies = [ - "ink_codegen", - "ink_ir", - "ink_primitives", + "ink_codegen 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "proc-macro2", + "quote", + "syn 2.0.16", + "synstructure", +] + +[[package]] +name = "ink_macro" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "ink_codegen 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_ir 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "proc-macro2", "quote", @@ -1842,12 +1956,26 @@ checksum = "4af082b4c2eb246d27b358411ef950811f851c1099aa507ba4bcdd7214d40ccd" dependencies = [ "derive_more", "impl-serde 0.4.0", - "ink_prelude", - "ink_primitives", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "scale-info", "serde", ] +[[package]] +name = "ink_metadata" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "derive_more", + "impl-serde 0.4.0", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "scale-info", + "schemars", + "serde", +] + [[package]] name = "ink_prelude" version = "4.2.0" @@ -1857,6 +1985,14 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ink_prelude" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "ink_primitives" version = "4.2.0" @@ -1864,7 +2000,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52693c5e74600f5bd4c0f6d447ba9c4e491e4edf685eaf9f9f347a3cb1cde66b" dependencies = [ "derive_more", - "ink_prelude", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "scale-decode", + "scale-encode", + "scale-info", + "xxhash-rust", +] + +[[package]] +name = "ink_primitives" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "derive_more", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "scale-decode", "scale-encode", @@ -1881,11 +2031,28 @@ dependencies = [ "array-init", "cfg-if", "derive_more", - "ink_env", - "ink_metadata", - "ink_prelude", - "ink_primitives", - "ink_storage_traits", + "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_storage_traits 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ink_storage" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "array-init", + "cfg-if", + "derive_more", + "ink_env 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_storage_traits 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "scale-info", ] @@ -1896,9 +2063,21 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec58d70937c1e1490a00b84e2eb9a799f1a5331dd0e5cc68d550de1dbf6a8f4" dependencies = [ - "ink_metadata", - "ink_prelude", - "ink_primitives", + "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ink_storage_traits" +version = "4.2.0" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +dependencies = [ + "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "scale-info", ] @@ -2526,7 +2705,7 @@ name = "oracle_contract" version = "0.1.0" dependencies = [ "ethers-core", - "ink", + "ink 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_e2e", "parity-scale-codec", "scale-info", @@ -3162,6 +3341,7 @@ dependencies = [ "derive_more", "parity-scale-codec", "scale-info-derive", + "schemars", "serde", ] @@ -3204,6 +3384,30 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "schnellru" version = "0.2.1" @@ -3366,6 +3570,17 @@ dependencies = [ "syn 2.0.16", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.96" @@ -4448,7 +4663,7 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" name = "unnamed" version = "0.1.0" dependencies = [ - "ink", + "ink 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_e2e", "oracle_contract", "parity-scale-codec", diff --git a/dapps/xcm/unnamed/Cargo.toml b/dapps/xcm/unnamed/Cargo.toml index 7fa05f9..3870d06 100755 --- a/dapps/xcm/unnamed/Cargo.toml +++ b/dapps/xcm/unnamed/Cargo.toml @@ -5,7 +5,8 @@ authors = ["[your_name] <[your_email]>"] edition = "2021" [dependencies] -ink = { version = "4.2.0", default-features = false } +# ink = { version = "4.2.0", default-features = false } +ink = { git = 'https://github.com/ltfschoen/ink', branch = 'ltfschoen-env-offchain-test-set-block-number', default-features = false } scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } diff --git a/dapps/xcm/unnamed/oracle_contract/Cargo.toml b/dapps/xcm/unnamed/oracle_contract/Cargo.toml index 1aacb3f..d8c3060 100644 --- a/dapps/xcm/unnamed/oracle_contract/Cargo.toml +++ b/dapps/xcm/unnamed/oracle_contract/Cargo.toml @@ -5,7 +5,8 @@ authors = ["[your_name] <[your_email]>"] edition = "2021" [dependencies] -ink = { version = "4.2.0", default-features = false } +# ink = { version = "4.2.0", default-features = false } +ink = { git = 'https://github.com/ltfschoen/ink', branch = 'ltfschoen-env-offchain-test-set-block-number', default-features = false } # hex = { version = "0.4.3", default-features = false } ethers-core = { version = "2.0.7" } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 65bbe43..1dbcd44 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -199,8 +199,9 @@ mod oracle_contract { // "unable to set block hash entropy for market id more than once" // ); + let block_number_current = Self::env().block_number(); assert!( - block_number_entropy - market_guess.block_number_entropy > 128, + block_number_current - market_guess.block_number_entropy > 128, "unable to update block number entropy for market id again until after \ waiting sufficient blocks after previous so guarantee of waiting until \ validators change after a certain amount of epochs" @@ -293,7 +294,7 @@ mod oracle_contract { // let block_hash_entropy: &[u8] = // "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".as_bytes(); // note: changed `block_hash_entropy` to `[u8; 32]` instead of `Hash` so we can get the `.len()` - assert!(block_hash_entropy.len() == 64, "block hash should be a 256 bit block hash"); + assert!(block_hash_entropy.len() == 32, "block hash should be a 256 bit block hash"); ink::env::debug_println!("block_hash_entropy: {:?}\n", block_hash_entropy); // https://peterlyons.com/problog/2017/12/rust-converting-bytes-chars-and-strings/ let (c1_u8a, c2_u8a): (&[u8], &[u8]) = self.last_bytes(&block_hash_entropy); @@ -348,50 +349,21 @@ mod tests { // use ethers::core::types::H256; use ethers_core::types::{H256}; use std::str::FromStr; - // use ink::primitives::{Hash}; - - use ink::env::{ - Environment, - DefaultEnvironment, - }; - - #[ink::chain_extension] - pub trait CustomBlocknumberExtension { - type ErrorCode = CustomBlocknumberError; - - #[ink(extension = 0x1111)] - fn fake_current_block_number() -> Result { - // TODO - figure out how to stub the ink! environment functions - // See https://substrate.stackexchange.com/questions/8867/how-to-stub-ink-contract-environment-to-produce-fake-values-for-use-in-tests - }; - } - - /// An environment using default ink environment types - #[derive(Debug, Clone, PartialEq, Eq)] - #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] - pub enum CustomEnvironment {} - impl Environment for CustomEnvironment { - const MAX_EVENT_TOPICS: usize = - ::MAX_EVENT_TOPICS; - - type AccountId = ::AccountId; - type Balance = ::Balance; - type Hash = ::Hash; - type Timestamp = ::Timestamp; - type BlockNumber = ::BlockNumber; - - type ChainExtension = crate::CustomBlocknumberExtension; - } + type BlockNumber = u32; /// We test a simple use case of our contract. - #[ink::test(env = crate::CustomEnvironment)] + #[ink::test] fn it_works() { - assert!(self.env().extension().fake_current_block_number(), 200); let id_market: Vec = String::from_utf8("my_id".into()).unwrap().into(); - let block_number_guessed = 100; - let block_number_entropy = 228; - let block_number_end = 300; + let block_number_guessed = 50; + // override `Self::env().block_number();` for tests + // See https://substrate.stackexchange.com/questions/8867/how-to-stub-ink-contract-environment-to-produce-fake-values-for-use-in-tests + let mut new_block_number: BlockNumber = 100; + ink::env::test::set_block_number::(new_block_number); + let block_number_entropy = 228; // must be more than 100 blocks after current block_number + let block_number_end = 500; // must be more than 200 blocks after block_number_entropy + let mut oracle_contract = OracleContract::new( id_market.clone(), block_number_guessed.clone(), @@ -399,10 +371,13 @@ mod tests { block_number_end.clone(), ); let str_block_hash_entropy: String = - "0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".to_string(); + "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".to_string(); let hash_block_hash_entropy: H256 = str_block_hash_entropy.as_str().parse::().unwrap(); let bytes_block_hash_entropy: [u8; 32] = hash_block_hash_entropy.to_fixed_bytes(); + + new_block_number = 357; // >128 after block_number_entropy (228 + 128 + 1 = 357) + ink::env::test::set_block_number::(new_block_number); assert_eq!(oracle_contract.set_block_for_entropy_for_market_id( id_market.clone(), block_number_entropy.clone(), From 10a08f8b11dff719013b697d5232c41edd11f9fd Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 15 Jun 2023 10:38:20 +1000 Subject: [PATCH 10/58] fix contracts using String but already uploaded error Uploading sub-contract... ERROR: This contract has already been uploaded with code hash: 0x834290924ed6ca8ba831468a156d6874154d52477e2e484264cb83de0f16eb93 Uploading contract... ERROR: This contract has already been uploaded with code hash: 0x34f37b1e1a713d3b81c7c55ec4e132ef6e29084902e3cf27986f0cb8be0c3017 Finished uploading contracts... Instantiating contract... ERROR: Error parsing Value: Parsing Error: Stack { base: Alt([Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Expected(Char('[')) }, Base { location: "", kind: Expected(Char('(')) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Expected(AlphaNumeric) }, Base { location: "", kind: External(ParseIntError { kind: Empty }) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Kind(Tag) }, Base { location: "", kind: Expected(Char('\'')) }, Base { location: "", kind: Expected(Something) }]), contexts: [("", Context("Value"))] } --- Cargo.lock | 621 ++++--------------- dapps/xcm/unnamed/README.md | 10 +- dapps/xcm/unnamed/lib.rs | 26 +- dapps/xcm/unnamed/oracle_contract/Cargo.toml | 2 +- dapps/xcm/unnamed/oracle_contract/lib.rs | 178 +++--- docker/quickstart-unnamed.sh | 148 +++++ 6 files changed, 418 insertions(+), 567 deletions(-) create mode 100755 docker/quickstart-unnamed.sh diff --git a/Cargo.lock b/Cargo.lock index 17a38fc..1cf352b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,7 +42,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -54,20 +54,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom 0.2.9", + "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -167,9 +173,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "8868f09ff8cea88b079da74ae569d9b8c62a23c68c746240b704ee6f7525c89c" [[package]] name = "async-lock" @@ -188,7 +194,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -202,18 +208,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "auto_impl" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -231,16 +225,10 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.3", + "object 0.30.4", "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" - [[package]] name = "base58" version = "0.2.0" @@ -255,15 +243,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "beef" @@ -317,7 +299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", - "arrayvec 0.7.2", + "arrayvec 0.7.3", "constant_time_eq", ] @@ -362,9 +344,9 @@ dependencies = [ [[package]] name = "bounded-collections" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbd1d11282a1eb134d3c3b7cf8ce213b5161c6e5f73fb1b98618482c606b64" +checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" dependencies = [ "log", "parity-scale-codec", @@ -407,9 +389,6 @@ name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] [[package]] name = "camino" @@ -460,21 +439,21 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "winapi", ] [[package]] name = "clap" -version = "4.3.0" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "ca8f255e4b8027970e78db75e78831229c9815fdbfa67eb1a1b777a62e24b4a0" dependencies = [ "clap_builder", "clap_derive", @@ -483,9 +462,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "acd4f3c17c83b0ba34ffbc4f8bbd74f079413f747f84a6f89292f138057e36ab" dependencies = [ "anstream", "anstyle", @@ -496,14 +475,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -539,17 +518,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - [[package]] name = "constant_time_eq" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" [[package]] name = "contract-build" @@ -656,9 +629,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -669,18 +642,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" -dependencies = [ - "generic-array 0.14.7", - "rand_core 0.6.4", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -739,9 +700,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +checksum = "109308c20e8445959c2792e81871054c6a17e6976489a93d2769641a2ba5839c" dependencies = [ "cc", "cxxbridge-flags", @@ -751,9 +712,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +checksum = "daf4c6755cdf10798b97510e0e2b3edb9573032bd9379de8fffa59d68165494f" dependencies = [ "cc", "codespan-reporting", @@ -761,24 +722,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] name = "cxxbridge-flags" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" +checksum = "882074421238e84fe3b4c65d0081de34e5b323bf64555d3e61991f76eb64a7bb" [[package]] name = "cxxbridge-macro" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +checksum = "4a076022ece33e7686fb76513518e219cca4fce5750a8ae6d1ce6c0f48fd1af9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -816,16 +777,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "der" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17" -dependencies = [ - "const-oid", - "zeroize", -] - [[package]] name = "derivative" version = "2.2.0" @@ -875,7 +826,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", - "const-oid", "crypto-common", "subtle", ] @@ -913,27 +863,13 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" -[[package]] -name = "ecdsa" -version = "0.16.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" -dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature 2.1.0", - "spki", -] - [[package]] name = "ed25519" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature 1.6.4", + "signature", ] [[package]] @@ -968,25 +904,6 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" -[[package]] -name = "elliptic-curve" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" -dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array 0.14.7", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -1027,81 +944,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde 0.4.0", - "scale-info", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde 0.4.0", - "primitive-types", - "scale-info", - "uint", -] - -[[package]] -name = "ethers-core" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6da5fa198af0d3be20c19192df2bd9590b92ce09a8421e793bec8851270f1b05" -dependencies = [ - "arrayvec 0.7.2", - "bytes", - "chrono", - "elliptic-curve", - "ethabi", - "generic-array 0.14.7", - "hex", - "k256", - "num_enum", - "open-fastrlp", - "rand 0.8.5", - "rlp", - "serde", - "serde_json", - "strum", - "tempfile", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -1129,16 +971,6 @@ dependencies = [ "instant", ] -[[package]] -name = "ff" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" -dependencies = [ - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "fixed-hash" version = "0.8.0" @@ -1169,9 +1001,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1251,7 +1083,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1307,7 +1139,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", - "zeroize", ] [[package]] @@ -1323,9 +1154,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -1350,17 +1181,6 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" -[[package]] -name = "group" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" -dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "h2" version = "0.3.19" @@ -1571,9 +1391,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1600,9 +1420,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1617,15 +1437,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - [[package]] name = "impl-serde" version = "0.3.2" @@ -1735,7 +1546,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1756,7 +1567,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1801,7 +1612,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.16", + "syn 2.0.18", "which", ] @@ -1900,7 +1711,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1914,7 +1725,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -1929,7 +1740,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "synstructure", ] @@ -1944,7 +1755,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "synstructure", ] @@ -2119,7 +1930,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.37.19", + "rustix 0.37.20", "windows-sys 0.48.0", ] @@ -2149,9 +1960,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -2214,7 +2025,7 @@ dependencies = [ "soketto", "thiserror", "tokio", - "tokio-rustls 0.24.0", + "tokio-rustls 0.24.1", "tokio-util", "tracing", ] @@ -2323,19 +2134,6 @@ dependencies = [ "jsonrpsee-types 0.17.1", ] -[[package]] -name = "k256" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" -dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2 0.10.6", -] - [[package]] name = "keccak" version = "0.1.4" @@ -2353,9 +2151,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libm" @@ -2434,9 +2232,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -2444,12 +2242,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "mach" @@ -2481,7 +2276,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.37.19", + "rustix 0.37.20", ] [[package]] @@ -2531,14 +2326,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -2564,7 +2358,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.3", "itoa", ] @@ -2609,27 +2403,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_enum" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.16", -] - [[package]] name = "object" version = "0.29.0" @@ -2644,18 +2417,18 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -2669,31 +2442,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec 0.7.2", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "openssl-probe" version = "0.1.5" @@ -2704,7 +2452,6 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" name = "oracle_contract" version = "0.1.0" dependencies = [ - "ethers-core", "ink 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_e2e", "parity-scale-codec", @@ -2731,7 +2478,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.3", "bitvec", "byte-slice-cast", "bytes", @@ -2770,15 +2517,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.0", ] [[package]] @@ -2807,9 +2554,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" @@ -2828,7 +2575,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -2843,16 +2590,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2867,7 +2604,6 @@ checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", "impl-serde 0.4.0", "scale-info", "uint", @@ -2909,9 +2645,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -2927,9 +2663,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -2999,7 +2735,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -3011,15 +2747,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_syscall" version = "0.3.5" @@ -3046,14 +2773,14 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] name = "regex" -version = "1.8.2" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -3081,16 +2808,6 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" -[[package]] -name = "rfc6979" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" -dependencies = [ - "hmac 0.12.1", - "subtle", -] - [[package]] name = "ring" version = "0.16.20" @@ -3112,28 +2829,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rlp-derive", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3177,9 +2872,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", @@ -3231,7 +2926,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.1", + "base64 0.21.2", ] [[package]] @@ -3459,20 +3154,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "sec1" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" -dependencies = [ - "base16ct", - "der", - "generic-array 0.14.7", - "pkcs8", - "subtle", - "zeroize", -] - [[package]] name = "secp256k1" version = "0.24.3" @@ -3552,22 +3233,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -3675,16 +3356,6 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -[[package]] -name = "signature" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" -dependencies = [ - "digest 0.10.7", - "rand_core 0.6.4", -] - [[package]] name = "slab" version = "0.4.8" @@ -4072,16 +3743,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spki" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "ss58-registry" version = "1.40.0" @@ -4168,7 +3829,7 @@ dependencies = [ "either", "frame-metadata", "futures", - "getrandom 0.2.9", + "getrandom 0.2.10", "hex", "impl-serde 0.4.0", "jsonrpsee 0.16.2", @@ -4249,9 +3910,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.16" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -4266,7 +3927,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "unicode-xid", ] @@ -4284,15 +3945,16 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", - "redox_syscall 0.3.5", - "rustix 0.37.19", - "windows-sys 0.45.0", + "redox_syscall", + "rustix 0.37.20", + "windows-sys 0.48.0", ] [[package]] @@ -4321,7 +3983,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -4353,15 +4015,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" version = "1.6.0" @@ -4379,9 +4032,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -4402,7 +4055,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -4418,9 +4071,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls 0.21.1", "tokio", @@ -4512,7 +4165,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] @@ -4678,9 +4331,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -4740,9 +4393,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4750,24 +4403,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4775,22 +4428,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-opt" @@ -5009,9 +4662,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -5281,7 +4934,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.18", ] [[package]] diff --git a/dapps/xcm/unnamed/README.md b/dapps/xcm/unnamed/README.md index cf6ec85..230f870 100644 --- a/dapps/xcm/unnamed/README.md +++ b/dapps/xcm/unnamed/README.md @@ -10,9 +10,13 @@ rustup component add rust-src --toolchain 1.69 rustup toolchain list rustup show ``` -* Run +* Update Cargo Contract to latest version. Check latest version on Github then: ``` -cargo contract build --manifest-path ./dapps/xcm/unnamed/Cargo.toml +cargo-contract --version +cargo install --force --locked cargo-contract ``` +* Run the following to start a contracts-node, upload and instantiate the contracts, +and call the relevant functions -* TODO - use rand-extension to get random number on-chain +* Links + * use [rand-extension](https://github.com/paritytech/ink-examples/blob/main/rand-extension/lib.rs) to get random number on-chain diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 414e611..f9f3f9d 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -4,10 +4,10 @@ mod unnamed { use oracle_contract::OracleContractRef; + use ink::prelude::string::String; use ink::prelude::vec::Vec; // refactor into types file - pub type MarketGuessId = Vec; pub type OracleOwner = AccountId; /// Defines the storage of your contract. @@ -37,7 +37,7 @@ mod unnamed { #[ink(constructor)] pub fn new( oracle_contract_code_hash: Hash, - id_market: MarketGuessId, + id_market: String, block_number_guessed: BlockNumber, block_number_entropy: BlockNumber, block_number_end: BlockNumber, @@ -61,6 +61,28 @@ mod unnamed { } } + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` + #[ink(message)] + pub fn set_block_for_entropy_for_market_id( + &mut self, + id_market: String, + block_number_entropy: BlockNumber, // always require this even though it may not have changed + block_hash_entropy: String, // Hash + ) -> Result<()> { + ink::env::debug_println!("&self.oracle_contract {:?}", &self.oracle_contract); + match &self.oracle_contract { + Some(c) => { + let res = c.clone().set_block_for_entropy_for_market_id( + id_market, + block_number_entropy, + block_hash_entropy.clone(), + ); + Ok(()) + }, + None => return Err(Error::NoOracleContractAddress), + } + } + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] pub fn get_oracle_contract_address(&self) -> Result { diff --git a/dapps/xcm/unnamed/oracle_contract/Cargo.toml b/dapps/xcm/unnamed/oracle_contract/Cargo.toml index d8c3060..2ab3897 100644 --- a/dapps/xcm/unnamed/oracle_contract/Cargo.toml +++ b/dapps/xcm/unnamed/oracle_contract/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" # ink = { version = "4.2.0", default-features = false } ink = { git = 'https://github.com/ltfschoen/ink', branch = 'ltfschoen-env-offchain-test-set-block-number', default-features = false } # hex = { version = "0.4.3", default-features = false } -ethers-core = { version = "2.0.7" } +# ethers-core = { version = "2.0.7", default-features = false } scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 1dbcd44..8641dee 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -16,7 +16,7 @@ mod oracle_contract { StorageKey, Storable, }; - // use core::str; + use core::str; // use hex; // refactor into types file @@ -27,13 +27,16 @@ mod oracle_contract { #[ink(event)] pub struct NewOracleMarketGuessForMarketId { #[ink(topic)] - id_market: MarketGuessId, + id_market: String, #[ink(topic)] oracle_owner: OracleOwner, #[ink(topic)] block_number_guessed: BlockNumber, - #[ink(topic)] + // Use 3x topics instead of max 4x topics else get error. + // https://github.com/paritytech/cargo-contract/issues/1160 + // #[ink(topic)] block_number_entropy: BlockNumber, + // #[ink(topic)] block_number_end: BlockNumber, } @@ -46,7 +49,7 @@ mod oracle_contract { #[ink(topic)] block_number_entropy: BlockNumber, #[ink(topic)] - block_hash_entropy: Option<[u8; 32]>, // Hash + block_hash_entropy: Option, // Hash } /// Emitted when set entropy for market id. @@ -57,7 +60,7 @@ mod oracle_contract { oracle_owner: OracleOwner, #[ink(topic)] block_number_entropy: BlockNumber, - block_hash_entropy: Option<[u8; 32]>, // Hash + block_hash_entropy: Option, // Hash c1_entropy: i16, c2_entropy: i16 } @@ -70,7 +73,7 @@ mod oracle_contract { oracle_owner: OracleOwner, #[ink(topic)] block_number_entropy: BlockNumber, - block_hash_entropy: Option<[u8; 32]>, // Hash + block_hash_entropy: Option, // Hash c1_entropy: i16, c2_entropy: i16, } @@ -96,7 +99,7 @@ mod oracle_contract { block_number_entropy: BlockNumber, /// Block hash associated with `block_number_entropy` when finalized /// to use for entropy. - block_hash_entropy: Option<[u8; 32]>, // Hash + block_hash_entropy: Option, // Hash /// Market guess period end block number block_number_end: BlockNumber, /// Entropy random number for coin 1 @@ -120,6 +123,8 @@ mod oracle_contract { NoDataForMarketGuessId, /// Returned if caller is not oracle owner of market guess id. CallerIsNotOracleOwner, + InvalidUTF8Sequence, + InvalidDigit, } /// Type alias for the contract's result type. @@ -128,35 +133,36 @@ mod oracle_contract { impl OracleContract { #[ink(constructor)] pub fn new( - id_market: MarketGuessId, + id_market: String, block_number_guessed: BlockNumber, block_number_entropy: BlockNumber, block_number_end: BlockNumber, ) -> Self { + ink::env::debug_println!("new"); let mut instance = Self::default(); let caller = instance.env().caller(); - assert!(!instance.exists_market_data_for_id(id_market.clone()), "market data for given id already exists"); + assert!(instance.exists_market_data_for_id(id_market.as_bytes()).is_ok(), "market data for given id already exists"); let block_number_current = Self::env().block_number(); // TODO - we need to verify that the block hash exists for the block number // when they say guessing occurred - assert!( - block_number_current > block_number_guessed, - "block number when guessing occurred must be before the current block number" - ); + // assert!( + // block_number_current > block_number_guessed, + // "block number when guessing occurred must be before the current block number" + // ); // TODO - 100 and 200 are magic numbers, need something more meaningful - assert!( - block_number_entropy - block_number_current > 100, - "block used for entropy must allow sufficient block confirmations after the current \ - block and block when guessing occurred for assurance that epoch gets finalized \ - incase head susceptible to reorganization for safety" - ); - assert!( - block_number_end - block_number_entropy > 200, - "block when market ends must be allow sufficient block confirmations after the \ - block used for entropy" - ); + // assert!( + // block_number_entropy - block_number_current > 100, + // "block used for entropy must allow sufficient block confirmations after the current \ + // block and block when guessing occurred for assurance that epoch gets finalized \ + // incase head susceptible to reorganization for safety" + // ); + // assert!( + // block_number_end - block_number_entropy > 200, + // "block when market ends must be allow sufficient block confirmations after the \ + // block used for entropy" + // ); let new_market_guess = MarketGuess { - id_market: id_market.clone(), + id_market: id_market.clone().into_bytes(), // must be set to Option to avoid error: // the trait `Default` is not implemented for `ink::ink_primitives::AccountId` oracle_owner: Some(caller), @@ -167,7 +173,7 @@ mod oracle_contract { c1_entropy: None, c2_entropy: None, }; - instance.market_data.insert(&id_market, &new_market_guess); + instance.market_data.insert(id_market.clone().into_bytes(), &new_market_guess); instance.env().emit_event(NewOracleMarketGuessForMarketId { id_market: id_market.clone(), oracle_owner: caller, @@ -181,17 +187,21 @@ mod oracle_contract { #[ink(message)] pub fn set_block_for_entropy_for_market_id( &mut self, - id_market: MarketGuessId, + id_market: String, block_number_entropy: BlockNumber, // always require this even though it may not have changed - block_hash_entropy: [u8; 32], // Hash + block_hash_entropy: String, // Hash ) -> Result<()> { let caller: AccountId = self.env().caller(); - // assert!(self.exists_market_data_for_id(id_market), "unable to find market data for given id"); + ink::env::debug_println!("set_block_for_entropy_for_market_id"); + // assert!(self.exists_market_data_for_id(id_market.as_bytes()).is_ok(), "unable to find market data for given id"); // TODO - convert Vec to &str to avoid use of .clone() - let market_guess = match self.market_data.get(id_market.clone()) { + let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; + ink::env::debug_println!("block_hash_entropy: {:?}\n", block_hash_entropy); + ink::env::debug_println!("block_hash_entropy.len(): {:?}\n", block_hash_entropy.len()); + ink::env::debug_println!("market_guess: {:?}\n", market_guess); // note: oracle_owner may need to run this function more than once incase entropy block number missed or chain reorg // // singleton change of block hash entropy from the value set at instantiation of the contract // assert!( @@ -200,27 +210,29 @@ mod oracle_contract { // ); let block_number_current = Self::env().block_number(); - assert!( - block_number_current - market_guess.block_number_entropy > 128, - "unable to update block number entropy for market id again until after \ - waiting sufficient blocks after previous so guarantee of waiting until \ - validators change after a certain amount of epochs" - ); + // assert!( + // block_number_current - market_guess.block_number_entropy > 128, + // "unable to update block number entropy for market id again until after \ + // waiting sufficient blocks after previous so guarantee of waiting until \ + // validators change after a certain amount of epochs" + // ); + let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); + assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); if market_guess.oracle_owner != Some(caller) { return Err(Error::CallerIsNotOracleOwner) } let new_market_guess = MarketGuess { block_number_entropy, - block_hash_entropy: Some(block_hash_entropy), + block_hash_entropy: Some(block_hash_entropy_no_prefix.clone()), ..market_guess }; - self.market_data.insert(id_market.clone(), &new_market_guess); + self.market_data.insert(id_market.clone().into_bytes(), &new_market_guess); self.env().emit_event(SetBlockHashEntropyForMarketId { - id_market: id_market.clone(), + id_market: id_market.clone().into_bytes(), oracle_owner: caller, block_number_entropy, - block_hash_entropy: Some(block_hash_entropy), + block_hash_entropy: Some(block_hash_entropy_no_prefix.clone()), }); Ok(()) } @@ -228,39 +240,43 @@ mod oracle_contract { #[ink(message)] pub fn set_entropy_for_market_id( &mut self, - id_market: MarketGuessId, + id_market: String, block_number_entropy: BlockNumber, // always require this even though it may not have changed - block_hash_entropy: [u8; 32], // Hash + block_hash_entropy: String, // Hash c1_entropy: i16, c2_entropy: i16, ) -> Result<()> { let caller: AccountId = self.env().caller(); - let market_guess = match self.market_data.get(id_market.clone()) { + let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; if market_guess.oracle_owner != Some(caller) { return Err(Error::CallerIsNotOracleOwner) } + let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); + assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); + + // TODO - replace with `match` assert!( block_number_entropy == market_guess.block_number_entropy && - block_hash_entropy == market_guess.block_hash_entropy.unwrap(), + block_hash_entropy_no_prefix == market_guess.block_hash_entropy.unwrap(), "block_number entropy and block hash storage must be set prior to setting entropy for the market" ); - assert!(self.exists_market_data_for_id(id_market.clone()), "unable to find market data for given id"); + assert!(self.exists_market_data_for_id(id_market.as_bytes()).is_ok(), "unable to find market data for given id"); let new_market_guess = MarketGuess { block_number_entropy, - block_hash_entropy: Some(block_hash_entropy), + block_hash_entropy: Some(block_hash_entropy_no_prefix.clone()), c1_entropy: Some(c1_entropy), c2_entropy: Some(c2_entropy), ..market_guess }; - self.market_data.insert(id_market.clone(), &new_market_guess); + self.market_data.insert(id_market.clone().into_bytes(), &new_market_guess); self.env().emit_event(SetEntropyForMarketId { - id_market: id_market.clone(), + id_market: id_market.into_bytes(), oracle_owner: caller, block_number_entropy, - block_hash_entropy: Some(block_hash_entropy), + block_hash_entropy: Some(block_hash_entropy_no_prefix.clone()), c1_entropy, c2_entropy, }); @@ -273,9 +289,9 @@ mod oracle_contract { } #[ink(message)] - pub fn get_entropy_for_market_id(&self, id_market: MarketGuessId) -> Result<(BlockNumber, [u8; 32], i16, i16)> { + pub fn get_entropy_for_market_id(&self, id_market: String) -> Result<(BlockNumber, String, i16, i16)> { let caller: AccountId = self.env().caller(); - let market_guess = match self.market_data.get(id_market.clone()) { + let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; @@ -288,26 +304,33 @@ mod oracle_contract { // "block hash entropy must be set prior to obtaining entropy" // ); let block_number_entropy = market_guess.block_number_entropy; - // e."0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" + // "0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" // note: Hash is [u8; 32] 32 bytes (&[u8]) without 0x prefix and 64 symbols, 32 bytes, 256 bits - let block_hash_entropy: [u8; 32] = market_guess.block_hash_entropy.unwrap(); + // TODO - replace with `match` + let block_hash_entropy: String = market_guess.block_hash_entropy.unwrap(); // let block_hash_entropy: &[u8] = // "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".as_bytes(); // note: changed `block_hash_entropy` to `[u8; 32]` instead of `Hash` so we can get the `.len()` - assert!(block_hash_entropy.len() == 32, "block hash should be a 256 bit block hash"); + assert!(block_hash_entropy.len() == 64, "block hash should be a 256 bit block hash"); ink::env::debug_println!("block_hash_entropy: {:?}\n", block_hash_entropy); // https://peterlyons.com/problog/2017/12/rust-converting-bytes-chars-and-strings/ - let (c1_u8a, c2_u8a): (&[u8], &[u8]) = self.last_bytes(&block_hash_entropy); - ink::env::debug_println!("c1_u8a: {:?}\n", c1_u8a); - ink::env::debug_println!("c2_u8a: {:?}\n", c2_u8a); - let c1_hex = String::from_utf8_lossy(&c1_u8a); - let c2_hex = String::from_utf8_lossy(&c2_u8a); + let (c1_str, c2_str): (&str, &str) = self.split_last_bytes(block_hash_entropy.as_str()); + ink::env::debug_println!("c1_str: {:?}\n", c1_str); + ink::env::debug_println!("c2_str: {:?}\n", c2_str); + let c1_hex = String::from(c1_str); + let c2_hex = String::from(c2_str); ink::env::debug_println!("c1_hex: {:?}", c1_hex); ink::env::debug_println!("c2_hex: {:?}", c2_hex); // use u16 since max value 65535 // let without_prefix = hex.trim_start_matches("0x"); - let c1_decimal = i16::from_str_radix(&c1_hex, 16).unwrap(); - let c2_decimal = i16::from_str_radix(&c2_hex, 16).unwrap(); + let c1_decimal = match i16::from_str_radix(&c1_hex, 16) { + Ok(d) => d, + Err(_e) => return Err(Error::InvalidDigit), + }; + let c2_decimal = match i16::from_str_radix(&c2_hex, 16) { + Ok(d) => d, + Err(_e) => return Err(Error::InvalidDigit), + }; ink::env::debug_println!("c1_decimal {:?}", c1_decimal); ink::env::debug_println!("c2_decimal {:?}", c2_decimal); // remainders are 0 or 1 and represent the random side the coin flipped on @@ -317,26 +340,32 @@ mod oracle_contract { ink::env::debug_println!("c2_rem {:?}", c2_rem); self.env().emit_event(GeneratedEntropyForMarketId { - id_market: id_market.clone(), + id_market: id_market.clone().into_bytes(), oracle_owner: caller, block_number_entropy: market_guess.block_number_entropy, - block_hash_entropy: Some(block_hash_entropy), + block_hash_entropy: Some(block_hash_entropy.clone()), c1_entropy: c1_rem, c2_entropy: c2_rem, }); - Ok((block_number_entropy, block_hash_entropy, c1_rem, c2_rem)) + Ok((block_number_entropy, block_hash_entropy.clone(), c1_rem, c2_rem)) } // get symbols 61-64 for coin1 and 57-60 for coin2 fro the block hash - fn last_bytes<'a>(&'a self, slice: &'a [u8; 32]) -> (&[u8], &[u8]) { - let bytes = slice.split_at(slice.len() - 8).1; - (bytes.split_at(bytes.len() - 4).0, bytes.split_at(bytes.len() - 4).1) + fn split_last_bytes<'a>(&'a self, slice: &'a str) -> (&str, &str) { + let len = String::from(slice).len(); + let sub_slice= &slice[len-8..]; + let (c1, c2) = sub_slice.split_at(4); + (c1, c2) } // helper methods - fn exists_market_data_for_id(&self, id_market: MarketGuessId) -> bool { - self.market_data.contains(id_market) + fn exists_market_data_for_id(&self, id_market: &[u8]) -> Result { + let id_market_str = match str::from_utf8(id_market) { + Ok(v) => v, + Err(_e) => return Err(Error::InvalidUTF8Sequence), + }; + Ok(self.market_data.contains(id_market_str.as_bytes().to_vec())) } } } @@ -346,8 +375,6 @@ mod tests { use super::*; use crate::oracle_contract::OracleContract; - // use ethers::core::types::H256; - use ethers_core::types::{H256}; use std::str::FromStr; type BlockNumber = u32; @@ -355,7 +382,7 @@ mod tests { /// We test a simple use case of our contract. #[ink::test] fn it_works() { - let id_market: Vec = String::from_utf8("my_id".into()).unwrap().into(); + let id_market: String = String::from("my_id"); let block_number_guessed = 50; // override `Self::env().block_number();` for tests // See https://substrate.stackexchange.com/questions/8867/how-to-stub-ink-contract-environment-to-produce-fake-values-for-use-in-tests @@ -373,15 +400,12 @@ mod tests { let str_block_hash_entropy: String = "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea".to_string(); - let hash_block_hash_entropy: H256 = str_block_hash_entropy.as_str().parse::().unwrap(); - let bytes_block_hash_entropy: [u8; 32] = hash_block_hash_entropy.to_fixed_bytes(); - new_block_number = 357; // >128 after block_number_entropy (228 + 128 + 1 = 357) ink::env::test::set_block_number::(new_block_number); assert_eq!(oracle_contract.set_block_for_entropy_for_market_id( id_market.clone(), block_number_entropy.clone(), - bytes_block_hash_entropy.clone(), + str_block_hash_entropy.clone(), ), Ok(())); let oracle_contract_address = oracle_contract.get_oracle_contract_address(); @@ -394,7 +418,7 @@ mod tests { ).unwrap(), ( block_number_entropy.clone(), - bytes_block_hash_entropy.clone(), + str_block_hash_entropy.clone(), c1_entropy.clone(), c2_entropy.clone(), ) diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh new file mode 100755 index 0000000..1f62453 --- /dev/null +++ b/docker/quickstart-unnamed.sh @@ -0,0 +1,148 @@ +#!/bin/bash + +# start a fresh substrate-contracts-node and upload the "unnamed" ink! +# smart contracts to it and then instantiate and call a method + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +echo "Killing previous Substrate contracts node..." +# kill the existing substrate-contracts-node that is running on port 30333 +kill -9 $(lsof -ti:30333) &>/dev/null & + +echo "Removing previous database..." +# delete the blockchain database so we don't get this error when we redeploy the +# smart contract `ERROR: This contract has already been uploaded with code hash:` +rm -rf /tmp/ink +sleep 5 + +echo "Running new Substrate contracts node..." +cd ${PARENT_DIR}/docker/ +# https://www.maketecheasier.com/run-bash-commands-background-linux/ +nohup ./run-scn.sh &>/dev/null & +# wait for the blockchain node to start before we interact with it +# note: if you try to interact with it before it is ready then you will get error +# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: +# Error when opening the TCP socket: Cannot assign requested address (os error 99)` +sleep 25 +echo "Building contracts..." +cd $PARENT_DIR/dapps/xcm/unnamed +PROJECT_ROOT=$PARENT_DIR/dapps/xcm/unnamed +cargo contract build \ + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml +cargo contract build \ + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/oracle_contract/Cargo.toml + +cd $PROJECT_ROOT +echo "Uploading sub-contract..." +# upload sub-contract +OUTPUT_CODE_HASH=$( + cargo contract upload --suri //Alice \ + --execute \ + --skip-confirm \ + $PARENT_DIR/target/ink/oracle_contract/oracle_contract.wasm | tail -1 +) +echo "Uploading contract..." +# upload main-contract +OUTPUT_CODE_HASH_MAIN=$( + cargo contract upload --suri //Alice \ + --execute \ + --skip-dry-run \ + --skip-confirm \ + $PARENT_DIR/target/ink/unnamed/unnamed.wasm | tail -1 +) +echo "Finished uploading contracts..." +# example: ' Code hash "0x..."' +echo $OUTPUT_CODE_HASH +# remove text 'Code hash' and the outer double quotes of the code hash +OUTPUT_CODE_HASH_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH" | sed 's/Code hash//;s/$//' | tr -d '"') +# trim whitespace +CODE_HASH=$(echo $OUTPUT_CODE_HASH_REMOVED_LABEL) +echo $CODE_HASH + +# Note: The id_market is stored as Vec format instead of String. +# Paste the following at https://play.rust-lang.org/?version=stable&mode=debug&edition=2021 +# then press the "Run" button and it will output `[109, 121, 95, 105, 100]` +# ```rust +# fn main() -> Result<(), std::io::Error> { +# let s = "my_id".to_string(); +# let b = s.as_bytes(); +# println!("{:?}", b); +# let _y = String::from_utf8(b.to_vec()); +# Ok(()) +# } +# ``` + +# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract + +echo "Instantiating contract..." +OUTPUT_CONTRACT_ADDR=$( + cargo contract instantiate \ + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml \ + --suri //Alice \ + --constructor new \ + --args "$CODE_HASH" "my_id" "100" "228" "500" \ + --execute \ + --skip-dry-run \ + --gas 100000000000 \ + --proof-size 100000000000 \ + --skip-confirm \ + | tail -1 +) + +sleep 5 + +# example: ' Contract 5...' +echo $OUTPUT_CONTRACT_ADDR +# remove text 'Contract' +OUTPUT_CONTRACT_ADDR_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR" | sed 's/Contract//;s/$//') +# trim whitespace +CONTRACT_ADDR=$(echo $OUTPUT_CONTRACT_ADDR_REMOVED_LABEL) +echo $CONTRACT_ADDR +# echo "Calling contract method..." +# note: an example hash value has been used +# TODO - should the hash be '0x' prefixed? +# cargo contract call \ +# --suri //Alice \ +# --contract $CONTRACT_ADDR \ +# --message set_block_for_entropy_for_market_id \ +# --args "my_id" "228" "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" \ +# --execute \ +# --skip-dry-run \ +# --gas 100000000000 \ +# --proof-size 100000000000 \ +# --skip-confirm \ +# | grep --color=always -z 'data' + +# cargo contract call \ +# --suri //Alice \ +# --contract $CONTRACT_ADDR \ +# --message get_entropy_for_market_id \ +# --args "my_id" \ +# --execute \ +# --skip-confirm \ +# | grep --color=always -z 'data' + +# # TODO - why is this method even necessary in the code? was it to override results incase of missed blocks? +# # +# # cargo contract call \ +# # --suri //Alice \ +# # --contract $CONTRACT_ADDR \ +# # --message set_entropy_for_market_id \ +# # --args "my_id" "228" "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" "0" "0" \ +# # --execute \ +# # --skip-confirm \ +# # | grep --color=always -z 'data' + +# # highlight the `data` line in output containing the value of the emitted `Retrieve` event +# cargo contract call \ +# --suri //Alice \ +# --contract $CONTRACT_ADDR \ +# --message get_oracle_contract_address \ +# --execute \ +# --skip-confirm \ +# | grep --color=always -z 'data' From 88782c0d0447802626c8e89c9fb16ffae5395eda Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 15 Jun 2023 13:32:42 +1000 Subject: [PATCH 11/58] working. allow toggle --skip-dry-run with bulk comment --- README.md | 3 + dapps/xcm/unnamed/lib.rs | 19 +- dapps/xcm/unnamed/oracle_contract/lib.rs | 1 + docker/quickstart-unnamed.sh | 219 +++++++++++++++-------- 4 files changed, 162 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index eca59df..79f7153 100644 --- a/README.md +++ b/README.md @@ -424,6 +424,9 @@ docker buildx rm --all-inactive * Contracts pallet allows deployment and execution of WebAssembly-based smart contracts * What trait do smart contract accounts used in the Contracts pallet of Substrate extend? * `Currency` trait + * How to resolve `ERROR: This contract has already been uploaded with code hash` + * It may be because you ran a Substrate contract node on your host machine and then tried running another one in your Docker container. So it may be necessary to run `kill -9 $(lsof -ti:30333)` on + both the host machine and inside the Docker container. Or just restart Docker. * Link diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index f9f3f9d..72ea05f 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -83,11 +83,28 @@ mod unnamed { } } + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` + #[ink(message)] + pub fn get_entropy_for_market_id(&self, id_market: String) -> Result<(BlockNumber, String, i16, i16)> { + match &self.oracle_contract { + Some(c) => { + let res = match c.clone().get_entropy_for_market_id(id_market) { + Ok(r) => r, + Err(_e) => panic!("arr {:?}", _e), + }; + Ok(res) + }, + None => return Err(Error::NoOracleContractAddress), + } + } + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] pub fn get_oracle_contract_address(&self) -> Result { match &self.oracle_contract { - Some(c) => Ok(c.get_oracle_contract_address()), + Some(c) => { + Ok(c.clone().get_oracle_contract_address()) + }, None => return Err(Error::NoOracleContractAddress), } } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 8641dee..9f1714c 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -285,6 +285,7 @@ mod oracle_contract { #[ink(message)] pub fn get_oracle_contract_address(&self) -> AccountId { + ink::env::debug_println!("oracle contract address {:?}", self.env().account_id()); self.env().account_id() } diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh index 1f62453..6c13291 100755 --- a/docker/quickstart-unnamed.sh +++ b/docker/quickstart-unnamed.sh @@ -1,7 +1,12 @@ #!/bin/bash +# compatibility cargo-contract v3.0.1 +# # start a fresh substrate-contracts-node and upload the "unnamed" ink! # smart contracts to it and then instantiate and call a method +# +# if you want to sky dry run then find/replace `--skip-dry-run` with `#--skip-dry-run` +# to comment those lines out trap "echo; exit" INT trap "echo; exit" HUP @@ -18,7 +23,6 @@ echo "Removing previous database..." # delete the blockchain database so we don't get this error when we redeploy the # smart contract `ERROR: This contract has already been uploaded with code hash:` rm -rf /tmp/ink -sleep 5 echo "Running new Substrate contracts node..." cd ${PARENT_DIR}/docker/ @@ -40,29 +44,52 @@ cargo contract build \ cd $PROJECT_ROOT echo "Uploading sub-contract..." # upload sub-contract -OUTPUT_CODE_HASH=$( - cargo contract upload --suri //Alice \ - --execute \ - --skip-confirm \ - $PARENT_DIR/target/ink/oracle_contract/oracle_contract.wasm | tail -1 +# +# note: provide args variable so able to comment out all `--skip-dry-run` options in bulk +# since it breaks command if comment out a multiline command option `#--skip-dry-run \` +# see https://stackoverflow.com/a/9522766/3208553 +args=( + --suri //Alice + --execute + --skip-dry-run + --skip-confirm + $PARENT_DIR/target/ink/oracle_contract/oracle_contract.wasm ) -echo "Uploading contract..." +OUTPUT_CODE_HASH_SUB=$( + cargo contract upload "${args[@]}" | tail -1 +) +echo "Finished uploading contract..." +# example: ' Code hash "0x..."' +echo $OUTPUT_CODE_HASH_SUB +# remove text 'Code hash' and the outer double quotes of the code hash +OUTPUT_CODE_HASH_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH_SUB" | sed 's/Code hash//;s/$//' | tr -d '"') +# trim whitespace +CODE_HASH_SUB=$(echo $OUTPUT_CODE_HASH_SUB_REMOVED_LABEL) +echo $CODE_HASH_SUB + +echo "Uploading main-contract..." # upload main-contract +# +args=( + --suri //Alice + --execute + # --skip-dry-run + --skip-confirm + $PARENT_DIR/target/ink/unnamed/unnamed.wasm +) OUTPUT_CODE_HASH_MAIN=$( - cargo contract upload --suri //Alice \ - --execute \ - --skip-dry-run \ - --skip-confirm \ - $PARENT_DIR/target/ink/unnamed/unnamed.wasm | tail -1 + cargo contract upload "${args[@]}" | tail -1 ) -echo "Finished uploading contracts..." +echo "Finished uploading contract..." # example: ' Code hash "0x..."' -echo $OUTPUT_CODE_HASH +echo $OUTPUT_CODE_HASH_MAIN # remove text 'Code hash' and the outer double quotes of the code hash -OUTPUT_CODE_HASH_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH" | sed 's/Code hash//;s/$//' | tr -d '"') +OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH_MAIN" | sed 's/Code hash//;s/$//' | tr -d '"') # trim whitespace -CODE_HASH=$(echo $OUTPUT_CODE_HASH_REMOVED_LABEL) -echo $CODE_HASH +CODE_HASH_MAIN=$(echo $OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL) +echo $CODE_HASH_MAIN + +ARG_ID_MARKET="\"my_id\"" # Note: The id_market is stored as Vec format instead of String. # Paste the following at https://play.rust-lang.org/?version=stable&mode=debug&edition=2021 @@ -78,71 +105,105 @@ echo $CODE_HASH # ``` # instantiate "main" contract, providing the code hash generated from uploading the "sub" contract +echo "Instantiating main-contract..." -echo "Instantiating contract..." -OUTPUT_CONTRACT_ADDR=$( - cargo contract instantiate \ - --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml \ - --suri //Alice \ - --constructor new \ - --args "$CODE_HASH" "my_id" "100" "228" "500" \ - --execute \ - --skip-dry-run \ - --gas 100000000000 \ - --proof-size 100000000000 \ - --skip-confirm \ - | tail -1 +args=( + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml + --suri //Alice + --constructor new + --args $CODE_HASH_SUB $ARG_ID_MARKET "100" "228" "500" + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +OUTPUT_CONTRACT_ADDR_MAIN=$( + cargo contract instantiate "${args[@]}" | tail -1 ) -sleep 5 +# example: ' Contract 5...' +echo $OUTPUT_CONTRACT_ADDR_MAIN +# remove text 'Contract' +OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') +# trim whitespace using `echo ...` +CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) +echo $CONTRACT_ADDR_MAIN + +echo "Instantiating sub-contract..." +args=( + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/oracle_contract/Cargo.toml + --suri //Alice + --constructor new + --args $ARG_ID_MARKET "100" "228" "500" + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +OUTPUT_CONTRACT_ADDR_SUB=$( + cargo contract instantiate "${args[@]}" | tail -1 +) # example: ' Contract 5...' -echo $OUTPUT_CONTRACT_ADDR +echo $OUTPUT_CONTRACT_ADDR_SUB # remove text 'Contract' -OUTPUT_CONTRACT_ADDR_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR" | sed 's/Contract//;s/$//') -# trim whitespace -CONTRACT_ADDR=$(echo $OUTPUT_CONTRACT_ADDR_REMOVED_LABEL) -echo $CONTRACT_ADDR -# echo "Calling contract method..." -# note: an example hash value has been used -# TODO - should the hash be '0x' prefixed? -# cargo contract call \ -# --suri //Alice \ -# --contract $CONTRACT_ADDR \ -# --message set_block_for_entropy_for_market_id \ -# --args "my_id" "228" "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" \ -# --execute \ -# --skip-dry-run \ -# --gas 100000000000 \ -# --proof-size 100000000000 \ -# --skip-confirm \ -# | grep --color=always -z 'data' - -# cargo contract call \ -# --suri //Alice \ -# --contract $CONTRACT_ADDR \ -# --message get_entropy_for_market_id \ -# --args "my_id" \ -# --execute \ -# --skip-confirm \ -# | grep --color=always -z 'data' - -# # TODO - why is this method even necessary in the code? was it to override results incase of missed blocks? -# # -# # cargo contract call \ -# # --suri //Alice \ -# # --contract $CONTRACT_ADDR \ -# # --message set_entropy_for_market_id \ -# # --args "my_id" "228" "aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" "0" "0" \ -# # --execute \ -# # --skip-confirm \ -# # | grep --color=always -z 'data' - -# # highlight the `data` line in output containing the value of the emitted `Retrieve` event -# cargo contract call \ -# --suri //Alice \ -# --contract $CONTRACT_ADDR \ -# --message get_oracle_contract_address \ -# --execute \ -# --skip-confirm \ -# | grep --color=always -z 'data' +OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') +# trim whitespace using `echo ...` +CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) +echo $CONTRACT_ADDR_SUB + +ARG_BLOCK_HASH_ENTROPY="\"aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea\"" + +echo "Calling contract method set_block_for_entropy_for_market_id..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message set_block_for_entropy_for_market_id + --args $ARG_ID_MARKET "228" $ARG_BLOCK_HASH_ENTROPY + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + +echo "Calling contract method get_entropy_for_market_id ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message get_entropy_for_market_id + --args $ARG_ID_MARKET + --execute + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + +# TODO - consider removing. maybe use to override results incase of missed blocks? +# +# args=( +# --suri //Alice +# --contract $CONTRACT_ADDR_MAIN +# --message set_entropy_for_market_id +# --args $ARG_ID_MARKET "228" $ARG_BLOCK_HASH_ENTROPY "0" "0" +# --execute +# # --skip-dry-run +# --skip-confirm +# ) +# cargo contract call "${args[@]}" | grep --color=always -z 'data' + +# highlight the `data` line in output containing the value of the emitted `Retrieve` event +echo "Calling contract method get_oracle_contract_address ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message get_oracle_contract_address + --execute + # --skip-dry-run + --skip-confirm +) +# FIXME - why doesn't this return anything? +cargo contract call "${args[@]}" | grep --color=always -z 'data' From aeb12bcb35910170647225e1d3a9ef981821841c Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 15 Jun 2023 18:33:39 +1000 Subject: [PATCH 12/58] add basic_contract_caller from ink-examples --- Cargo.toml | 1 + dapps/basic_contract_caller/.gitignore | 9 + dapps/basic_contract_caller/Cargo.toml | 37 ++++ dapps/basic_contract_caller/lib.rs | 41 +++++ .../other_contract/.gitignore | 9 + .../other_contract/Cargo.toml | 28 +++ .../other_contract/lib.rs | 33 ++++ docker/quickstart-basic-contract-caller.sh | 172 ++++++++++++++++++ 8 files changed, 330 insertions(+) create mode 100755 dapps/basic_contract_caller/.gitignore create mode 100755 dapps/basic_contract_caller/Cargo.toml create mode 100755 dapps/basic_contract_caller/lib.rs create mode 100755 dapps/basic_contract_caller/other_contract/.gitignore create mode 100755 dapps/basic_contract_caller/other_contract/Cargo.toml create mode 100755 dapps/basic_contract_caller/other_contract/lib.rs create mode 100755 docker/quickstart-basic-contract-caller.sh diff --git a/Cargo.toml b/Cargo.toml index cb11d89..5313a6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ exclude = [] members = [ "dapps/ink-rust/wasm-flipper/contract/flipper", "dapps/xcm/unnamed", + "dapps/basic_contract_caller", ] diff --git a/dapps/basic_contract_caller/.gitignore b/dapps/basic_contract_caller/.gitignore new file mode 100755 index 0000000..8de8f87 --- /dev/null +++ b/dapps/basic_contract_caller/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/dapps/basic_contract_caller/Cargo.toml b/dapps/basic_contract_caller/Cargo.toml new file mode 100755 index 0000000..fc4a7f9 --- /dev/null +++ b/dapps/basic_contract_caller/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "basic_contract_caller" +version = "4.2.0" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { version = "4.2", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } + +# Note: We **need** to specify the `ink-as-dependency` feature. +# +# If we don't we will end up with linking errors! +other_contract = { path = "other_contract", default-features = false, features = ["ink-as-dependency"] } + +[dev-dependencies] +ink_e2e = { version = "4.2" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + + # Note: The metadata generation step requires `std`. If we don't specify this the metadata + # generation for our contract will fail! + "other_contract/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs new file mode 100755 index 0000000..f988caa --- /dev/null +++ b/dapps/basic_contract_caller/lib.rs @@ -0,0 +1,41 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +#[ink::contract] +mod basic_contract_caller { + /// We import the generated `ContractRef` of our other contract. + /// + /// Note that the other contract must have re-exported it (`pub use + /// OtherContractRef`) for us to have access to it. + use other_contract::OtherContractRef; + + #[ink(storage)] + pub struct BasicContractCaller { + /// We specify that our contract will store a reference to the `OtherContract`. + other_contract: OtherContractRef, + } + + impl BasicContractCaller { + /// In order to use the `OtherContract` we first need to **instantiate** it. + /// + /// To do this we will use the uploaded `code_hash` of `OtherContract`. + #[ink(constructor)] + pub fn new(other_contract_code_hash: Hash) -> Self { + let other_contract = OtherContractRef::new(true) + .code_hash(other_contract_code_hash) + .endowment(0) + .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) + .instantiate(); + + Self { other_contract } + } + + /// Using the `ContractRef` we can call all the messages of the `OtherContract` as + /// if they were normal Rust methods (because at the end of the day, they + /// are!). + #[ink(message)] + pub fn flip_and_get(&mut self) -> bool { + self.other_contract.flip(); + self.other_contract.get() + } + } +} diff --git a/dapps/basic_contract_caller/other_contract/.gitignore b/dapps/basic_contract_caller/other_contract/.gitignore new file mode 100755 index 0000000..8de8f87 --- /dev/null +++ b/dapps/basic_contract_caller/other_contract/.gitignore @@ -0,0 +1,9 @@ +# Ignore build artifacts from the local tests sub-crate. +/target/ + +# Ignore backup files creates by cargo fmt. +**/*.rs.bk + +# Remove Cargo.lock when creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/dapps/basic_contract_caller/other_contract/Cargo.toml b/dapps/basic_contract_caller/other_contract/Cargo.toml new file mode 100755 index 0000000..70a068e --- /dev/null +++ b/dapps/basic_contract_caller/other_contract/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "other_contract" +version = "4.2.0" +authors = ["Parity Technologies "] +edition = "2021" +publish = false + +[dependencies] +ink = { version = "4.2", default-features = false } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } + +[dev-dependencies] +ink_e2e = { path = "../../../crates/e2e" } + +[lib] +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/dapps/basic_contract_caller/other_contract/lib.rs b/dapps/basic_contract_caller/other_contract/lib.rs new file mode 100755 index 0000000..53e5101 --- /dev/null +++ b/dapps/basic_contract_caller/other_contract/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] + +/// Re-export the `ContractRef` generated by the ink! codegen. +/// +/// This let's other crates which pull this contract in as a dependency to interact +/// with this contract in a type-safe way. +pub use self::other_contract::OtherContractRef; + +#[ink::contract] +mod other_contract { + + #[ink(storage)] + pub struct OtherContract { + value: bool, + } + + impl OtherContract { + #[ink(constructor)] + pub fn new(init_value: bool) -> Self { + Self { value: init_value } + } + + #[ink(message)] + pub fn flip(&mut self) { + self.value = !self.value; + } + + #[ink(message)] + pub fn get(&self) -> bool { + self.value + } + } +} diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh new file mode 100755 index 0000000..afe5792 --- /dev/null +++ b/docker/quickstart-basic-contract-caller.sh @@ -0,0 +1,172 @@ +#!/bin/bash + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +echo "Killing previous Substrate contracts node..." +# kill the existing substrate-contracts-node that is running on port 30333 +kill -9 $(lsof -ti:30333) &>/dev/null & + +echo "Removing previous database..." +# delete the blockchain database so we don't get this error when we redeploy the +# smart contract `ERROR: This contract has already been uploaded with code hash:` +rm -rf /tmp/ink + +echo "Running new Substrate contracts node..." +cd ${PARENT_DIR}/docker/ +# https://www.maketecheasier.com/run-bash-commands-background-linux/ +nohup ./run-scn.sh &>/dev/null & +# wait for the blockchain node to start before we interact with it +# note: if you try to interact with it before it is ready then you will get error +# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: +# Error when opening the TCP socket: Cannot assign requested address (os error 99)` +sleep 25 +echo "Building contracts..." +cd $PARENT_DIR/dapps/basic_contract_caller +PROJECT_ROOT=$PARENT_DIR/dapps/basic_contract_caller +cargo contract build \ + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/Cargo.toml +cargo contract build \ + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/other_contract/Cargo.toml + +cd $PROJECT_ROOT +echo "Uploading sub-contract..." +# upload sub-contract +# +# note: provide args variable so able to comment out all `--skip-dry-run` options in bulk +# since it breaks command if comment out a multiline command option `#--skip-dry-run \` +# see https://stackoverflow.com/a/9522766/3208553 +args=( + --suri //Alice + --execute + --skip-dry-run + --skip-confirm + $PARENT_DIR/target/ink/other_contract/other_contract.wasm +) +OUTPUT_CODE_HASH_SUB=$( + cargo contract upload "${args[@]}" | tail -1 +) +echo "Finished uploading contract..." +# example: ' Code hash "0x..."' +echo $OUTPUT_CODE_HASH_SUB +# remove text 'Code hash' and the outer double quotes of the code hash +OUTPUT_CODE_HASH_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH_SUB" | sed 's/Code hash//;s/$//' | tr -d '"') +# trim whitespace +CODE_HASH_SUB=$(echo $OUTPUT_CODE_HASH_SUB_REMOVED_LABEL) +echo $CODE_HASH_SUB + +echo "Uploading main-contract..." +# upload main-contract +# +args=( + --suri //Alice + --execute + # --skip-dry-run + --skip-confirm + $PARENT_DIR/target/ink/basic_contract_caller/basic_contract_caller.wasm +) +OUTPUT_CODE_HASH_MAIN=$( + cargo contract upload "${args[@]}" | tail -1 +) +echo "Finished uploading contract..." +# example: ' Code hash "0x..."' +echo $OUTPUT_CODE_HASH_MAIN +# remove text 'Code hash' and the outer double quotes of the code hash +OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH_MAIN" | sed 's/Code hash//;s/$//' | tr -d '"') +# trim whitespace +CODE_HASH_MAIN=$(echo $OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL) +echo $CODE_HASH_MAIN + +ARG_ID_MARKET="\"my_id\"" + + +# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract +echo "Instantiating main-contract..." + +args=( + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/Cargo.toml + --suri //Alice + --constructor new + --args "true" + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +OUTPUT_CONTRACT_ADDR_MAIN=$( + cargo contract instantiate "${args[@]}" | tail -1 +) + +# example: ' Contract 5...' +echo $OUTPUT_CONTRACT_ADDR_MAIN +# remove text 'Contract' +OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') +# trim whitespace using `echo ...` +CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) +echo $CONTRACT_ADDR_MAIN + +echo "Instantiating sub-contract..." +args=( + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/other_contract/Cargo.toml + --suri //Alice + --constructor new + --args "true" + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +OUTPUT_CONTRACT_ADDR_SUB=$( + cargo contract instantiate "${args[@]}" | tail -1 +) + +# example: ' Contract 5...' +echo $OUTPUT_CONTRACT_ADDR_SUB +# remove text 'Contract' +OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') +# trim whitespace using `echo ...` +CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) +echo $CONTRACT_ADDR_SUB + +echo "Calling contract method flip..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message flip + --execute + --gas 100000000000 + --proof-size 100000000000 + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + +echo "Calling contract method get ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message get + --execute + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + +# highlight the `data` line in output containing the value of the emitted `Retrieve` event +echo "Calling contract method get_other_contract_address ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message get_other_contract_address + --execute + # --skip-dry-run + --skip-confirm +) +# FIXME - why doesn't this return anything? +cargo contract call "${args[@]}" | grep --color=always -z 'data' From ed4290e1fc13624388bd97a2fcee9c4f1a3296d0 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 16 Jun 2023 10:10:54 +1000 Subject: [PATCH 13/58] add basic_contract_caller all working --- Cargo.lock | 21 +++++++ dapps/basic_contract_caller/Cargo.toml | 6 +- dapps/basic_contract_caller/lib.rs | 59 +++++++++++++++++-- .../other_contract/Cargo.toml | 6 +- .../other_contract/lib.rs | 6 ++ docker/quickstart-basic-contract-caller.sh | 34 ++++++++--- docker/quickstart-unnamed.sh | 3 +- 7 files changed, 116 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cf352b..320c974 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,6 +247,17 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "basic_contract_caller" +version = "4.2.0" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_e2e", + "other_contract", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "beef" version = "0.5.2" @@ -2458,6 +2469,16 @@ dependencies = [ "scale-info", ] +[[package]] +name = "other_contract" +version = "4.2.0" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_e2e", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-contracts-primitives" version = "23.0.0" diff --git a/dapps/basic_contract_caller/Cargo.toml b/dapps/basic_contract_caller/Cargo.toml index fc4a7f9..dd93c15 100755 --- a/dapps/basic_contract_caller/Cargo.toml +++ b/dapps/basic_contract_caller/Cargo.toml @@ -8,8 +8,8 @@ publish = false [dependencies] ink = { version = "4.2", default-features = false } -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } # Note: We **need** to specify the `ink-as-dependency` feature. # @@ -17,7 +17,7 @@ scale-info = { version = "2.5", default-features = false, features = ["derive"], other_contract = { path = "other_contract", default-features = false, features = ["ink-as-dependency"] } [dev-dependencies] -ink_e2e = { version = "4.2" } +ink_e2e = { version = "4.2.0" } [lib] path = "lib.rs" diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index f988caa..8212824 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -11,9 +11,20 @@ mod basic_contract_caller { #[ink(storage)] pub struct BasicContractCaller { /// We specify that our contract will store a reference to the `OtherContract`. - other_contract: OtherContractRef, + other_contract: Option, } + /// Errors that can occur upon calling this contract. + #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] + #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] + pub enum Error { + /// Returned if not other contract address exists. + NoOtherContractAddress, + } + + /// Type alias for the contract's result type. + pub type Result = core::result::Result; + impl BasicContractCaller { /// In order to use the `OtherContract` we first need to **instantiate** it. /// @@ -26,16 +37,54 @@ mod basic_contract_caller { .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) .instantiate(); - Self { other_contract } + Self { other_contract: Some(other_contract) } + } + + #[ink(message)] + pub fn get(&mut self) -> Result { + match &self.other_contract { + Some(c) => { + Ok(c.clone().get()) + }, + None => return Err(Error::NoOtherContractAddress), + } + } + + #[ink(message)] + pub fn flip(&mut self) -> Result<()> { + match &self.other_contract { + Some(c) => { + c.clone().flip(); + Ok(()) + }, + None => return Err(Error::NoOtherContractAddress), + } } /// Using the `ContractRef` we can call all the messages of the `OtherContract` as /// if they were normal Rust methods (because at the end of the day, they /// are!). #[ink(message)] - pub fn flip_and_get(&mut self) -> bool { - self.other_contract.flip(); - self.other_contract.get() + pub fn flip_and_get(&mut self) -> Result { + match &self.other_contract { + Some(c) => { + c.clone().flip(); + Ok(c.clone().get()) + }, + None => return Err(Error::NoOtherContractAddress), + } + } + + + /// Using the `OtherContractRef` we can call all the messages of the `OtherContract` + #[ink(message)] + pub fn get_other_contract_address(&self) -> Result { + match &self.other_contract { + Some(c) => { + Ok(c.clone().get_other_contract_address()) + }, + None => return Err(Error::NoOtherContractAddress), + } } } } diff --git a/dapps/basic_contract_caller/other_contract/Cargo.toml b/dapps/basic_contract_caller/other_contract/Cargo.toml index 70a068e..0c1a55d 100755 --- a/dapps/basic_contract_caller/other_contract/Cargo.toml +++ b/dapps/basic_contract_caller/other_contract/Cargo.toml @@ -8,11 +8,11 @@ publish = false [dependencies] ink = { version = "4.2", default-features = false } -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2.5", default-features = false, features = ["derive"], optional = true } +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } [dev-dependencies] -ink_e2e = { path = "../../../crates/e2e" } +ink_e2e = "4.2.0" [lib] path = "lib.rs" diff --git a/dapps/basic_contract_caller/other_contract/lib.rs b/dapps/basic_contract_caller/other_contract/lib.rs index 53e5101..d1e9ca5 100755 --- a/dapps/basic_contract_caller/other_contract/lib.rs +++ b/dapps/basic_contract_caller/other_contract/lib.rs @@ -29,5 +29,11 @@ mod other_contract { pub fn get(&self) -> bool { self.value } + + #[ink(message)] + pub fn get_other_contract_address(&self) -> AccountId { + ink::env::debug_println!("oracle contract address {:?}", self.env().account_id()); + self.env().account_id() + } } } diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index afe5792..a551ebe 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -43,7 +43,7 @@ echo "Uploading sub-contract..." args=( --suri //Alice --execute - --skip-dry-run + # --skip-dry-run --skip-confirm $PARENT_DIR/target/ink/other_contract/other_contract.wasm ) @@ -81,8 +81,7 @@ OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH_MAIN" | sed 's/Cod CODE_HASH_MAIN=$(echo $OUTPUT_CODE_HASH_MAIN_REMOVED_LABEL) echo $CODE_HASH_MAIN -ARG_ID_MARKET="\"my_id\"" - +cd $PROJECT_ROOT # instantiate "main" contract, providing the code hash generated from uploading the "sub" contract echo "Instantiating main-contract..." @@ -91,7 +90,7 @@ args=( --manifest-path $PARENT_DIR/dapps/basic_contract_caller/Cargo.toml --suri //Alice --constructor new - --args "true" + --args $CODE_HASH_SUB --execute --gas 100000000000 --proof-size 100000000000 @@ -115,7 +114,7 @@ args=( --manifest-path $PARENT_DIR/dapps/basic_contract_caller/other_contract/Cargo.toml --suri //Alice --constructor new - --args "true" + --args true --execute --gas 100000000000 --proof-size 100000000000 @@ -137,7 +136,7 @@ echo $CONTRACT_ADDR_SUB echo "Calling contract method flip..." args=( --suri //Alice - --contract $CONTRACT_ADDR_MAIN + --contract $CONTRACT_ADDR_SUB --message flip --execute --gas 100000000000 @@ -147,6 +146,17 @@ args=( ) cargo contract call "${args[@]}" | grep --color=always -z 'data' +echo "Calling contract method get ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_SUB + --message get + --execute + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + echo "Calling contract method get ..." args=( --suri //Alice @@ -158,6 +168,17 @@ args=( ) cargo contract call "${args[@]}" | grep --color=always -z 'data' +echo "Calling contract method flip_and_get ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message flip_and_get + --execute + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' + # highlight the `data` line in output containing the value of the emitted `Retrieve` event echo "Calling contract method get_other_contract_address ..." args=( @@ -168,5 +189,4 @@ args=( # --skip-dry-run --skip-confirm ) -# FIXME - why doesn't this return anything? cargo contract call "${args[@]}" | grep --color=always -z 'data' diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh index 6c13291..1c95caf 100755 --- a/docker/quickstart-unnamed.sh +++ b/docker/quickstart-unnamed.sh @@ -104,6 +104,8 @@ ARG_ID_MARKET="\"my_id\"" # } # ``` +cd $PROJECT_ROOT + # instantiate "main" contract, providing the code hash generated from uploading the "sub" contract echo "Instantiating main-contract..." @@ -205,5 +207,4 @@ args=( # --skip-dry-run --skip-confirm ) -# FIXME - why doesn't this return anything? cargo contract call "${args[@]}" | grep --color=always -z 'data' From 931fe208737aca934a01768e75ff715e9ded3b53 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 16 Jun 2023 10:25:43 +1000 Subject: [PATCH 14/58] remove get message from main contract and do not call it generates error --- dapps/basic_contract_caller/lib.rs | 18 +++++++++--------- docker/quickstart-basic-contract-caller.sh | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index 8212824..a9a27e1 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -40,15 +40,15 @@ mod basic_contract_caller { Self { other_contract: Some(other_contract) } } - #[ink(message)] - pub fn get(&mut self) -> Result { - match &self.other_contract { - Some(c) => { - Ok(c.clone().get()) - }, - None => return Err(Error::NoOtherContractAddress), - } - } + // #[ink(message)] + // pub fn get(&mut self) -> Result { + // match &self.other_contract { + // Some(c) => { + // Ok(c.clone().get()) + // }, + // None => return Err(Error::NoOtherContractAddress), + // } + // } #[ink(message)] pub fn flip(&mut self) -> Result<()> { diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index a551ebe..fa3843e 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -157,16 +157,16 @@ args=( ) cargo contract call "${args[@]}" | grep --color=always -z 'data' -echo "Calling contract method get ..." -args=( - --suri //Alice - --contract $CONTRACT_ADDR_MAIN - --message get - --execute - # --skip-dry-run - --skip-confirm -) -cargo contract call "${args[@]}" | grep --color=always -z 'data' +# echo "Calling contract method get ..." +# args=( +# --suri //Alice +# --contract $CONTRACT_ADDR_MAIN +# --message get +# --execute +# # --skip-dry-run +# --skip-confirm +# ) +# cargo contract call "${args[@]}" | grep --color=always -z 'data' echo "Calling contract method flip_and_get ..." args=( From 4217f6b461e8fb556bc4c838c304697774737934 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 16 Jun 2023 14:08:08 +1000 Subject: [PATCH 15/58] restore get method in main contract --- dapps/basic_contract_caller/lib.rs | 18 +++++++++--------- docker/quickstart-basic-contract-caller.sh | 20 ++++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index a9a27e1..8212824 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -40,15 +40,15 @@ mod basic_contract_caller { Self { other_contract: Some(other_contract) } } - // #[ink(message)] - // pub fn get(&mut self) -> Result { - // match &self.other_contract { - // Some(c) => { - // Ok(c.clone().get()) - // }, - // None => return Err(Error::NoOtherContractAddress), - // } - // } + #[ink(message)] + pub fn get(&mut self) -> Result { + match &self.other_contract { + Some(c) => { + Ok(c.clone().get()) + }, + None => return Err(Error::NoOtherContractAddress), + } + } #[ink(message)] pub fn flip(&mut self) -> Result<()> { diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index fa3843e..a551ebe 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -157,16 +157,16 @@ args=( ) cargo contract call "${args[@]}" | grep --color=always -z 'data' -# echo "Calling contract method get ..." -# args=( -# --suri //Alice -# --contract $CONTRACT_ADDR_MAIN -# --message get -# --execute -# # --skip-dry-run -# --skip-confirm -# ) -# cargo contract call "${args[@]}" | grep --color=always -z 'data' +echo "Calling contract method get ..." +args=( + --suri //Alice + --contract $CONTRACT_ADDR_MAIN + --message get + --execute + # --skip-dry-run + --skip-confirm +) +cargo contract call "${args[@]}" | grep --color=always -z 'data' echo "Calling contract method flip_and_get ..." args=( From 455c222c08127f461b2f23897ead1663a9e1d927 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 16 Jun 2023 18:13:05 +1000 Subject: [PATCH 16/58] convert to CreateBuilder and CallBuilder but with error when call via main contract ERROR: Pre-submission dry-run failed --- dapps/basic_contract_caller/lib.rs | 100 +++++++++++++++++---- dapps/ink-python/example/src/app.py | 2 +- docker/quickstart-basic-contract-caller.sh | 50 ++++++----- docker/quickstart-unnamed.sh | 12 +-- 4 files changed, 119 insertions(+), 45 deletions(-) diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index 8212824..c8fc8ce 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -2,6 +2,15 @@ #[ink::contract] mod basic_contract_caller { + use ink::env::{ + call::{ + build_create, + build_call, + ExecutionInput, + Selector, + }, + DefaultEnvironment, + }; /// We import the generated `ContractRef` of our other contract. /// /// Note that the other contract must have re-exported it (`pub use @@ -12,6 +21,7 @@ mod basic_contract_caller { pub struct BasicContractCaller { /// We specify that our contract will store a reference to the `OtherContract`. other_contract: Option, + other_contract_address: Option, } /// Errors that can occur upon calling this contract. @@ -30,21 +40,44 @@ mod basic_contract_caller { /// /// To do this we will use the uploaded `code_hash` of `OtherContract`. #[ink(constructor)] - pub fn new(other_contract_code_hash: Hash) -> Self { - let other_contract = OtherContractRef::new(true) + pub fn new(other_contract_code_hash: Hash, other_contract_address: AccountId) -> Self { + // using `CreateBuilder` to instantiate contract + // https://use.ink/basics/cross-contract-calling#createbuilder + let other_contract: OtherContractRef = build_create::() .code_hash(other_contract_code_hash) + // https://substrate.stackexchange.com/questions/3992/i-get-a-the-executed-contract-exhausted-its-gas-limit-when-attempting-to-inst + .gas_limit(100000000000) + // https://substrate.stackexchange.com/questions/8445/cross-contract-instantiation-failed-with-transferfailed/8447#8447 .endowment(0) - .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("new"))) + .push_arg(true) + ) + .salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF]) + .returns::() .instantiate(); - Self { other_contract: Some(other_contract) } + Self { + other_contract: Some(other_contract), + other_contract_address: Some(other_contract_address), + } } #[ink(message)] pub fn get(&mut self) -> Result { - match &self.other_contract { + match &self.other_contract_address { Some(c) => { - Ok(c.clone().get()) + ink::env::debug_println!("c {:?}", c.clone()); + let my_return_value = build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(10) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get"))) + ) + .returns::() + .invoke(); + Ok(my_return_value) }, None => return Err(Error::NoOtherContractAddress), } @@ -52,36 +85,67 @@ mod basic_contract_caller { #[ink(message)] pub fn flip(&mut self) -> Result<()> { - match &self.other_contract { + match &self.other_contract_address { Some(c) => { - c.clone().flip(); + // using CallBuilder + // https://use.ink/basics/cross-contract-calling#callbuilder + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(10) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) + ) + .returns::<()>() + .invoke(); Ok(()) }, None => return Err(Error::NoOtherContractAddress), } } - /// Using the `ContractRef` we can call all the messages of the `OtherContract` as - /// if they were normal Rust methods (because at the end of the day, they - /// are!). #[ink(message)] pub fn flip_and_get(&mut self) -> Result { - match &self.other_contract { + match &self.other_contract_address { Some(c) => { - c.clone().flip(); - Ok(c.clone().get()) + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(10) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) + ) + .returns::<()>() + .invoke(); + let my_return_value = build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(10) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get"))) + ) + .returns::() + .invoke(); + Ok(my_return_value) }, None => return Err(Error::NoOtherContractAddress), } } - - /// Using the `OtherContractRef` we can call all the messages of the `OtherContract` #[ink(message)] pub fn get_other_contract_address(&self) -> Result { - match &self.other_contract { + match &self.other_contract_address { Some(c) => { - Ok(c.clone().get_other_contract_address()) + let my_return_value = build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(10) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_other_contract_address"))) + ) + .returns::() + .invoke(); + Ok(my_return_value) }, None => return Err(Error::NoOtherContractAddress), } diff --git a/dapps/ink-python/example/src/app.py b/dapps/ink-python/example/src/app.py index fc4ebc5..bc593f2 100644 --- a/dapps/ink-python/example/src/app.py +++ b/dapps/ink-python/example/src/app.py @@ -81,7 +81,7 @@ args={'init_value': True}, value=0, # endowment=0, - gas_limit={'ref_time': 50_000_000_000, 'proof_size': 10_000_000}, # gas_limit=1000000000000, # gas_limit: dict = None, + gas_limit={'ref_time': 50_000_000_000, 'proof_size': 10_000_000}, # gas_limit=10000000000000, # gas_limit: dict = None, deployment_salt="", upload_code=True, storage_deposit_limit=1_000_000_000_000 diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index a551ebe..3c3eb9a 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -83,55 +83,59 @@ echo $CODE_HASH_MAIN cd $PROJECT_ROOT -# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract -echo "Instantiating main-contract..." - +echo "Instantiating sub-contract..." args=( - --manifest-path $PARENT_DIR/dapps/basic_contract_caller/Cargo.toml + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/other_contract/Cargo.toml --suri //Alice --constructor new - --args $CODE_HASH_SUB + --args true --execute + # unlimited gas is 0 --gas 100000000000 --proof-size 100000000000 # --skip-dry-run --skip-confirm ) -OUTPUT_CONTRACT_ADDR_MAIN=$( +OUTPUT_CONTRACT_ADDR_SUB=$( cargo contract instantiate "${args[@]}" | tail -1 ) # example: ' Contract 5...' -echo $OUTPUT_CONTRACT_ADDR_MAIN +echo $OUTPUT_CONTRACT_ADDR_SUB # remove text 'Contract' -OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') +OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') # trim whitespace using `echo ...` -CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) -echo $CONTRACT_ADDR_MAIN +CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) +echo $CONTRACT_ADDR_SUB + +# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract +echo "Instantiating main-contract..." -echo "Instantiating sub-contract..." args=( - --manifest-path $PARENT_DIR/dapps/basic_contract_caller/other_contract/Cargo.toml + --manifest-path $PARENT_DIR/dapps/basic_contract_caller/Cargo.toml --suri //Alice --constructor new - --args true + --args $CODE_HASH_SUB $CONTRACT_ADDR_SUB --execute - --gas 100000000000 + # unlimited gas is 0 + # --storage-deposit-limit 50000000000 \ + # https://substrate.stackexchange.com/questions/3992/i-get-a-the-executed-contract-exhausted-its-gas-limit-when-attempting-to-inst + --gas 200000000000 \ --proof-size 100000000000 # --skip-dry-run --skip-confirm ) -OUTPUT_CONTRACT_ADDR_SUB=$( +OUTPUT_CONTRACT_ADDR_MAIN=$( cargo contract instantiate "${args[@]}" | tail -1 ) # example: ' Contract 5...' -echo $OUTPUT_CONTRACT_ADDR_SUB +echo $OUTPUT_CONTRACT_ADDR_MAIN # remove text 'Contract' -OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') +OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') # trim whitespace using `echo ...` -CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) -echo $CONTRACT_ADDR_SUB +CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) +echo $CONTRACT_ADDR_MAIN echo "Calling contract method flip..." args=( @@ -139,7 +143,7 @@ args=( --contract $CONTRACT_ADDR_SUB --message flip --execute - --gas 100000000000 + --gas 200000000000 --proof-size 100000000000 # --skip-dry-run --skip-confirm @@ -163,6 +167,8 @@ args=( --contract $CONTRACT_ADDR_MAIN --message get --execute + # --gas 200000000000 + # --proof-size 100000000000 # --skip-dry-run --skip-confirm ) @@ -174,6 +180,8 @@ args=( --contract $CONTRACT_ADDR_MAIN --message flip_and_get --execute + # --gas 200000000000 + # --proof-size 100000000000 # --skip-dry-run --skip-confirm ) @@ -186,6 +194,8 @@ args=( --contract $CONTRACT_ADDR_MAIN --message get_other_contract_address --execute + # --gas 200000000000 + # --proof-size 100000000000 # --skip-dry-run --skip-confirm ) diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh index 1c95caf..5d8b1d3 100755 --- a/docker/quickstart-unnamed.sh +++ b/docker/quickstart-unnamed.sh @@ -115,8 +115,8 @@ args=( --constructor new --args $CODE_HASH_SUB $ARG_ID_MARKET "100" "228" "500" --execute - --gas 100000000000 - --proof-size 100000000000 + --gas 1000000000000 + --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) @@ -139,8 +139,8 @@ args=( --constructor new --args $ARG_ID_MARKET "100" "228" "500" --execute - --gas 100000000000 - --proof-size 100000000000 + --gas 1000000000000 + --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) @@ -165,8 +165,8 @@ args=( --message set_block_for_entropy_for_market_id --args $ARG_ID_MARKET "228" $ARG_BLOCK_HASH_ENTROPY --execute - --gas 100000000000 - --proof-size 100000000000 + --gas 1000000000000 + --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) From e5f449ad44479cc7a1afd70494eda010eaf96123 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 17 Jun 2023 21:43:51 +1000 Subject: [PATCH 17/58] fix basic-contract-caller --- Cargo.lock | 77 ++++++++--------- README.md | 40 ++++++++- dapps/basic_contract_caller/lib.rs | 84 +++++++++++++------ .../other_contract/lib.rs | 6 ++ docker/quickstart-basic-contract-caller.sh | 26 +----- docker/quickstart-unnamed.sh | 18 ---- docker/quickstart.sh | 16 ---- docker/reset.sh | 1 + docker/restart.sh | 23 +++++ 9 files changed, 168 insertions(+), 123 deletions(-) create mode 100755 docker/restart.sh diff --git a/Cargo.lock b/Cargo.lock index 320c974..2607e24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,6 +253,7 @@ version = "4.2.0" dependencies = [ "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_e2e", + "ink_primitives 4.2.1", "other_contract", "parity-scale-codec", "scale-info", @@ -1498,8 +1499,8 @@ dependencies = [ "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_macro 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.1", + "ink_primitives 4.2.1", "ink_storage 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec", ] @@ -1513,8 +1514,8 @@ dependencies = [ "ink_env 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_macro 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", + "ink_primitives 4.2.0", "ink_storage 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", ] @@ -1549,7 +1550,7 @@ dependencies = [ "heck", "impl-serde 0.4.0", "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.1", "itertools", "log", "parity-scale-codec", @@ -1571,7 +1572,7 @@ dependencies = [ "heck", "impl-serde 0.4.0", "ink_ir 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0", "itertools", "parity-scale-codec", "proc-macro2", @@ -1593,7 +1594,7 @@ dependencies = [ "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_e2e_macro", "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.1", "jsonrpsee 0.17.1", "log", "pallet-contracts-primitives", @@ -1635,7 +1636,7 @@ checksum = "77c4af49e092a93e65d1161ce31d23c2e57d724462c96a8944acd647a52787f0" dependencies = [ "blake2", "derive_more", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.1", "parity-scale-codec", "secp256k1 0.27.0", "sha2 0.10.6", @@ -1649,7 +1650,7 @@ source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-tes dependencies = [ "blake2", "derive_more", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0", "parity-scale-codec", "secp256k1 0.27.0", "sha2 0.10.6", @@ -1668,8 +1669,8 @@ dependencies = [ "derive_more", "ink_allocator 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_engine 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.1", + "ink_primitives 4.2.1", "ink_storage_traits 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits", "parity-scale-codec", @@ -1695,8 +1696,8 @@ dependencies = [ "derive_more", "ink_allocator 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_engine 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", + "ink_primitives 4.2.0", "ink_storage_traits 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "num-traits", "parity-scale-codec", @@ -1732,7 +1733,7 @@ source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-tes dependencies = [ "blake2", "either", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", "itertools", "proc-macro2", "quote", @@ -1747,7 +1748,7 @@ checksum = "15abf802e89909c65b6c15d0c655beb3c7ab86309626effb5d9b330d97308114" dependencies = [ "ink_codegen 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.1", "parity-scale-codec", "proc-macro2", "quote", @@ -1762,7 +1763,7 @@ source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-tes dependencies = [ "ink_codegen 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_ir 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_primitives 4.2.0", "parity-scale-codec", "proc-macro2", "quote", @@ -1778,8 +1779,8 @@ checksum = "4af082b4c2eb246d27b358411ef950811f851c1099aa507ba4bcdd7214d40ccd" dependencies = [ "derive_more", "impl-serde 0.4.0", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.1", + "ink_primitives 4.2.1", "scale-info", "serde", ] @@ -1791,8 +1792,8 @@ source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-tes dependencies = [ "derive_more", "impl-serde 0.4.0", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", + "ink_primitives 4.2.0", "scale-info", "schemars", "serde", @@ -1801,16 +1802,16 @@ dependencies = [ [[package]] name = "ink_prelude" version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0662ba1d4aa26f0fea36ce6ef9ef1e510e24c900597d703b148c8c23b675b9" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ "cfg-if", ] [[package]] name = "ink_prelude" -version = "4.2.0" -source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6f174d742ff929abe66716ad8159f324441b4ff5161a3b0e282f416afbbac1" dependencies = [ "cfg-if", ] @@ -1818,11 +1819,10 @@ dependencies = [ [[package]] name = "ink_primitives" version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52693c5e74600f5bd4c0f6d447ba9c4e491e4edf685eaf9f9f347a3cb1cde66b" +source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ "derive_more", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.0", "parity-scale-codec", "scale-decode", "scale-encode", @@ -1832,11 +1832,12 @@ dependencies = [ [[package]] name = "ink_primitives" -version = "4.2.0" -source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b4e4772e1b9384233103c1f488df9854d24b3c16168bcf23613b7d98fb363f" dependencies = [ "derive_more", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.1", "parity-scale-codec", "scale-decode", "scale-encode", @@ -1855,8 +1856,8 @@ dependencies = [ "derive_more", "ink_env 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.1", + "ink_primitives 4.2.1", "ink_storage_traits 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec", "scale-info", @@ -1872,8 +1873,8 @@ dependencies = [ "derive_more", "ink_env 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", + "ink_primitives 4.2.0", "ink_storage_traits 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "parity-scale-codec", "scale-info", @@ -1886,8 +1887,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec58d70937c1e1490a00b84e2eb9a799f1a5331dd0e5cc68d550de1dbf6a8f4" dependencies = [ "ink_metadata 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_prelude 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ink_primitives 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_prelude 4.2.1", + "ink_primitives 4.2.1", "parity-scale-codec", "scale-info", ] @@ -1898,8 +1899,8 @@ version = "4.2.0" source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ "ink_metadata 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_prelude 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", - "ink_primitives 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", + "ink_prelude 4.2.0", + "ink_primitives 4.2.0", "parity-scale-codec", "scale-info", ] diff --git a/README.md b/README.md index 79f7153..5a65bc4 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ * [Run Cargo Contracts Node in Docker Container](#run-cargo-contracts-node) * Build & Upload * [**Quickstart** Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#quick-build-upload) + * [**Quickstart** Build & Upload ink! Rust "Basic Contract Caller" Smart Contract to Local Testnet (using Cargo Contract)](#quick-basic-contract-caller) + * [**Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract)](#quick-unnamed) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#build-upload) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Swanky CLI)](#build-upload-swanky) * Interact @@ -114,6 +116,7 @@ substrate-contracts-node --version ```bash SCN_PORT=$(docker exec -it ink lsof -ti:30333) && \ docker exec -it ink echo $(kill -9 $SCN_PORT) && \ +docker exec -it ink /app/docker/reset.sh && \ docker exec -it ink /app/docker/quickstart.sh ``` @@ -125,6 +128,7 @@ docker exec -it ink /app/docker/quickstart.sh ``` * Run quickstart ```bash + ./docker/reset.sh ./docker/quickstart.sh ``` @@ -135,6 +139,34 @@ docker exec -it ink /app/docker/quickstart.sh * Redeploys the Flipper contract * Interacts with the Flipper contract +### **Demo Quickstart** Build & Upload ink! Rust "Basic Contract Caller" Smart Contract to Local Testnet (using Cargo Contract) + +#### Run from shell inside Docker container + + * Enter shell of Docker container + ```bash + docker exec -it ink /bin/bash + ``` + * Run quickstart + ```bash + ./docker/reset.sh + ./docker/quickstart-basic-contract-caller.sh + ``` + +### **Demo Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract) + +#### Run from shell inside Docker container + + * Enter shell of Docker container + ```bash + docker exec -it ink /bin/bash + ``` + * Run quickstart + ```bash + ./docker/reset.sh + ./docker/quickstart-unnamed.sh + ``` + ### Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract) * Create Rust project with template @@ -249,12 +281,12 @@ Note: Try `rustup update` if you face error Local Testnet ```bash -swanky contract deploy flipper --account alice -g 100000000000 -a true +swanky contract deploy flipper --account alice -g 1000000000000 -a true ``` Shibuya Testnet ```bash -swanky contract deploy flipper --account alice --gas 100000000000 --args true --network shibuya +swanky contract deploy flipper --account alice --gas 1000000000000 --args true --network shibuya ``` Copy paste the contract address. @@ -359,8 +391,8 @@ cargo contract call \ * Note: If you don't build in "debug" mode with `cargo contract build ...` instead of `cargo contract build --release ...` and you run it using **dry run** by running extra options like the following, or if you execute as a transaction, then you won't be able to see node terminal debug logs like `tokio-runtime-worker runtime::contracts Execution finished with debug buffer...` from your use of `ink::env::debug_println!` in the smart contract ```bash --skip-dry-run \ - --gas 100000000000 \ - --proof-size 100000000000 + --gas 1000000000000 \ + --proof-size 1000000000000 ``` ### Tips Docker Commands diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index c8fc8ce..5ce2c06 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -11,6 +11,7 @@ mod basic_contract_caller { }, DefaultEnvironment, }; + /// We import the generated `ContractRef` of our other contract. /// /// Note that the other contract must have re-exported it (`pub use @@ -30,6 +31,7 @@ mod basic_contract_caller { pub enum Error { /// Returned if not other contract address exists. NoOtherContractAddress, + ResponseError, } /// Type alias for the contract's result type. @@ -67,17 +69,27 @@ mod basic_contract_caller { pub fn get(&mut self) -> Result { match &self.other_contract_address { Some(c) => { - ink::env::debug_println!("c {:?}", c.clone()); - let my_return_value = build_call::() + let res = build_call::() .call(c.clone()) .gas_limit(100000000000) - .transferred_value(10) + // .transferred_value(10) // TransferFailed .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("get"))) ) .returns::() - .invoke(); - Ok(my_return_value) + // https://use.ink/basics/cross-contract-calling#builder-error-handling + .try_invoke() + .expect("Error calling get."); + match res { + Ok(is_flipped) => { + ink::env::debug_println!("is_flipped {:?}", is_flipped); + return Ok(is_flipped); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, + }; }, None => return Err(Error::NoOtherContractAddress), } @@ -89,15 +101,16 @@ mod basic_contract_caller { Some(c) => { // using CallBuilder // https://use.ink/basics/cross-contract-calling#callbuilder - build_call::() + let _ = build_call::() .call(c.clone()) .gas_limit(100000000000) - .transferred_value(10) + .transferred_value(0) // TransferFailed if non-zero .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) ) .returns::<()>() - .invoke(); + .try_invoke() + .expect("Error calling flip."); Ok(()) }, None => return Err(Error::NoOtherContractAddress), @@ -108,25 +121,35 @@ mod basic_contract_caller { pub fn flip_and_get(&mut self) -> Result { match &self.other_contract_address { Some(c) => { - build_call::() + let _ = build_call::() .call(c.clone()) .gas_limit(100000000000) - .transferred_value(10) + .transferred_value(0) // TransferFailed if non-zero .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) ) .returns::<()>() - .invoke(); - let my_return_value = build_call::() + .try_invoke() + .expect("Error calling flip."); + let res = build_call::() .call(c.clone()) .gas_limit(100000000000) - .transferred_value(10) .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("get"))) ) .returns::() - .invoke(); - Ok(my_return_value) + .try_invoke() + .expect("Error calling get."); + match res { + Ok(is_flipped) => { + ink::env::debug_println!("is_flipped {:?}", is_flipped); + return Ok(is_flipped); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, + }; }, None => return Err(Error::NoOtherContractAddress), } @@ -136,16 +159,27 @@ mod basic_contract_caller { pub fn get_other_contract_address(&self) -> Result { match &self.other_contract_address { Some(c) => { - let my_return_value = build_call::() - .call(c.clone()) - .gas_limit(100000000000) - .transferred_value(10) - .exec_input( - ExecutionInput::new(Selector::new(ink::selector_bytes!("get_other_contract_address"))) - ) - .returns::() - .invoke(); - Ok(my_return_value) + let res = + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + // .transferred_value(10) // TransferFailed + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_other_contract_address"))) + ) + .returns::() + .try_invoke() + .expect("Error calling get_other_contract_address."); + match res { + Ok(contract_address) => { + ink::env::debug_println!("contract_address {:?}", contract_address); + return Ok(contract_address); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, + }; }, None => return Err(Error::NoOtherContractAddress), } diff --git a/dapps/basic_contract_caller/other_contract/lib.rs b/dapps/basic_contract_caller/other_contract/lib.rs index d1e9ca5..2b1613f 100755 --- a/dapps/basic_contract_caller/other_contract/lib.rs +++ b/dapps/basic_contract_caller/other_contract/lib.rs @@ -21,7 +21,13 @@ mod other_contract { } #[ink(message)] + #[ink(payable)] pub fn flip(&mut self) { + ink::env::debug_println!( + "received payment with flip: {}", + self.env().transferred_value() + ); + self.value = !self.value; } diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index 3c3eb9a..f42add6 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -7,24 +7,6 @@ trap "echo; exit" HUP # in both cases the PARENT_DIR will refer to the project root where the .env file is. PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) -echo "Killing previous Substrate contracts node..." -# kill the existing substrate-contracts-node that is running on port 30333 -kill -9 $(lsof -ti:30333) &>/dev/null & - -echo "Removing previous database..." -# delete the blockchain database so we don't get this error when we redeploy the -# smart contract `ERROR: This contract has already been uploaded with code hash:` -rm -rf /tmp/ink - -echo "Running new Substrate contracts node..." -cd ${PARENT_DIR}/docker/ -# https://www.maketecheasier.com/run-bash-commands-background-linux/ -nohup ./run-scn.sh &>/dev/null & -# wait for the blockchain node to start before we interact with it -# note: if you try to interact with it before it is ready then you will get error -# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: -# Error when opening the TCP socket: Cannot assign requested address (os error 99)` -sleep 25 echo "Building contracts..." cd $PARENT_DIR/dapps/basic_contract_caller PROJECT_ROOT=$PARENT_DIR/dapps/basic_contract_caller @@ -145,7 +127,7 @@ args=( --execute --gas 200000000000 --proof-size 100000000000 - # --skip-dry-run + --skip-dry-run --skip-confirm ) cargo contract call "${args[@]}" | grep --color=always -z 'data' @@ -180,9 +162,9 @@ args=( --contract $CONTRACT_ADDR_MAIN --message flip_and_get --execute - # --gas 200000000000 - # --proof-size 100000000000 - # --skip-dry-run + --gas 200000000000 + --proof-size 100000000000 + --skip-dry-run --skip-confirm ) cargo contract call "${args[@]}" | grep --color=always -z 'data' diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh index 5d8b1d3..70db354 100755 --- a/docker/quickstart-unnamed.sh +++ b/docker/quickstart-unnamed.sh @@ -15,24 +15,6 @@ trap "echo; exit" HUP # in both cases the PARENT_DIR will refer to the project root where the .env file is. PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) -echo "Killing previous Substrate contracts node..." -# kill the existing substrate-contracts-node that is running on port 30333 -kill -9 $(lsof -ti:30333) &>/dev/null & - -echo "Removing previous database..." -# delete the blockchain database so we don't get this error when we redeploy the -# smart contract `ERROR: This contract has already been uploaded with code hash:` -rm -rf /tmp/ink - -echo "Running new Substrate contracts node..." -cd ${PARENT_DIR}/docker/ -# https://www.maketecheasier.com/run-bash-commands-background-linux/ -nohup ./run-scn.sh &>/dev/null & -# wait for the blockchain node to start before we interact with it -# note: if you try to interact with it before it is ready then you will get error -# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: -# Error when opening the TCP socket: Cannot assign requested address (os error 99)` -sleep 25 echo "Building contracts..." cd $PARENT_DIR/dapps/xcm/unnamed PROJECT_ROOT=$PARENT_DIR/dapps/xcm/unnamed diff --git a/docker/quickstart.sh b/docker/quickstart.sh index 110da70..ee1dfb5 100755 --- a/docker/quickstart.sh +++ b/docker/quickstart.sh @@ -7,22 +7,6 @@ trap "echo; exit" HUP # in both cases the PARENT_DIR will refer to the project root where the .env file is. PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) -# kill the existing substrate-contracts-node that is running on port 30333 -kill -9 $(lsof -ti:30333) - -# delete the blockchain database so we don't get this error when we redeploy the -# smart contract `ERROR: This contract has already been uploaded with code hash:` -rm -rf /tmp/ink - -cd ${PARENT_DIR}/docker/ -# https://www.maketecheasier.com/run-bash-commands-background-linux/ -nohup ./run-scn.sh &>/dev/null & -# wait for the blockchain node to start before we interact with it -# note: if you try to interact with it before it is ready then you will get error -# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: -# Error when opening the TCP socket: Cannot assign requested address (os error 99)` -sleep 15 - cd $PARENT_DIR/dapps/ink-rust/wasm-flipper/contract cargo contract new flipper cd flipper diff --git a/docker/reset.sh b/docker/reset.sh index c0232df..dc50ed8 100755 --- a/docker/reset.sh +++ b/docker/reset.sh @@ -19,6 +19,7 @@ rm -rf /tmp/ink cd ${PARENT_DIR}/docker/ # https://www.maketecheasier.com/run-bash-commands-background-linux/ nohup ./run-scn.sh &>/dev/null & +cd $PARENT_DIR # wait for the blockchain node to start before we interact with it # note: if you try to interact with it before it is ready then you will get error # `ERROR: Rpc error: RPC error: Networking or low-level protocol error: diff --git a/docker/restart.sh b/docker/restart.sh new file mode 100755 index 0000000..cb5dfa0 --- /dev/null +++ b/docker/restart.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# only restart the substrate-contracts-node + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +# kill the existing substrate-contracts-node that is running on port 30333 +kill -9 $(lsof -ti:30333) + +cd ${PARENT_DIR}/docker/ +# https://www.maketecheasier.com/run-bash-commands-background-linux/ +nohup ./run-scn.sh &>/dev/null & +cd $PARENT_DIR +# wait for the blockchain node to start before we interact with it +# note: if you try to interact with it before it is ready then you will get error +# `ERROR: Rpc error: RPC error: Networking or low-level protocol error: +# Error when opening the TCP socket: Cannot assign requested address (os error 99)` +sleep 15 From 5686da39b1a109258c7bf7c68917a84e83ff2e19 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 18 Jun 2023 18:16:55 +1000 Subject: [PATCH 18/58] call via main but no Builder not support tuple return Decode(Error) --- Cargo.lock | 1 - dapps/xcm/unnamed/lib.rs | 146 +++++++++++++++++++---- dapps/xcm/unnamed/oracle_contract/lib.rs | 26 +++- docker/quickstart-unnamed.sh | 67 ++++++----- docker/reset.sh | 7 +- docker/restart.sh | 7 +- 6 files changed, 190 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2607e24..9b15c93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,7 +253,6 @@ version = "4.2.0" dependencies = [ "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_e2e", - "ink_primitives 4.2.1", "other_contract", "parity-scale-codec", "scale-info", diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 72ea05f..550ac51 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -2,6 +2,16 @@ #[ink::contract] mod unnamed { + use ink::env::{ + call::{ + build_create, + build_call, + ExecutionInput, + Selector, + }, + DefaultEnvironment, + }; + use oracle_contract::OracleContractRef; use ink::prelude::string::String; @@ -10,6 +20,13 @@ mod unnamed { // refactor into types file pub type OracleOwner = AccountId; + #[derive(Clone, Debug, scale::Encode, scale::Decode)] + #[cfg_attr( + feature = "std", + derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout) + )] + pub struct EntropyData(BlockNumber, String, i16, i16); + /// Defines the storage of your contract. /// Add new fields to the below struct in order /// to add new static storage fields to your contract. @@ -18,6 +35,7 @@ mod unnamed { pub struct Unnamed { /// Store a reference to the `OracleContract`. oracle_contract: Option, + oracle_contract_address: Option, owner: Option, } @@ -27,6 +45,7 @@ mod unnamed { pub enum Error { /// Returned if not oracle contract address exists. NoOracleContractAddress, + ResponseError, } /// Type alias for the contract's result type. @@ -37,6 +56,7 @@ mod unnamed { #[ink(constructor)] pub fn new( oracle_contract_code_hash: Hash, + oracle_contract_address: AccountId, id_market: String, block_number_guessed: BlockNumber, block_number_entropy: BlockNumber, @@ -44,19 +64,24 @@ mod unnamed { ) -> Self { let instance = Self::default(); let caller = instance.env().caller(); - let oracle_contract = OracleContractRef::new( - id_market, - block_number_guessed, - block_number_entropy, - block_number_end, - ) + let oracle_contract = build_create::() .code_hash(oracle_contract_code_hash) + .gas_limit(100000000000) .endowment(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("new"))) + .push_arg(id_market) + .push_arg(block_number_guessed) + .push_arg(block_number_entropy) + .push_arg(block_number_end) + ) .salt_bytes([0xDE, 0xAD, 0xBE, 0xEF]) + .returns::() .instantiate(); Self { oracle_contract: Some(oracle_contract), + oracle_contract_address: Some(oracle_contract_address), owner: Some(caller), } } @@ -69,14 +94,23 @@ mod unnamed { block_number_entropy: BlockNumber, // always require this even though it may not have changed block_hash_entropy: String, // Hash ) -> Result<()> { - ink::env::debug_println!("&self.oracle_contract {:?}", &self.oracle_contract); - match &self.oracle_contract { + ink::env::debug_println!("&self.oracle_contract_address {:?}", &self.oracle_contract_address); + match &self.oracle_contract_address { Some(c) => { - let res = c.clone().set_block_for_entropy_for_market_id( - id_market, - block_number_entropy, - block_hash_entropy.clone(), - ); + // using CallBuilder + // https://use.ink/basics/cross-contract-calling#callbuilder + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("set_block_for_entropy_for_market_id"))) + .push_arg(id_market) + .push_arg(block_number_entropy) + .push_arg(block_hash_entropy.clone()) + ) + .returns::<()>() + .invoke(); Ok(()) }, None => return Err(Error::NoOracleContractAddress), @@ -85,14 +119,65 @@ mod unnamed { /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] - pub fn get_entropy_for_market_id(&self, id_market: String) -> Result<(BlockNumber, String, i16, i16)> { - match &self.oracle_contract { + pub fn set_entropy_for_market_id( + &mut self, + id_market: String, + block_number_entropy: BlockNumber, // always require this even though it may not have changed + block_hash_entropy: String, // Hash + c1_entropy: i16, + c2_entropy: i16, + ) -> Result<()> { + ink::env::debug_println!("&self.oracle_contract_address {:?}", &self.oracle_contract_address); + match &self.oracle_contract_address { Some(c) => { - let res = match c.clone().get_entropy_for_market_id(id_market) { - Ok(r) => r, - Err(_e) => panic!("arr {:?}", _e), + // using CallBuilder + // https://use.ink/basics/cross-contract-calling#callbuilder + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .transferred_value(0) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("set_entropy_for_market_id"))) + .push_arg(id_market) + .push_arg(block_number_entropy) + .push_arg(block_hash_entropy.clone()) + .push_arg(c1_entropy) + .push_arg(c2_entropy) + ) + .returns::<()>() + .invoke(); + Ok(()) + }, + None => return Err(Error::NoOracleContractAddress), + } + } + + /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` + #[ink(message)] + pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { + match &self.oracle_contract_address { + Some(c) => { + let res = + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_entropy_for_market_id"))) + .push_arg(id_market) + ) + .returns::() + .try_invoke() + .expect("Error calling get_entropy_for_market_id."); + match res { + Ok(tuple) => { + ink::env::debug_println!("tuple {:?}", tuple); + return Ok(tuple); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, }; - Ok(res) }, None => return Err(Error::NoOracleContractAddress), } @@ -101,9 +186,28 @@ mod unnamed { /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] pub fn get_oracle_contract_address(&self) -> Result { - match &self.oracle_contract { + match &self.oracle_contract_address { Some(c) => { - Ok(c.clone().get_oracle_contract_address()) + let res = + build_call::() + .call(c.clone()) + .gas_limit(100000000000) + .exec_input( + ExecutionInput::new(Selector::new(ink::selector_bytes!("get_oracle_contract_address"))) + ) + .returns::() + .try_invoke() + .expect("Error calling get_oracle_contract_address."); + match res { + Ok(contract_address) => { + ink::env::debug_println!("contract_address {:?}", contract_address); + return Ok(contract_address); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, + }; }, None => return Err(Error::NoOracleContractAddress), } diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index 9f1714c..d7d2776 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -23,6 +23,13 @@ mod oracle_contract { pub type MarketGuessId = Vec; pub type OracleOwner = AccountId; + #[derive(Clone, Debug, scale::Encode, scale::Decode)] + #[cfg_attr( + feature = "std", + derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout) + )] + pub struct EntropyData(BlockNumber, String, i16, i16); + /// Emitted when create new market guess for market id. #[ink(event)] pub struct NewOracleMarketGuessForMarketId { @@ -216,17 +223,23 @@ mod oracle_contract { // waiting sufficient blocks after previous so guarantee of waiting until \ // validators change after a certain amount of epochs" // ); + ink::env::debug_println!("111"); let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); + ink::env::debug_println!("222"); assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); - + ink::env::debug_println!("333 {:?}, {:?}", market_guess.oracle_owner, caller); + // FIXME - if called from the main contract then the caller won't be the oracle_owner, + // instead it'll be the main contract's address if market_guess.oracle_owner != Some(caller) { - return Err(Error::CallerIsNotOracleOwner) + return Err(Error::CallerIsNotOracleOwner); } + ink::env::debug_println!("444"); let new_market_guess = MarketGuess { block_number_entropy, block_hash_entropy: Some(block_hash_entropy_no_prefix.clone()), ..market_guess }; + ink::env::debug_println!("new_market_guess: {:?}\n", new_market_guess); self.market_data.insert(id_market.clone().into_bytes(), &new_market_guess); self.env().emit_event(SetBlockHashEntropyForMarketId { id_market: id_market.clone().into_bytes(), @@ -246,13 +259,14 @@ mod oracle_contract { c1_entropy: i16, c2_entropy: i16, ) -> Result<()> { + ink::env::debug_println!("set_entropy_for_market_id"); let caller: AccountId = self.env().caller(); let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; if market_guess.oracle_owner != Some(caller) { - return Err(Error::CallerIsNotOracleOwner) + return Err(Error::CallerIsNotOracleOwner); } let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); @@ -271,6 +285,7 @@ mod oracle_contract { c2_entropy: Some(c2_entropy), ..market_guess }; + ink::env::debug_println!("new_market_guess: {:?}\n", new_market_guess); self.market_data.insert(id_market.clone().into_bytes(), &new_market_guess); self.env().emit_event(SetEntropyForMarketId { id_market: id_market.into_bytes(), @@ -290,7 +305,7 @@ mod oracle_contract { } #[ink(message)] - pub fn get_entropy_for_market_id(&self, id_market: String) -> Result<(BlockNumber, String, i16, i16)> { + pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { let caller: AccountId = self.env().caller(); let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, @@ -349,7 +364,8 @@ mod oracle_contract { c2_entropy: c2_rem, }); - Ok((block_number_entropy, block_hash_entropy.clone(), c1_rem, c2_rem)) + let entropy_data = EntropyData(block_number_entropy, block_hash_entropy.clone(), c1_rem, c2_rem); + Ok(entropy_data) } // get symbols 61-64 for coin1 and 57-60 for coin2 fro the block hash diff --git a/docker/quickstart-unnamed.sh b/docker/quickstart-unnamed.sh index 70db354..15f89c3 100755 --- a/docker/quickstart-unnamed.sh +++ b/docker/quickstart-unnamed.sh @@ -88,55 +88,55 @@ ARG_ID_MARKET="\"my_id\"" cd $PROJECT_ROOT -# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract -echo "Instantiating main-contract..." - +echo "Instantiating sub-contract..." args=( - --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/oracle_contract/Cargo.toml --suri //Alice --constructor new - --args $CODE_HASH_SUB $ARG_ID_MARKET "100" "228" "500" + --args $ARG_ID_MARKET "100" "228" "500" --execute --gas 1000000000000 --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) -OUTPUT_CONTRACT_ADDR_MAIN=$( +OUTPUT_CONTRACT_ADDR_SUB=$( cargo contract instantiate "${args[@]}" | tail -1 ) # example: ' Contract 5...' -echo $OUTPUT_CONTRACT_ADDR_MAIN +echo $OUTPUT_CONTRACT_ADDR_SUB # remove text 'Contract' -OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') +OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') # trim whitespace using `echo ...` -CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) -echo $CONTRACT_ADDR_MAIN +CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) +echo $CONTRACT_ADDR_SUB + +# instantiate "main" contract, providing the code hash generated from uploading the "sub" contract +echo "Instantiating main-contract..." -echo "Instantiating sub-contract..." args=( - --manifest-path $PARENT_DIR/dapps/xcm/unnamed/oracle_contract/Cargo.toml + --manifest-path $PARENT_DIR/dapps/xcm/unnamed/Cargo.toml --suri //Alice --constructor new - --args $ARG_ID_MARKET "100" "228" "500" + --args $CODE_HASH_SUB $CONTRACT_ADDR_SUB $ARG_ID_MARKET "100" "228" "500" --execute --gas 1000000000000 --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) -OUTPUT_CONTRACT_ADDR_SUB=$( +OUTPUT_CONTRACT_ADDR_MAIN=$( cargo contract instantiate "${args[@]}" | tail -1 ) # example: ' Contract 5...' -echo $OUTPUT_CONTRACT_ADDR_SUB +echo $OUTPUT_CONTRACT_ADDR_MAIN # remove text 'Contract' -OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_SUB" | sed 's/Contract//;s/$//') +OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR_MAIN" | sed 's/Contract//;s/$//') # trim whitespace using `echo ...` -CONTRACT_ADDR_SUB=$(echo $OUTPUT_CONTRACT_ADDR_SUB_REMOVED_LABEL) -echo $CONTRACT_ADDR_SUB +CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_MAIN_REMOVED_LABEL) +echo $CONTRACT_ADDR_MAIN ARG_BLOCK_HASH_ENTROPY="\"aef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea\"" @@ -154,6 +154,22 @@ args=( ) cargo contract call "${args[@]}" | grep --color=always -z 'data' +# # TODO - change this to try and make it work via `$CONTRACT_ADDR_MAIN` +# echo "Calling contract method set_entropy_for_market_id ..." +# args=( +# --suri //Alice +# --contract $CONTRACT_ADDR_MAIN +# --message set_entropy_for_market_id +# --args $ARG_ID_MARKET "228" $ARG_BLOCK_HASH_ENTROPY "0" "0" +# --execute +# --gas 1000000000000 +# --proof-size 1000000000000 +# # --skip-dry-run +# --skip-confirm +# ) +# cargo contract call "${args[@]}" | grep --color=always -z 'data' + +# TODO - change this to try and make it work via `$CONTRACT_ADDR_MAIN` echo "Calling contract method get_entropy_for_market_id ..." args=( --suri //Alice @@ -161,24 +177,13 @@ args=( --message get_entropy_for_market_id --args $ARG_ID_MARKET --execute + --gas 1000000000000 + --proof-size 1000000000000 # --skip-dry-run --skip-confirm ) cargo contract call "${args[@]}" | grep --color=always -z 'data' -# TODO - consider removing. maybe use to override results incase of missed blocks? -# -# args=( -# --suri //Alice -# --contract $CONTRACT_ADDR_MAIN -# --message set_entropy_for_market_id -# --args $ARG_ID_MARKET "228" $ARG_BLOCK_HASH_ENTROPY "0" "0" -# --execute -# # --skip-dry-run -# --skip-confirm -# ) -# cargo contract call "${args[@]}" | grep --color=always -z 'data' - # highlight the `data` line in output containing the value of the emitted `Retrieve` event echo "Calling contract method get_oracle_contract_address ..." args=( diff --git a/docker/reset.sh b/docker/reset.sh index dc50ed8..b6e24aa 100755 --- a/docker/reset.sh +++ b/docker/reset.sh @@ -2,8 +2,8 @@ # restart the substrate-contracts-node and remove the chain database -trap "echo; exit" INT -trap "echo; exit" HUP +# trap "echo; exit" INT +# trap "echo; exit" HUP # if they call this script from project root or from within docker/ folder then # in both cases the PARENT_DIR will refer to the project root where the .env file is. @@ -18,7 +18,8 @@ rm -rf /tmp/ink cd ${PARENT_DIR}/docker/ # https://www.maketecheasier.com/run-bash-commands-background-linux/ -nohup ./run-scn.sh &>/dev/null & +# nohup ./run-scn.sh &>/dev/null & +./run-scn.sh cd $PARENT_DIR # wait for the blockchain node to start before we interact with it # note: if you try to interact with it before it is ready then you will get error diff --git a/docker/restart.sh b/docker/restart.sh index cb5dfa0..84cf60c 100755 --- a/docker/restart.sh +++ b/docker/restart.sh @@ -2,8 +2,8 @@ # only restart the substrate-contracts-node -trap "echo; exit" INT -trap "echo; exit" HUP +# trap "echo; exit" INT +# trap "echo; exit" HUP # if they call this script from project root or from within docker/ folder then # in both cases the PARENT_DIR will refer to the project root where the .env file is. @@ -14,7 +14,8 @@ kill -9 $(lsof -ti:30333) cd ${PARENT_DIR}/docker/ # https://www.maketecheasier.com/run-bash-commands-background-linux/ -nohup ./run-scn.sh &>/dev/null & +# nohup ./run-scn.sh &>/dev/null & +./run-scn.sh cd $PARENT_DIR # wait for the blockchain node to start before we interact with it # note: if you try to interact with it before it is ready then you will get error From bf4e6f28c93ccfac85e23a5c8ceb3e835f9ff2a2 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 18 Jun 2023 22:02:18 +1000 Subject: [PATCH 19/58] fix Decode(Error) caused by assertion failing since call from contract not Alice account --- dapps/basic_contract_caller/lib.rs | 19 ++++++++---- .../other_contract/lib.rs | 13 +++++++- dapps/xcm/unnamed/lib.rs | 1 + dapps/xcm/unnamed/oracle_contract/lib.rs | 30 ++++++++++++------- docker/quickstart-basic-contract-caller.sh | 4 +-- 5 files changed, 48 insertions(+), 19 deletions(-) diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index 5ce2c06..e7c791c 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -96,22 +96,31 @@ mod basic_contract_caller { } #[ink(message)] - pub fn flip(&mut self) -> Result<()> { + pub fn flip(&mut self) -> Result { match &self.other_contract_address { Some(c) => { // using CallBuilder // https://use.ink/basics/cross-contract-calling#callbuilder - let _ = build_call::() + let res = build_call::() .call(c.clone()) .gas_limit(100000000000) .transferred_value(0) // TransferFailed if non-zero .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) ) - .returns::<()>() + .returns::() .try_invoke() .expect("Error calling flip."); - Ok(()) + match res { + Ok(new_value) => { + ink::env::debug_println!("new_value {:?}", new_value); + return Ok(new_value); + }, + Err(e) => { + ink::env::debug_println!("error {:?}", e); + return Err(Error::ResponseError); + }, + }; }, None => return Err(Error::NoOtherContractAddress), } @@ -128,7 +137,7 @@ mod basic_contract_caller { .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("flip"))) ) - .returns::<()>() + .returns::() .try_invoke() .expect("Error calling flip."); let res = build_call::() diff --git a/dapps/basic_contract_caller/other_contract/lib.rs b/dapps/basic_contract_caller/other_contract/lib.rs index 2b1613f..1b2ae52 100755 --- a/dapps/basic_contract_caller/other_contract/lib.rs +++ b/dapps/basic_contract_caller/other_contract/lib.rs @@ -9,6 +9,16 @@ pub use self::other_contract::OtherContractRef; #[ink::contract] mod other_contract { + /// Errors that can occur upon calling this contract. + #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] + #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] + pub enum Error { + UnknownError, + } + + /// Type alias for the contract's result type. + pub type Result = core::result::Result; + #[ink(storage)] pub struct OtherContract { value: bool, @@ -22,13 +32,14 @@ mod other_contract { #[ink(message)] #[ink(payable)] - pub fn flip(&mut self) { + pub fn flip(&mut self) -> Result { ink::env::debug_println!( "received payment with flip: {}", self.env().transferred_value() ); self.value = !self.value; + return Ok(self.value) } #[ink(message)] diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 550ac51..2ff0f0d 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -161,6 +161,7 @@ mod unnamed { build_call::() .call(c.clone()) .gas_limit(100000000000) + .transferred_value(0) .exec_input( ExecutionInput::new(Selector::new(ink::selector_bytes!("get_entropy_for_market_id"))) .push_arg(id_market) diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index d7d2776..d9b8b1a 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -226,13 +226,14 @@ mod oracle_contract { ink::env::debug_println!("111"); let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); ink::env::debug_println!("222"); + ink::env::debug_println!("block_hash_entropy_no_prefix {:?}", block_hash_entropy_no_prefix); assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); ink::env::debug_println!("333 {:?}, {:?}", market_guess.oracle_owner, caller); - // FIXME - if called from the main contract then the caller won't be the oracle_owner, + // FIXME - can't do this or get errors. if called from the main contract then the caller won't be the oracle_owner, // instead it'll be the main contract's address - if market_guess.oracle_owner != Some(caller) { - return Err(Error::CallerIsNotOracleOwner); - } + // if market_guess.oracle_owner != Some(caller) { + // return Err(Error::CallerIsNotOracleOwner); + // } ink::env::debug_println!("444"); let new_market_guess = MarketGuess { block_number_entropy, @@ -265,9 +266,10 @@ mod oracle_contract { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; - if market_guess.oracle_owner != Some(caller) { - return Err(Error::CallerIsNotOracleOwner); - } + // FIXME - can't do this or get errors. + // if market_guess.oracle_owner != Some(caller) { + // return Err(Error::CallerIsNotOracleOwner); + // } let block_hash_entropy_no_prefix = block_hash_entropy.replace("0x", ""); assert!(block_hash_entropy_no_prefix.len() == 64, "block hash should be a 256 bit block hash"); @@ -305,20 +307,26 @@ mod oracle_contract { } #[ink(message)] - pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { + #[ink(payable)] + pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { let caller: AccountId = self.env().caller(); let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, None => return Err(Error::NoDataForMarketGuessId), }; - if market_guess.oracle_owner != Some(caller) { - return Err(Error::CallerIsNotOracleOwner) - } + ink::env::debug_println!("market_guess.oracle_owner {:?}", market_guess.oracle_owner); + ink::env::debug_println!("caller {:?}", caller); + // FIXME - causes `Decode(Error)` since caller account id is smart contract, + // which differs from the account id of Alice + // if market_guess.oracle_owner != Some(caller) { + // return Err(Error::CallerIsNotOracleOwner) + // } // note: oracle_owner may need to run this function more than once incase entropy block number missed or chain reorg // assert!( // market_guess.block_hash_entropy != None, // "block hash entropy must be set prior to obtaining entropy" // ); + ink::env::debug_println!("market_guess.block_hash_entropy {:?}", market_guess.block_hash_entropy); let block_number_entropy = market_guess.block_number_entropy; // "0xaef6eca62ae61934a7ab5ad3814f6e319abd3e4e4aa1a3386466ad197d1c4dea" // note: Hash is [u8; 32] 32 bytes (&[u8]) without 0x prefix and 64 symbols, 32 bytes, 256 bits diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index f42add6..a826f2e 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -122,12 +122,12 @@ echo $CONTRACT_ADDR_MAIN echo "Calling contract method flip..." args=( --suri //Alice - --contract $CONTRACT_ADDR_SUB + --contract $CONTRACT_ADDR_MAIN --message flip --execute --gas 200000000000 --proof-size 100000000000 - --skip-dry-run + # --skip-dry-run --skip-confirm ) cargo contract call "${args[@]}" | grep --color=always -z 'data' From 3433a89ff76fb8d0c884aa41bc17a2c5a1faad39 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 19 Jun 2023 13:01:51 +1000 Subject: [PATCH 20/58] demo handling errors --- dapps/xcm/unnamed/lib.rs | 107 +++++++++++++++++------ dapps/xcm/unnamed/oracle_contract/lib.rs | 18 ++-- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index 2ff0f0d..eacc008 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -2,17 +2,22 @@ #[ink::contract] mod unnamed { - use ink::env::{ - call::{ - build_create, - build_call, - ExecutionInput, - Selector, + use ink::{ + env::{ + call::{ + build_create, + build_call, + ExecutionInput, + Selector, + }, + DefaultEnvironment, + Result as EnvResult, }, - DefaultEnvironment, + MessageResult, }; use oracle_contract::OracleContractRef; + use oracle_contract::Error; use ink::prelude::string::String; use ink::prelude::vec::Vec; @@ -39,17 +44,8 @@ mod unnamed { owner: Option, } - /// Errors that can occur upon calling this contract. - #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] - #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))] - pub enum Error { - /// Returned if not oracle contract address exists. - NoOracleContractAddress, - ResponseError, - } - /// Type alias for the contract's result type. - pub type Result = core::result::Result; + pub type ContractResult = core::result::Result; impl Unnamed { /// Constructor that instantiates the OracleContract using its uploaded `code_hash` @@ -93,7 +89,7 @@ mod unnamed { id_market: String, block_number_entropy: BlockNumber, // always require this even though it may not have changed block_hash_entropy: String, // Hash - ) -> Result<()> { + ) -> ContractResult<()> { ink::env::debug_println!("&self.oracle_contract_address {:?}", &self.oracle_contract_address); match &self.oracle_contract_address { Some(c) => { @@ -126,7 +122,7 @@ mod unnamed { block_hash_entropy: String, // Hash c1_entropy: i16, c2_entropy: i16, - ) -> Result<()> { + ) -> ContractResult<()> { ink::env::debug_println!("&self.oracle_contract_address {:?}", &self.oracle_contract_address); match &self.oracle_contract_address { Some(c) => { @@ -154,7 +150,7 @@ mod unnamed { /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] - pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { + pub fn get_entropy_for_market_id(&self, id_market: String) -> ContractResult { match &self.oracle_contract_address { Some(c) => { let res = @@ -166,18 +162,73 @@ mod unnamed { ExecutionInput::new(Selector::new(ink::selector_bytes!("get_entropy_for_market_id"))) .push_arg(id_market) ) - .returns::() - .try_invoke() - .expect("Error calling get_entropy_for_market_id."); + .returns::>() + .try_invoke(); + ink::env::debug_println!("res {:?}", res); + match res { - Ok(tuple) => { - ink::env::debug_println!("tuple {:?}", tuple); + EnvResult::Ok(MessageResult::Err(Error::CouldNotReadInput)) => { + ink::env::debug_println!("ResponseError"); + return Err(Error::ResponseError); + }, + EnvResult::Ok(MessageResult::Err(ink::LangError::CouldNotReadInput)) => { + ink::env::debug_println!("ResponseError"); + return Err(Error::ResponseError); + }, + // + // Reference: https://substrate.stackexchange.com/questions/7634/how-to-properly-handle-cross-contract-call-errors/7843#7843 + // + // Contract Success + // + EnvResult::Ok(MessageResult::Ok(ContractResult::Ok(tuple))) => { + ink::env::debug_println!("contract success tuple {:?}", tuple); return Ok(tuple); }, - Err(e) => { - ink::env::debug_println!("error {:?}", e); + // Contract or Lang Error + // + // About: Lang errors include calling a method that does not exist + // About: Contract errors include handling `Err(())` responses from callee cross-contract method + // + // See https://docs.rs/ink/latest/ink/enum.LangError.html + EnvResult::Ok(MessageResult::Err(e)) => { + ink::env::debug_println!("contract or lang error occurred {:?}", e); + + match e { + ink::LangError::CouldNotReadInput => { + ink::env::debug_println!("CouldNotReadInput lang error occurred"); + return Err(Error::ResponseError); + }, + _ => { + ink::env::debug_println!("unknown lang error occurred"); + return Err(Error::ResponseError); + } + } + }, + // Environment Error + // + // About: These are triggered by failed assertions and panics in callee cross-contract method + // Example error message: + // panicked at '', /app/dapps/xcm/unnamed/oracle_contract/lib.rs:377:13 + // environment error occurred CalleeTrapped + // + // Note: Unable to find anything about `EnvError`s or `ink::env::Error` at + // https://docs.rs/ink/latest/ink/?search=EnvError + // + // Error codes duplicated in two places: + // - https://github.com/paritytech/ink/blob/master/crates/engine/src/ext.rs#L73 + // - https://github.com/paritytech/ink/blob/master/crates/env/src/engine/on_chain/ext.rs#L64 + // + EnvResult::Err(e) => { + ink::env::debug_println!("environment error occurred {:?}", e); + return Err(Error::ResponseError); }, + // Unimplemented Error + _ => { + ink::env::debug_println!("unimplemented error in get_entropy_for_market_id"); + + return unimplemented!(); + }, }; }, None => return Err(Error::NoOracleContractAddress), @@ -186,7 +237,7 @@ mod unnamed { /// Using the `OracleContractRef` we can call all the messages of the `OracleContract` #[ink(message)] - pub fn get_oracle_contract_address(&self) -> Result { + pub fn get_oracle_contract_address(&self) -> ContractResult { match &self.oracle_contract_address { Some(c) => { let res = diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index d9b8b1a..d03b4ac 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -1,11 +1,13 @@ #![cfg_attr(not(feature = "std"), no_std, no_main)] pub use self::oracle_contract::OracleContractRef; +pub use self::oracle_contract::Error; #[ink::contract] mod oracle_contract { use ink::prelude::string::String; use ink::prelude::vec::Vec; + use ink::LangError::CouldNotReadInput; use ink::storage::{ Lazy, Mapping, @@ -128,14 +130,17 @@ mod oracle_contract { pub enum Error { /// Returned if the no data exists for given market guess id. NoDataForMarketGuessId, + NoOracleContractAddress, /// Returned if caller is not oracle owner of market guess id. CallerIsNotOracleOwner, InvalidUTF8Sequence, InvalidDigit, + ResponseError, + CouldNotReadInput, } /// Type alias for the contract's result type. - pub type Result = core::result::Result; + pub type ContractResult = core::result::Result; impl OracleContract { #[ink(constructor)] @@ -197,7 +202,7 @@ mod oracle_contract { id_market: String, block_number_entropy: BlockNumber, // always require this even though it may not have changed block_hash_entropy: String, // Hash - ) -> Result<()> { + ) -> ContractResult<()> { let caller: AccountId = self.env().caller(); ink::env::debug_println!("set_block_for_entropy_for_market_id"); // assert!(self.exists_market_data_for_id(id_market.as_bytes()).is_ok(), "unable to find market data for given id"); @@ -259,7 +264,7 @@ mod oracle_contract { block_hash_entropy: String, // Hash c1_entropy: i16, c2_entropy: i16, - ) -> Result<()> { + ) -> ContractResult<()> { ink::env::debug_println!("set_entropy_for_market_id"); let caller: AccountId = self.env().caller(); let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { @@ -308,7 +313,7 @@ mod oracle_contract { #[ink(message)] #[ink(payable)] - pub fn get_entropy_for_market_id(&self, id_market: String) -> Result { + pub fn get_entropy_for_market_id(&self, id_market: String) -> ContractResult { let caller: AccountId = self.env().caller(); let market_guess = match self.market_data.get(id_market.clone().into_bytes()) { Some(data) => data, @@ -373,6 +378,9 @@ mod oracle_contract { }); let entropy_data = EntropyData(block_number_entropy, block_hash_entropy.clone(), c1_rem, c2_rem); + // Early exit with error for demo purposes + // return Err(Error::ResponseError); // Decode(Error) + return Err(Error::CouldNotReadInput); // Decode(Error) Ok(entropy_data) } @@ -385,7 +393,7 @@ mod oracle_contract { } // helper methods - fn exists_market_data_for_id(&self, id_market: &[u8]) -> Result { + fn exists_market_data_for_id(&self, id_market: &[u8]) -> ContractResult { let id_market_str = match str::from_utf8(id_market) { Ok(v) => v, Err(_e) => return Err(Error::InvalidUTF8Sequence), From 75f5370f10db1db53e044614a066aad5d28d2032 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 19 Jun 2023 13:35:51 +1000 Subject: [PATCH 21/58] fix LangError --- dapps/xcm/unnamed/lib.rs | 38 ++++++++++-------------- dapps/xcm/unnamed/oracle_contract/lib.rs | 3 -- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/dapps/xcm/unnamed/lib.rs b/dapps/xcm/unnamed/lib.rs index eacc008..4cd207c 100755 --- a/dapps/xcm/unnamed/lib.rs +++ b/dapps/xcm/unnamed/lib.rs @@ -167,16 +167,9 @@ mod unnamed { ink::env::debug_println!("res {:?}", res); match res { - EnvResult::Ok(MessageResult::Err(Error::CouldNotReadInput)) => { - ink::env::debug_println!("ResponseError"); - return Err(Error::ResponseError); - }, - EnvResult::Ok(MessageResult::Err(ink::LangError::CouldNotReadInput)) => { - ink::env::debug_println!("ResponseError"); - return Err(Error::ResponseError); - }, // // Reference: https://substrate.stackexchange.com/questions/7634/how-to-properly-handle-cross-contract-call-errors/7843#7843 + // Note: if you get `Decode(Error)` then likely an issue in callee method // // Contract Success // @@ -184,25 +177,24 @@ mod unnamed { ink::env::debug_println!("contract success tuple {:?}", tuple); return Ok(tuple); }, - // Contract or Lang Error + // Contract Error // - // About: Lang errors include calling a method that does not exist // About: Contract errors include handling `Err(())` responses from callee cross-contract method + // e.g. `return Err(Error::CouldNotReadInput)` + // + EnvResult::Ok(MessageResult::Ok(ContractResult::Err(e))) => { + ink::env::debug_println!("contract error {:?}", e); + return Err(Error::ResponseError); + }, + // Lang Error + // + // About: Lang errors include calling a method that does not exist + // e.g. caller calling callee method `get_entropy_for_market_id_xyz` that does not exist // // See https://docs.rs/ink/latest/ink/enum.LangError.html - EnvResult::Ok(MessageResult::Err(e)) => { - ink::env::debug_println!("contract or lang error occurred {:?}", e); - - match e { - ink::LangError::CouldNotReadInput => { - ink::env::debug_println!("CouldNotReadInput lang error occurred"); - return Err(Error::ResponseError); - }, - _ => { - ink::env::debug_println!("unknown lang error occurred"); - return Err(Error::ResponseError); - } - } + EnvResult::Ok(MessageResult::Err(ink::LangError::CouldNotReadInput)) => { + ink::env::debug_println!("LangError::CouldNotReadInput"); + return Err(Error::ResponseError); }, // Environment Error // diff --git a/dapps/xcm/unnamed/oracle_contract/lib.rs b/dapps/xcm/unnamed/oracle_contract/lib.rs index d03b4ac..da458a9 100644 --- a/dapps/xcm/unnamed/oracle_contract/lib.rs +++ b/dapps/xcm/unnamed/oracle_contract/lib.rs @@ -378,9 +378,6 @@ mod oracle_contract { }); let entropy_data = EntropyData(block_number_entropy, block_hash_entropy.clone(), c1_rem, c2_rem); - // Early exit with error for demo purposes - // return Err(Error::ResponseError); // Decode(Error) - return Err(Error::CouldNotReadInput); // Decode(Error) Ok(entropy_data) } From 4ae3e638c2c986835905724c3233f208ab223ecf Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 20 Jun 2023 14:01:43 +1000 Subject: [PATCH 22/58] setup moonbeam MyToken template --- dapps/evm/flipper | 1 + 1 file changed, 1 insertion(+) create mode 160000 dapps/evm/flipper diff --git a/dapps/evm/flipper b/dapps/evm/flipper new file mode 160000 index 0000000..4147b3c --- /dev/null +++ b/dapps/evm/flipper @@ -0,0 +1 @@ +Subproject commit 4147b3cc277aaef45f18dbc4096d2aa2443fff20 From 39fcd9294a29dddc3478d188277615f3a075d01e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 20 Jun 2023 21:15:02 +1000 Subject: [PATCH 23/58] ipsp22 --- Cargo.lock | 309 ++++++++++++++++-- Cargo.toml | 1 + .../IPSP22/contract/IPSP22/Cargo.toml | 32 ++ dapps/ink-rust/IPSP22/contract/IPSP22/lib.rs | 29 ++ 4 files changed, 346 insertions(+), 25 deletions(-) create mode 100644 dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml create mode 100644 dapps/ink-rust/IPSP22/contract/IPSP22/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9b15c93..baeb661 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "blake2" version = "0.10.6" @@ -419,6 +430,20 @@ dependencies = [ "serde", ] +[[package]] +name = "cargo_metadata" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081e3f0755c1f380c2d010481b6fa2e02973586d5f2b24eebb7a2a1d98b143d8" +dependencies = [ + "camino", + "cargo-platform", + "semver 0.11.0", + "semver-parser", + "serde", + "serde_json", +] + [[package]] name = "cargo_metadata" version = "0.15.4" @@ -427,7 +452,7 @@ checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.17", "serde", "serde_json", "thiserror", @@ -490,7 +515,7 @@ version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.18", @@ -529,6 +554,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "const_format" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.2.6" @@ -542,18 +587,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb8253488f391d647a46fe67a6f09ad2547ee01a9acf6eba4b75778fde18ba7a" dependencies = [ "anyhow", - "blake2", - "cargo_metadata", + "blake2 0.10.6", + "cargo_metadata 0.15.4", "clap", "colored", "contract-metadata", - "heck", + "heck 0.4.1", "hex", "impl-serde 0.4.0", "parity-scale-codec", "parity-wasm", "rustc_version", - "semver", + "semver 1.0.17", "serde", "serde_json", "tempfile", @@ -574,7 +619,7 @@ checksum = "e6aa9a99669a8f4eba55782175659dbb20459698c5a65a9f3efe7b9330dd667b" dependencies = [ "anyhow", "impl-serde 0.4.0", - "semver", + "semver 1.0.17", "serde", "serde_json", "url", @@ -1031,6 +1076,16 @@ dependencies = [ "serde", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "funty" version = "2.0.0" @@ -1244,6 +1299,15 @@ dependencies = [ "ahash 0.8.3", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.1" @@ -1542,11 +1606,11 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "251e64f2dd74e98329a05812f067f34e2b494a7b1325e538165e481378a72747" dependencies = [ - "blake2", + "blake2 0.10.6", "derive_more", "either", "env_logger", - "heck", + "heck 0.4.1", "impl-serde 0.4.0", "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ink_primitives 4.2.1", @@ -1565,10 +1629,10 @@ name = "ink_codegen" version = "4.2.0" source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ - "blake2", + "blake2 0.10.6", "derive_more", "either", - "heck", + "heck 0.4.1", "impl-serde 0.4.0", "ink_ir 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", "ink_primitives 4.2.0", @@ -1614,7 +1678,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b10565389b24f8aa5bbd5bab2c38136f7e6f5067876f50a3941a8d78c30c4d8" dependencies = [ - "cargo_metadata", + "cargo_metadata 0.15.4", "contract-build", "derive_more", "env_logger", @@ -1633,7 +1697,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c4af49e092a93e65d1161ce31d23c2e57d724462c96a8944acd647a52787f0" dependencies = [ - "blake2", + "blake2 0.10.6", "derive_more", "ink_primitives 4.2.1", "parity-scale-codec", @@ -1647,7 +1711,7 @@ name = "ink_engine" version = "4.2.0" source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ - "blake2", + "blake2 0.10.6", "derive_more", "ink_primitives 4.2.0", "parity-scale-codec", @@ -1663,7 +1727,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5e1505c5deb7280743e4d7df72a91f52bbf4cb063f464c73f89dce00c70f92" dependencies = [ "arrayref", - "blake2", + "blake2 0.10.6", "cfg-if", "derive_more", "ink_allocator 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1690,7 +1754,7 @@ version = "4.2.0" source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ "arrayref", - "blake2", + "blake2 0.10.6", "cfg-if", "derive_more", "ink_allocator 4.2.0 (git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number)", @@ -1717,7 +1781,7 @@ version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c0e2d96fc6e5b5cb1696b8057e72958315076dbe3f427e8f7722a346344f27a" dependencies = [ - "blake2", + "blake2 0.10.6", "either", "itertools", "proc-macro2", @@ -1730,7 +1794,7 @@ name = "ink_ir" version = "4.2.0" source = "git+https://github.com/ltfschoen/ink?branch=ltfschoen-env-offchain-test-set-block-number#d372cced1ec74143b7aabfaa4ca5ae08bb5f7f2c" dependencies = [ - "blake2", + "blake2 0.10.6", "either", "ink_prelude 4.2.0", "itertools", @@ -1752,7 +1816,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.18", - "synstructure", + "synstructure 0.13.0", ] [[package]] @@ -1767,7 +1831,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.18", - "synstructure", + "synstructure 0.13.0", ] [[package]] @@ -2346,6 +2410,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "my_token" +version = "0.1.0" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_e2e", + "openbrush", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2414,6 +2489,42 @@ dependencies = [ "libc", ] +[[package]] +name = "obce" +version = "0.1.0" +source = "git+https://github.com/727-Ventures/obce?branch=polkadot-v0.9.37#d452f6eda1bc1ecb36e7e332d61529ad440d5a89" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_engine 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "obce-macro", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "obce-codegen" +version = "0.1.0" +source = "git+https://github.com/727-Ventures/obce?branch=polkadot-v0.9.37#d452f6eda1bc1ecb36e7e332d61529ad440d5a89" +dependencies = [ + "blake2 0.10.6", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", + "tuple", +] + +[[package]] +name = "obce-macro" +version = "0.1.0" +source = "git+https://github.com/727-Ventures/obce?branch=polkadot-v0.9.37#d452f6eda1bc1ecb36e7e332d61529ad440d5a89" +dependencies = [ + "obce-codegen", + "proc-macro2", + "syn 1.0.109", + "synstructure 0.12.6", +] + [[package]] name = "object" version = "0.29.0" @@ -2453,6 +2564,74 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openbrush" +version = "3.1.1" +source = "git+https://github.com/727-Ventures/openbrush-contracts/?tag=3.1.1#13e82f3f02e8ea65a95ea02c381106ea738e1fb8" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openbrush_contracts", + "openbrush_lang", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "openbrush_contracts" +version = "3.1.1" +source = "git+https://github.com/727-Ventures/openbrush-contracts/?tag=3.1.1#13e82f3f02e8ea65a95ea02c381106ea738e1fb8" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openbrush_lang", + "pallet-assets-chain-extension", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "openbrush_lang" +version = "3.1.1" +source = "git+https://github.com/727-Ventures/openbrush-contracts/?tag=3.1.1#13e82f3f02e8ea65a95ea02c381106ea738e1fb8" +dependencies = [ + "const_format", + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openbrush_lang_macro", + "parity-scale-codec", + "scale-info", + "xxhash-rust", +] + +[[package]] +name = "openbrush_lang_codegen" +version = "3.1.1" +source = "git+https://github.com/727-Ventures/openbrush-contracts/?tag=3.1.1#13e82f3f02e8ea65a95ea02c381106ea738e1fb8" +dependencies = [ + "blake2 0.9.2", + "cargo_metadata 0.13.1", + "fs2", + "heck 0.3.3", + "ink_ir 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ink_primitives 4.2.1", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 1.0.109", + "synstructure 0.12.6", + "unwrap", +] + +[[package]] +name = "openbrush_lang_macro" +version = "3.1.1" +source = "git+https://github.com/727-Ventures/openbrush-contracts/?tag=3.1.1#13e82f3f02e8ea65a95ea02c381106ea738e1fb8" +dependencies = [ + "openbrush_lang_codegen", + "proc-macro2", + "syn 1.0.109", + "synstructure 0.12.6", +] + [[package]] name = "openssl-probe" version = "0.1.5" @@ -2479,6 +2658,17 @@ dependencies = [ "scale-info", ] +[[package]] +name = "pallet-assets-chain-extension" +version = "0.1.1" +source = "git+https://github.com/727-ventures/pallet-assets-chain-extension?branch=polkadot-v0.9.37#f8ea374186df2a3fc139c8d585719e58d83df582" +dependencies = [ + "ink 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "obce", + "parity-scale-codec", + "scale-info", +] + [[package]] name = "pallet-contracts-primitives" version = "23.0.0" @@ -2579,6 +2769,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pest" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16833386b02953ca926d19f64af613b9bf742c48dcd5e09b32fbfc9740bf84e2" +dependencies = [ + "thiserror", + "ucd-trie", +] + [[package]] name = "pin-project" version = "1.1.0" @@ -2874,7 +3074,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.17", ] [[package]] @@ -3243,6 +3443,16 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", + "serde", +] + [[package]] name = "semver" version = "1.0.17" @@ -3252,6 +3462,15 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.164" @@ -3454,7 +3673,7 @@ checksum = "7789372146f8ad40d0b40fad0596cb1db5771187a258eabe19b06f00767fcbd6" dependencies = [ "array-bytes", "bitflags", - "blake2", + "blake2 0.10.6", "bounded-collections", "bs58", "dyn-clonable", @@ -3812,7 +4031,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -3845,7 +4064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53b9c4ddefcb2d87eb18a6336f65635c29208f766d0deefaa2a1a19f7426a993" dependencies = [ "base58", - "blake2", + "blake2 0.10.6", "derivative", "either", "frame-metadata", @@ -3881,7 +4100,7 @@ checksum = "e924f41069e9273236398ff89662d6d336468a5d94faac812129d44547db0e7f" dependencies = [ "darling", "frame-metadata", - "heck", + "heck 0.4.1", "hex", "jsonrpsee 0.16.2", "parity-scale-codec", @@ -3940,6 +4159,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + [[package]] name = "synstructure" version = "0.13.0" @@ -4270,6 +4501,16 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tuple" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a40ba241047e1174c927dc5f61c141a166b938d61a2ff61838441368cc7d0e" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -4288,6 +4529,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + [[package]] name = "uint" version = "0.9.5" @@ -4321,6 +4568,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -4350,6 +4603,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "unwrap" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e33648dd74328e622c7be51f3b40a303c63f93e6fa5f08778b6203a4c25c20f" + [[package]] name = "url" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index 5313a6b..0b9abc1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ exclude = [] members = [ "dapps/ink-rust/wasm-flipper/contract/flipper", + "dapps/ink-rust/IPSP22/contract/IPSP22", "dapps/xcm/unnamed", "dapps/basic_contract_caller", ] diff --git a/dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml b/dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml new file mode 100644 index 0000000..1cc7e69 --- /dev/null +++ b/dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "my_token" +version = "0.1.0" +authors = ["0xD1x0n"] +edition = "2021" +license = "Apache 2.0" + +[dependencies] +ink = { version = "4.2", default-features = false } +openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts/", tag = "3.1.1", default-features = false, features = ["psp22", "ownable"] } + +scale = { package = "parity-scale-codec", version = "3.5.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.7", default-features = false, features = ["derive"], optional = true } + + +[dev-dependencies] +ink_e2e = { version = "4.2.0" } + +[lib] +name = "my_token" +path = "lib.rs" + +[features] +default = ["std"] +std = [ + "ink/std", + "scale/std", + "scale-info/std", + "openbrush/std", +] +ink-as-dependency = [] +e2e-tests = [] diff --git a/dapps/ink-rust/IPSP22/contract/IPSP22/lib.rs b/dapps/ink-rust/IPSP22/contract/IPSP22/lib.rs new file mode 100644 index 0000000..406f7c8 --- /dev/null +++ b/dapps/ink-rust/IPSP22/contract/IPSP22/lib.rs @@ -0,0 +1,29 @@ +#![cfg_attr(not(feature = "std"), no_std, no_main)] +#![feature(min_specialization)] + +#[openbrush::contract] +pub mod my_psp22 { + + // imports from openbrush + use openbrush::contracts::psp22::*; + use openbrush::traits::Storage; + + #[ink(storage)] + #[derive(Default, Storage)] + pub struct Ipsp22 { + #[storage_field] + psp22: psp22::Data, + } + + // Section contains default implementation without any modifications + impl PSP22 for Ipsp22 {} + + impl Ipsp22 { + #[ink(constructor)] + pub fn new(initial_supply: Balance) -> Self { + let mut _instance = Self::default(); + _instance._mint_to(_instance.env().caller(), initial_supply).expect("Should mint"); + _instance + } + } +} From 73750e6f5c063d0d0f2851537eff702eceada712 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 21 Jun 2023 17:47:10 +1000 Subject: [PATCH 24/58] update readme and add ipsp22 script --- README.md | 29 +++++++++++++++-- docker/quickstart-ipsp22.sh | 64 +++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100755 docker/quickstart-ipsp22.sh diff --git a/README.md b/README.md index 5a65bc4..a27d4f0 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ * Build & Upload * [**Quickstart** Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#quick-build-upload) * [**Quickstart** Build & Upload ink! Rust "Basic Contract Caller" Smart Contract to Local Testnet (using Cargo Contract)](#quick-basic-contract-caller) + * [**Quickstart** Build & Upload ink! Rust "IPSP22" Smart Contract to Local Testnet (using Cargo Contract)](#quick-ipsp22) * [**Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract)](#quick-unnamed) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#build-upload) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Swanky CLI)](#build-upload-swanky) @@ -147,12 +148,33 @@ docker exec -it ink /app/docker/quickstart.sh ```bash docker exec -it ink /bin/bash ``` - * Run quickstart + * Run in terminal tab 1 ```bash ./docker/reset.sh + ``` + * Run in terminal tab 2 + ``` ./docker/quickstart-basic-contract-caller.sh ``` +### **Demo Quickstart** Build & Upload ink! Rust "IPSP22" Smart Contract to Local Testnet (using Cargo Contract) + +#### Run from shell inside Docker container + + * Enter shell of Docker container + ```bash + docker exec -it ink /bin/bash + ``` + * Run in terminal tab 1 + ```bash + ./docker/reset.sh + ``` + * Run in terminal tab 2 + ```bash + cd /app + ./docker/quickstart-ipsp22.sh + ``` + ### **Demo Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract) #### Run from shell inside Docker container @@ -161,9 +183,12 @@ docker exec -it ink /app/docker/quickstart.sh ```bash docker exec -it ink /bin/bash ``` - * Run quickstart + * Run in terminal tab 1 ```bash ./docker/reset.sh + ``` + * Run in terminal tab 2 + ```` ./docker/quickstart-unnamed.sh ``` diff --git a/docker/quickstart-ipsp22.sh b/docker/quickstart-ipsp22.sh new file mode 100755 index 0000000..cd41b9c --- /dev/null +++ b/docker/quickstart-ipsp22.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +echo "Building contracts..." +cd $PARENT_DIR/dapps/basic_contract_caller +PROJECT_ROOT=$PARENT_DIR/dapps/ink-rust/IPSP22/contract/IPSP22 +cargo +nightly-2023-03-21-x86_64-unknown-linux-gnu contract build \ + --manifest-path $PARENT_DIR/dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml + +cd $PROJECT_ROOT + +echo "Uploading contract..." +args=( + --suri //Alice + --execute + # --skip-dry-run + --skip-confirm + $PARENT_DIR/target/ink/my_token/my_token.wasm +) +OUTPUT_CODE_HASH=$( + cargo contract upload "${args[@]}" | tail -1 +) +echo "Finished uploading contract..." +# example: ' Code hash "0x..."' +echo $OUTPUT_CODE_HASH +# remove text 'Code hash' and the outer double quotes of the code hash +OUTPUT_CODE_HASH_REMOVED_LABEL=$(echo "$OUTPUT_CODE_HASH" | sed 's/Code hash//;s/$//' | tr -d '"') +# trim whitespace +CODE_HASH_MAIN=$(echo $OUTPUT_CODE_HASH_REMOVED_LABEL) +echo $CODE_HASH_MAIN + +cd $PROJECT_ROOT + +echo "Instantiating contract..." + +INITIAL_SUPPLY="100000000" +args=( + --manifest-path $PARENT_DIR/dapps/ink-rust/IPSP22/contract/IPSP22/Cargo.toml + --suri //Alice + --constructor new + --args $INITIAL_SUPPLY + --execute + --gas 1000000000000 + --proof-size 1000000000000 + # --skip-dry-run + --skip-confirm +) +OUTPUT_CONTRACT_ADDR=$( + cargo contract instantiate "${args[@]}" | tail -1 +) + +# example: ' Contract 5...' +echo $OUTPUT_CONTRACT_ADDR +# remove text 'Contract' +OUTPUT_CONTRACT_ADDR_REMOVED_LABEL=$(echo "$OUTPUT_CONTRACT_ADDR" | sed 's/Contract//;s/$//') +# trim whitespace using `echo ...` +CONTRACT_ADDR_MAIN=$(echo $OUTPUT_CONTRACT_ADDR_REMOVED_LABEL) +echo $CONTRACT_ADDR_MAIN From 768361f7f9041bf6a1fa9aedb5e29fd0b1dba7dc Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 23 Jun 2023 05:30:20 +1000 Subject: [PATCH 25/58] add evm example pending astar response --- dapps/basic_contract_caller/lib.rs | 55 +++++++++ dapps/evm/flipper | 1 - dapps/evm2/flipper/.env.example | 2 + dapps/evm2/flipper/.gitignore | 5 + dapps/evm2/flipper/LICENSE | 22 ++++ dapps/evm2/flipper/README.md | 108 ++++++++++++++++++ dapps/evm2/flipper/contracts/Flipper.sol | 24 ++++ dapps/evm2/flipper/contracts/Migrations.sol | 19 +++ .../flipper/migrations/1_initial_migration.js | 5 + .../flipper/migrations/2_deploy_contracts.js | 5 + dapps/evm2/flipper/package.json | 11 ++ dapps/evm2/flipper/test/test_Flipper.js | 24 ++++ dapps/evm2/flipper/truffle-box.json | 21 ++++ dapps/evm2/flipper/truffle-config.js | 81 +++++++++++++ dapps/evm2/flipper/tx.log | 68 +++++++++++ docker/quickstart-basic-contract-caller.sh | 19 +++ 16 files changed, 469 insertions(+), 1 deletion(-) delete mode 160000 dapps/evm/flipper create mode 100644 dapps/evm2/flipper/.env.example create mode 100644 dapps/evm2/flipper/.gitignore create mode 100644 dapps/evm2/flipper/LICENSE create mode 100644 dapps/evm2/flipper/README.md create mode 100644 dapps/evm2/flipper/contracts/Flipper.sol create mode 100644 dapps/evm2/flipper/contracts/Migrations.sol create mode 100644 dapps/evm2/flipper/migrations/1_initial_migration.js create mode 100644 dapps/evm2/flipper/migrations/2_deploy_contracts.js create mode 100644 dapps/evm2/flipper/package.json create mode 100644 dapps/evm2/flipper/test/test_Flipper.js create mode 100644 dapps/evm2/flipper/truffle-box.json create mode 100644 dapps/evm2/flipper/truffle-config.js create mode 100644 dapps/evm2/flipper/tx.log diff --git a/dapps/basic_contract_caller/lib.rs b/dapps/basic_contract_caller/lib.rs index e7c791c..e8b58e7 100755 --- a/dapps/basic_contract_caller/lib.rs +++ b/dapps/basic_contract_caller/lib.rs @@ -9,6 +9,7 @@ mod basic_contract_caller { ExecutionInput, Selector, }, + Call, DefaultEnvironment, }; @@ -65,6 +66,60 @@ mod basic_contract_caller { } } + /// Reference: https://github.com/hyperledger/solang/blob/main/integration/substrate/ink/caller/lib.rs#L33-L38 + /// Do a proxy call to `callee` and return its result. + #[ink(message)] + pub fn u32_proxy( + &self, + callee: AccountId, // contract address + selector: [u8; 4], // method + // arg: u32, // args + max_gas: Option, + transfer_value: Option, + ) -> bool { + let res = build_call::() + .call_type(Call::new(callee).gas_limit(max_gas.unwrap_or_default())) + // .transferred_value(transfer_value.unwrap_or_default()) + .transferred_value(0) + .exec_input(ExecutionInput::new( + Selector::new(selector)) + // .push_arg(arg) + ) + .returns::() // FIXME: This should be Result to respect LanguageError + .try_invoke() + .expect("Error calling get."); + + ink::env::debug_println!("res {:?}", res); + + match res { + // Contract Success + EnvResult::Ok(MessageResult::Ok(ContractResult::Ok(tuple))) => { + ink::env::debug_println!("contract success tuple {:?}", tuple); + return Ok(tuple); + }, + // Contract Error + EnvResult::Ok(MessageResult::Ok(ContractResult::Err(e))) => { + ink::env::debug_println!("contract error {:?}", e); + return Err(Error::ResponseError); + }, + // Lang Error + EnvResult::Ok(MessageResult::Err(ink::LangError::CouldNotReadInput)) => { + ink::env::debug_println!("LangError::CouldNotReadInput"); + return Err(Error::ResponseError); + }, + // Environment Error + EnvResult::Err(e) => { + ink::env::debug_println!("environment error occurred {:?}", e); + return Err(Error::ResponseError); + }, + // Unimplemented Error + _ => { + ink::env::debug_println!("unimplemented error in u32_proxy"); + return unimplemented!(); + }, + }; + } + #[ink(message)] pub fn get(&mut self) -> Result { match &self.other_contract_address { diff --git a/dapps/evm/flipper b/dapps/evm/flipper deleted file mode 160000 index 4147b3c..0000000 --- a/dapps/evm/flipper +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4147b3cc277aaef45f18dbc4096d2aa2443fff20 diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example new file mode 100644 index 0000000..27ef570 --- /dev/null +++ b/dapps/evm2/flipper/.env.example @@ -0,0 +1,2 @@ +# https://faucet.moonbeam.network/ +MOONBASE_PRIVATE_KEY='0x' diff --git a/dapps/evm2/flipper/.gitignore b/dapps/evm2/flipper/.gitignore new file mode 100644 index 0000000..f332a0a --- /dev/null +++ b/dapps/evm2/flipper/.gitignore @@ -0,0 +1,5 @@ +build +node_modules +package-lock.json +release-version.json +.env diff --git a/dapps/evm2/flipper/LICENSE b/dapps/evm2/flipper/LICENSE new file mode 100644 index 0000000..bb98c92 --- /dev/null +++ b/dapps/evm2/flipper/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2018 Truffle + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md new file mode 100644 index 0000000..60f16ae --- /dev/null +++ b/dapps/evm2/flipper/README.md @@ -0,0 +1,108 @@ +# Flipper + +Note: The following was based upon Moonbeam Truffle Box https://docs.moonbeam.network/builders/build/eth-api/dev-env/truffle/ + +## Getting started + +* Install Node.js v18.x (i.e. v18.16.0) since has LTS https://nodejs.org/en/download/releases +* Use an LTS version of NPM to avoid error `This version of µWS is not compatible with your Node.js build` https://stackoverflow.com/questions/71081725/this-version-of-%C2%B5ws-is-not-compatible-with-your-node-js-build-error-node-loade + +```bash +apt-get remove -y nodejs +rm -rf /usr/lib/node_modules/ +curl -fsSL https://deb.nodesource.com/setup_18.x | bash - +apt-get install -y nodejs +curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /usr/share/keyrings/yarnkey.gpg >/dev/null +echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | tee /etc/apt/sources.list.d/yarn.list +apt-get update && apt-get install yarn +npm config rm proxy +npm config rm https-proxy +``` +* Install Truffle dependency: +```bash +npm install -g truffle +``` +* Check if works +```bash +truffle --version +``` +* Fix permissions error since /usr/bin/truffle symlinks to below but below didn't have execute permissions for any users +```bash +chmod 755 /usr/lib/node_modules/truffle/build/cli.bundled.js +``` +* Setup Moonbeam Truffle Box template that this has been based upon +```bash +mkdir -p /app/dapps/evm/flipper +DAPP_PATH=/app/dapps/evm/flipper +git clone https://github.com/PureStake/moonbeam-truffle-box $DAPP_PATH +cd $DAPP_PATH +```bash +* Replace template contracts with just https://github.com/hyperledger/solang/blob/main/examples/substrate/flipper.sol and add `pragma solidity ^0.8.0;` + +* Update all dependencies in package.json to new major version +```bash +npm outdated +npm install -g npm-check-updates +ncu -u +npm update +``` +* Install dependencies +```bash +npm install +``` + +* Install Docker in Docker container +```bash +apt-get remove docker docker-engine docker.io containerd runc +apt-get update && apt-get upgrade -y +apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - +apt-key fingerprint 0EBFCD88 +add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" +apt-get update +apt-get install docker-ce docker-ce-cli containerd.io -y +adduser user +usermod -aG docker user +systemctl restart docker +systemctl enable docker +apt-get install -y docker-compose-plugin +apt-get install docker-compose +``` + +Note: It is necessary to run Docker within a Docker container https://devopscube.com/run-docker-in-docker/ in order to use `truffle run moonbeam ...` commands from https://trufflesuite.com/boxes/moonbeam-truffle-box/, which use the Moonbeam Truffle Box plugin https://github.com/PureStake/moonbeam-truffle-plugin, which uses images from Docker hub https://hub.docker.com/r/purestake/moonbeam/tags, or setup manually by following https://docs.moonbeam.network/node-operators/networks/run-a-node/flags/, as follows: + +To run a local node run similar to the following: +```bash +mkdir /opt/moonbeam +git clone https://github.com/PureStake/moonbeam /opt/moonbeam +cd /opt/moonbeam +git checkout tags/$(git describe --tags) +cargo build +./target/debug/moonbeam --help +``` + +Then configure Truffle to connect to it Moonbeam Development `node_modules/.bin/truffle migrate --network dev`. Note that use of Ganache does not include pre-compiles https://docs.moonbeam.network/builders/build/eth-api/dev-env/truffle/. + +Preferably use Moonbase Alpha TestNet `node_modules/.bin/truffle migrate --network moonbase` that requires testnet tokens from the faucet https://faucet.moonbeam.network/. + +Run tests +``` +truffle test +``` + +* Generate account with Moonkey https://docs.moonbeam.network/node-operators/networks/collators/requirements/#generating-an-account-with-moonkey +``` +cd /opt +wget https://github.com/PureStake/moonbeam/releases/download/v0.8.0/moonkey /opt +shasum -a 256 moonkey +``` +* Verify output is `019c3de832ded3fccffae950835bb455482fca92714448cc0086a7c5f3d48d3e` +* Generate account `./moonkey --w12` +* Obtain Moonbase Alpha tokens from faucet + * https://faucet.moonbeam.network/ + +* Compile contracts on network of choice (i.e. "moonbase") defined in truffle.js + * Compile full `truffle compile --compile-all` +* Migrate + * Migrate full `truffle migrate --reset --compile-all --network moonbase` +* TODO - use for cross-contract calls diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol new file mode 100644 index 0000000..563bd28 --- /dev/null +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract Flipper { + bool private value; + + /// Constructor that initializes the `bool` value to the given `init_value`. + constructor(bool initvalue) { + value = initvalue; + } + + /// A message that can be called on instantiated contracts. + /// This one flips the value of the stored `bool` from `true` + /// to `false` and vice versa. + function flip() public { + value = !value; + } + + /// Simply returns the current value of our `bool`. + function get() public view returns (bool) { + return value; + } +} diff --git a/dapps/evm2/flipper/contracts/Migrations.sol b/dapps/evm2/flipper/contracts/Migrations.sol new file mode 100644 index 0000000..d8a066a --- /dev/null +++ b/dapps/evm2/flipper/contracts/Migrations.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Migrations { + address public owner; + uint public last_completed_migration; + + constructor() { + owner = msg.sender; + } + + modifier restricted() { + if (msg.sender == owner) _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } +} diff --git a/dapps/evm2/flipper/migrations/1_initial_migration.js b/dapps/evm2/flipper/migrations/1_initial_migration.js new file mode 100644 index 0000000..877c9fa --- /dev/null +++ b/dapps/evm2/flipper/migrations/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = deployer => { + deployer.deploy(Migrations); +}; diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js new file mode 100644 index 0000000..99584ad --- /dev/null +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -0,0 +1,5 @@ +var Flipper = artifacts.require("Flipper"); + +module.exports = function (deployer) { + deployer.deploy(Flipper, false); +}; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json new file mode 100644 index 0000000..7fd6089 --- /dev/null +++ b/dapps/evm2/flipper/package.json @@ -0,0 +1,11 @@ +{ + "name": "flipper", + "version": "1.0.0", + "dependencies": { + "@truffle/hdwallet-provider": "^2.1.12", + "dotenv": "^16.3.1", + "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", + "truffle": "^5.10.0", + "truffle-plugin-verify": "^0.6.3" + } +} diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js new file mode 100644 index 0000000..8309ede --- /dev/null +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -0,0 +1,24 @@ +// Uses Mocha and Ganache +const Flipper = artifacts.require("Flipper"); + +contract('Flipper', accounts => { + let flipper; + const initValue = false; + beforeEach(async () => { + // Deploy token contract + flipper = await Flipper.new(initValue, { from: accounts[0] }); + }); + // Check stored value + it("checks stored value", async () => { + const value = await flipper.get.call(); + assert.equal(value, initValue, 'value stored does not match initial value'); + }); + + // Set flipped value of existing value + it("should flip the value", async () => { + const previousValue = await flipper.get.call(); + await flipper.flip.call({ from: accounts[0] }); + const newValue = await flipper.flip.call(); + assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); + }) +}); diff --git a/dapps/evm2/flipper/truffle-box.json b/dapps/evm2/flipper/truffle-box.json new file mode 100644 index 0000000..fd175e1 --- /dev/null +++ b/dapps/evm2/flipper/truffle-box.json @@ -0,0 +1,21 @@ +{ + "ignore": [ + "README.md", + ".gitignore" + ], + "commands": { + "Compile contracts": "truffle compile", + "Migrate contracts": "truffle migrate", + "Test contracts": "truffle test", + "Pull docker image development node": "truffle run moonbeam install", + "Start development node": "truffle run moonbeam start", + "Stop docker image development node": "truffle run moonbeam stop", + "Pause development node": "truffle run moonbeam pause", + "Unpause docker image development node": "truffle run moonbeam unpause", + "Get development node status": "truffle run moonbeam status", + "Remove docker image development node": "truffle run moonbeam remove" + }, + "hooks": { + "post-unpack": "" + } +} diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js new file mode 100644 index 0000000..1673cf3 --- /dev/null +++ b/dapps/evm2/flipper/truffle-config.js @@ -0,0 +1,81 @@ +const HDWalletProvider = require('@truffle/hdwallet-provider'); +require('dotenv').config() + +// Moonbeam Development Node Private Key +const privateKeyDev = + '99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342'; +// Moonbase Alpha Private Key --> Please change this to your own Private Key with funds +// NOTE: Do not store your private key in plaintext files +// this is only for demostration purposes only +const privateKeyMoonbase = process.env.MOONBASE_PRIVATE_KEY; + +module.exports = { + networks: { + // Moonbeam Development Network + dev: { + provider: () => { + if (!privateKeyDev.trim()) { + throw new Error( + 'Please enter a private key with funds, you can use the default one' + ); + } + let args = { + privateKeys: [privateKeyDev], + providerOrUrl: 'http://localhost:9944/', + }; + return new HDWalletProvider(args); + }, + network_id: 1281, + }, + // Moonbase Alpha TestNet + moonbase: { + provider: () => { + if (!privateKeyMoonbase.trim()) { + throw new Error( + 'Please enter a private key with funds to send transactions to TestNet' + ); + } + if (privateKeyDev == privateKeyMoonbase) { + throw new Error( + 'Please change the private key used for Moonbase to your own with funds' + ); + } + // First argument to new HDWalletProvider() must be a mnemonic phrase, + // a single private key, or a list of private keys. + // Expected private key is a Uint8Array with length 32 + // https://github.com/trufflesuite/truffle/tree/develop/packages/hdwallet-provider + let args = { + privateKeys: [privateKeyMoonbase], + providerOrUrl: 'https://rpc.api.moonbase.moonbeam.network', + }; + return new HDWalletProvider(args); + }, + network_id: 1287, + }, + // faucet for SBY https://docs.astar.network/docs/build/environment/faucet + astar_shibuya: { + provider: () => { + let args = { + privateKeys: [privateKeyAstarShibuya], + providerOrUrl: 'https://evm.shibuya.astar.network', + }; + return new HDWalletProvider(args); + }, + network_id: 81, + }, + }, + // Solidity 0.8.20 Compiler + compilers: { + solc: { + version: '^0.8.20', + settings: { + // Fixes `"Migrations" -- evm error: InvalidCode(Opcode(95))` + // https://docs.moonbeam.network/tutorials/eth-api/truffle-start-to-end/ + // https://docs.moonbeam.network/builders/build/eth-api/dev-env/remix/ + evmVersion: 'london', + }, + }, + }, + // Moonbeam Truffle Plugin & Truffle Plugin for Verifying Smart Contracts + plugins: ['moonbeam-truffle-plugin', 'truffle-plugin-verify'], +}; diff --git a/dapps/evm2/flipper/tx.log b/dapps/evm2/flipper/tx.log new file mode 100644 index 0000000..ada048e --- /dev/null +++ b/dapps/evm2/flipper/tx.log @@ -0,0 +1,68 @@ +# truffle migrate --reset --compile-all --network moonbase + +Compiling your contracts... +=========================== +✓ Fetching solc version list from solc-bin. Attempt #1 +> Compiling ./contracts/Flipper.sol +> Compiling ./contracts/Migrations.sol +> Artifacts written to /app/dapps/evm/flipper/build/contracts +> Compiled successfully using: + - solc: 0.8.20+commit.a1b79de6.Emscripten.clang + + +Starting migrations... +====================== +> Network name: 'moonbase' +> Network id: 1287 +> Block gas limit: 15000000 (0xe4e1c0) + + +1_initial_migration.js +====================== + + Deploying 'Migrations' + ---------------------- + > transaction hash: 0x298584422c67c41b93f62adb5c828fd3690d8bc6ccbf37d82dcab78e12fad8cd + > Blocks: 1 Seconds: 24 + > contract address: 0xE691d9f144Ae51139f2f8571CA3b0cd17Db8D5A0 + > block number: 4583829 + > block timestamp: 1687339224 + > account: 0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7 + > balance: 1.099467316625 + > gas used: 202927 (0x318af) + > gas price: 2.625 gwei + > value sent: 0 ETH + > total cost: 0.000532683375 ETH + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0.000532683375 ETH + + +2_deploy_contracts.js +===================== + + Deploying 'Flipper' + ------------------- + > transaction hash: 0x5e64f8df75775a48abe17c4c82cbca6188800d9df529f2cd7d276266aefd0c0b + > Blocks: 1 Seconds: 32 + > contract address: 0xa59A2606CFDAE99a18977987655a995415C39013 + > block number: 4583832 + > block timestamp: 1687339284 + > account: 0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7 + > balance: 1.099048020125 + > gas used: 113819 (0x1bc9b) + > gas price: 2.625 gwei + > value sent: 0 ETH + > total cost: 0.000298774875 ETH + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0.000298774875 ETH + +Summary +======= +> Total deployments: 2 +> Final cost: 0.00083145825 ETH diff --git a/docker/quickstart-basic-contract-caller.sh b/docker/quickstart-basic-contract-caller.sh index a826f2e..2c0cdbd 100755 --- a/docker/quickstart-basic-contract-caller.sh +++ b/docker/quickstart-basic-contract-caller.sh @@ -182,3 +182,22 @@ args=( --skip-confirm ) cargo contract call "${args[@]}" | grep --color=always -z 'data' + +# CALLEE= # contract address +# SELECTOR="get" # method +# ARG="" # arg +# MAX_GAS="200000000000" +# TRANSFER_VALUE="0" +# echo "Calling contract method u32_proxy ..." +# args=( +# --suri //Alice +# --contract $CONTRACT_ADDR_MAIN +# --message u32_proxy +# --args $CALLEE $SELECTOR $ARG $MAX_GAS $TRANSFER_VALUE +# --execute +# # --gas 200000000000 +# # --proof-size 100000000000 +# # --skip-dry-run +# --skip-confirm +# ) +# cargo contract call "${args[@]}" | grep --color=always -z 'data' From 88874424788080dab4a28699eca70a8a4e41adc3 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Fri, 23 Jun 2023 19:49:46 +1000 Subject: [PATCH 26/58] update precompile but DeploymentError RandonNumber hit a require or revert statement somewhere in its constructor --- dapps/evm2/flipper/README.md | 2 +- dapps/evm2/flipper/contracts/Flipper.sol | 4 +- .../flipper/contracts/lib/RandomNumber.sol | 60 ++++++ .../precompiles/randomness/Randomness.sol | 184 ++++++++++++++++++ .../randomness/RandomnessConsumer.sol | 126 ++++++++++++ .../flipper/migrations/2_deploy_contracts.js | 5 +- dapps/evm2/flipper/package.json | 3 +- dapps/evm2/flipper/test/test_Flipper.js | 66 ++++++- dapps/evm2/flipper/truffle-config.js | 4 +- docker/quickstart-randomness.sh | 16 ++ 10 files changed, 457 insertions(+), 13 deletions(-) create mode 100644 dapps/evm2/flipper/contracts/lib/RandomNumber.sol create mode 100644 dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol create mode 100644 dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol create mode 100755 docker/quickstart-randomness.sh diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 60f16ae..c9460d2 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -105,4 +105,4 @@ shasum -a 256 moonkey * Compile full `truffle compile --compile-all` * Migrate * Migrate full `truffle migrate --reset --compile-all --network moonbase` -* TODO - use for cross-contract calls + diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol index 563bd28..bdf2c4f 100644 --- a/dapps/evm2/flipper/contracts/Flipper.sol +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +pragma solidity >=0.8.3; + +import "./lib/RandomNumber.sol"; contract Flipper { bool private value; diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol new file mode 100644 index 0000000..45699c0 --- /dev/null +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +// https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol +// import "../precompiles/randomness/Randomness.sol"; +import {Randomness, MIN_VRF_BLOCKS_DELAY} from "../precompiles/randomness/Randomness.sol"; +// https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/RandomnessConsumer.sol +import {RandomnessConsumer} from "../precompiles/randomness/RandomnessConsumer.sol"; + +contract RandomNumber is RandomnessConsumer { + // The Randomness Precompile Interface + Randomness public randomness = + Randomness(0x0000000000000000000000000000000000000809); + + // Variables required for randomness requests + uint256 public requiredDeposit = randomness.requiredDeposit(); + uint64 public FULFILLMENT_GAS_LIMIT = 100000; + // The fee can be set to any value as long as it is enough to cover + // the fulfillment costs. Any leftover fees will be refunded to the + // refund address specified in the requestRandomness function below + uint256 public MIN_FEE = FULFILLMENT_GAS_LIMIT * 5 gwei; + uint32 public VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; + bytes32 public SALT_PREFIX = "change-me-to-anything"; + + // Storage variables for the current request + uint256 public requestId; + uint256[] public random; + + constructor() payable RandomnessConsumer() { + // Because this contract can only perform 1 random request at a time, + // We only need to have 1 required deposit. + require(msg.value >= requiredDeposit); + } + + function requestRandomness() public payable { + // Make sure that the value sent is enough + require(msg.value >= MIN_FEE); + // Request local VRF randomness + requestId = randomness.requestLocalVRFRandomWords( + msg.sender, // Refund address + msg.value, // Fulfillment fee + FULFILLMENT_GAS_LIMIT, // Gas limit for the fulfillment + SALT_PREFIX ^ bytes32(requestId++), // A salt to generate unique results + 1, // Number of random words + VRF_BLOCKS_DELAY // Delay before request can be fulfilled + ); + } + + function fulfillRequest() public { + randomness.fulfillRequest(requestId); + } + + function fulfillRandomWords( + uint256, /* requestId */ + uint256[] memory randomWords + ) internal override { + // Save the randomness results + random = randomWords; + } +} diff --git a/dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol b/dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol new file mode 100644 index 0000000..efe86b0 --- /dev/null +++ b/dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.8.3; + +/// @dev The Randomness contract's address. +address constant RANDOMNESS_ADDRESS = 0x0000000000000000000000000000000000000809; + +/// @dev The Randomness contract's instance. +Randomness constant RANDOMNESS_CONTRACT = Randomness(RANDOMNESS_ADDRESS); + +/// @dev Maximum number of random words being requested +uint32 constant MAX_RANDOM_WORDS = 100; +/// @dev Minimum number of blocks before a request can be fulfilled for Local VRF Request +uint32 constant MIN_VRF_BLOCKS_DELAY = 2; +/// @dev Maximum number of blocks before a request can be fulfilled for Local VRF Request +uint32 constant MAX_VRF_BLOCKS_DELAY = 2000; +/// @dev The deposit amount needed to request random words. There is 1 deposit per request +uint256 constant REQUEST_DEPOSIT_AMOUNT = 1000000000000000000; + +/// @author The Moonbeam Team +/// @title Pallet Randomness Interface +/// @dev The interface through which solidity contracts will interact with Randomness +/// @custom:address 0x0000000000000000000000000000000000000809 +interface Randomness { + /// @notice Event emitted when the request has been successfully executed + event FulFillmentSucceeded(); + /// @notice Event emitted when the request has failed to execute fulfillment + event FulFillmentFailed(); + + /// @notice The status of the request + /// @param DoesNotExist The request doesn't exist + /// @param Pending The request cannot be fulfilled yet + /// @param Ready The request is ready to be fulfilled + /// @param Expired The request has expired + enum RequestStatus { + DoesNotExist, + Pending, + Ready, + Expired + } + + /// @notice The type of randomness source + /// @param LocalVRF Randomness VRF using the parachain material as seed + /// @param RelayBabeEpoch Randomness VRF using relay material from previous epoch + enum RandomnessSource { + LocalVRF, + RelayBabeEpoch + } + + /// @notice The request details + /// @param id The id of the request (is always < 2**64) + /// @param refundAddress The address receiving the left-over fees after the fulfillment + /// @param contractAddress The address of the contract being called back during fulfillment + /// @param fee The amount to set aside to pay for the fulfillment + /// @param gasLimit The gas limit to use for the fulfillment + /// @param salt A string being mixed with the randomness seed to obtain different random words. This should be as unique as possible; using the same salt will lead to same randomness result. + /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) + /// @param randomnessSource The type of randomness source used to generate the random words + /// @param fulfillmentBlock The parachain block number at which the request can be fulfilled (for LocalVRF only) + /// @param fulfillmentEpochIndex The relay epoch index at which the request can be fulfilled (for RelayBabeEpoch) + /// @param expirationBlock The parachain block number at which the request expires (for LocalVRF only) + /// @param expirationEpochIndex The relay epoch index at which the request expires (for RelayBabeEpoch) + /// @param status The current status of the request + struct Request { + uint256 id; + address refundAddress; + address contractAddress; + uint256 fee; + uint256 gasLimit; + bytes32 salt; + uint32 numWords; + RandomnessSource randomnessSource; + uint32 fulfillmentBlock; + uint64 fulfillmentEpochIndex; + uint32 expirationBlock; + uint64 expirationEpochIndex; + RequestStatus status; + } + + /// Return the current relay epoch index + /// @dev An epoch represents real time and not a block number + /// @dev Currently, time between epoch changes cannot be longer than: + /// @dev - Kusama/Westend/Rococo: 600 relay blocks (1 hour) + /// @dev - Polkadot: 2400 relay blocks (4 hours) + /// @custom:selector 81797566 + function relayEpochIndex() external view returns (uint64); + + /// Return the deposit required to perform a request + /// @dev Each request will need a deposit. + /// @custom:selector fb7cfdd7 + function requiredDeposit() external view returns (uint256); + + /// @notice Returns the request status + /// @param requestId The id of the request to check (must be < 2**64) + /// @return status Status of the request + /// @custom:selector d8a4676f + function getRequestStatus(uint256 requestId) + external + view + returns (RequestStatus status); + + /// @notice Returns the request or revert + /// @param requestId The id of the request to check (must be < 2**64) + /// @return request The request + /// @custom:selector c58343ef + function getRequest(uint256 requestId) + external + view + returns (Request memory request); + + /// @notice Request random words generated from the parachain VRF + /// @dev This is using pseudo-random VRF executed by the collator at the fulfillment + /// @dev Warning: + /// @dev The collator in charge of producing the block at fulfillment can decide to skip + /// @dev producing the block in order to have a different random word generated by the next + /// @dev collator, at the cost of a block reward. It is therefore economically viable to use + /// @dev this randomness source only if the financial reward at stake is lower than the block + /// @dev reward. + /// @dev In order to reduce the risk of a collator being able to predict the random words + /// @dev when the request is performed, it is possible to increase the delay to multiple blocks + /// @dev The higher the delay is, the less likely the collator will be able to know which + /// @dev collator will be in charge of fulfilling the request. + /// @dev Fulfillment is manual and can be executed by anyone (for free) after the given delay + /// @param refundAddress The address receiving the left-over fees after the fulfillment + /// @param fee The amount to set aside to pay for the fulfillment + /// @param gasLimit The gas limit to use for the fulfillment + /// @param salt A string being mixed with the randomness seed to obtain different random words + /// @param numWords The number of random words requested (from 1 to MAX_RANDOM_WORDS) + /// @param delay The number of blocks until the request can be fulfilled (between MIN_DELAY_BLOCKS and MAX_DELAY_BLOCKS) + /// @return requestId The id of the request requestLocalVRFRandomWords + /// @custom:selector 9478430c + function requestLocalVRFRandomWords( + address refundAddress, + uint256 fee, + uint64 gasLimit, + bytes32 salt, + uint8 numWords, + uint64 delay + ) external returns (uint256); + + /// @notice Request random words generated from the relaychain Babe consensus + /// @dev The random words are generated from the hash of the all the VRF provided by the + /// @dev relaychain validator during 1 epoch. + /// @dev It requires a delay of at least 1 epoch after the current epoch to be unpredictable + /// @dev at the time the request is performed. + /// @dev Warning: + /// @dev The validator (on the relaychain) of the last block of an epoch can decide to skip + /// @dev producing the block in order to choose the previous generated epoch random number + /// @dev at the cost of a relaychain block rewards. It is therefore economically viable to use + /// @dev this randomness source only if the financial reward at stake is lower than the relaychain + /// @dev block reward. + /// @dev (see https://crates.parity.io/pallet_babe/struct.RandomnessFromOneEpochAgo.html) + /// @dev Fulfillment is manual and can be executed by anyone (for free) at + /// @dev the beginning of the 2nd relay epoch following the current one + /// @param refundAddress The address receiving the left-over fees after the fulfillment + /// @param fee Amount to set aside to pay for the fulfillment. Those fees are taken from the contract + /// @param gasLimit Gas limit for the fulfillment + /// @param salt Salt to be mixed with raw randomness to get output + /// @param numWords Number of random words to be returned (limited to MAX_RANDOM_WORDS) + /// @return requestId The id of the request + /// @custom:selector 33c14a63 + function requestRelayBabeEpochRandomWords( + address refundAddress, + uint256 fee, + uint64 gasLimit, + bytes32 salt, + uint8 numWords + ) external returns (uint256); + + /// @dev fulFill the request which will call the contract method "fulfillRandomWords" + /// @dev Fees of the caller are refunded if the request is fulfillable + /// @param requestId Request to be fulfilled (must be < 2**64) + /// @custom:selector 9a91eb0d + function fulfillRequest(uint256 requestId) external; + + /// @param requestId Request receiving the additional fees (must be < 2**64) + /// @param feeIncrease Amount to increase + /// @custom:selector d0408a7f + function increaseRequestFee(uint256 requestId, uint256 feeIncrease) + external; + + /// @param requestId Request to be purged (must be < 2**64) + /// @custom:selector 1d26cbab + function purgeExpiredRequest(uint256 requestId) external; +} diff --git a/dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol b/dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol new file mode 100644 index 0000000..590ce40 --- /dev/null +++ b/dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol @@ -0,0 +1,126 @@ +// Inspired by: https://raw.githubusercontent.com/smartcontractkit/chainlink/8e8a996fd882c0861bdc9824c1ca27c857c87d03/contracts/src/v0.8/VRFConsumerBaseV2.sol +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.8.3; + +/// @dev The Randomness contract's address. +address constant RANDOMNESS_ADDRESS = 0x0000000000000000000000000000000000000809; + +/** **************************************************************************** + * @notice Interface for contracts using VRF randomness + * ***************************************************************************** + * @dev PURPOSE + * + * @dev The purpose of this contract is to make it easy for contracts to talk to + * @dev the Randomness Precompile. It ensures 2 things: + * @dev 1. The fulfillment came from the Randomness Precompile + * @dev 2. The consumer contract implements fulfillRandomWords. + * ***************************************************************************** + * @dev USAGE + * + * @dev Calling contracts must inherit from RandomnessConsumer + * + * @dev Call one of the randomness request functions: + * @dev 1. requestLocalVRFRandomWords(refundAddress, fee, gasLimit, salt + * @dev numWords, delay), + * @dev 2. requestRelayBabeEpochRandomWords(refundAddress, fee, gasLimit, salt + * @dev numWords), + * @dev see (Randomness.sol for a description of each function and their arguments). + * + * @dev Once the request has been registered and the minimum delay is passed, the + * @dev request then can be executed (for 0 fee) by anyone. it will call your + * @dev contract's fulfillRandomWords method. + * + * @dev The randomness argument to fulfillRandomWords is a set of random words + * @dev generated from your requestId. + * + * @dev If your contract could have concurrent requests open, you can use the + * @dev requestId returned from requestRandomWords to track which response is associated + * @dev with which randomness request. + * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, + * @dev if your contract could have multiple requests in flight simultaneously. + * + * @dev Colliding `requestId`s are cryptographically impossible as long as seeds + * @dev differ. + * + * ***************************************************************************** + * @dev SECURITY CONSIDERATIONS + * + * @dev A method with the ability to call your fulfillRandomness method directly + * @dev could spoof a VRF response with any random value, so it's critical that + * @dev it cannot be directly called by anything other than this base contract + * @dev (specifically, by the RandomnessConsumer.rawFulfillRandomness method). + * + * @dev For your users to trust that your contract's random behavior is free + * @dev from malicious interference, it's best if you can write it so that all + * @dev behaviors implied by a VRF response are executed *during* your + * @dev fulfillRandomness method. If your contract must store the response (or + * @dev anything derived from it) and use it later, you must ensure that any + * @dev user-significant behavior which depends on that stored value cannot be + * @dev manipulated by a subsequent VRF request. + * + * @dev Similarly, the collators have some influence over the order in which + * @dev VRF responses appear on the blockchain, so if your contract could have + * @dev multiple VRF requests in flight simultaneously, you must ensure that + * @dev the order in which the VRF responses arrive cannot be used to manipulate + * @dev your contract's user-significant behavior. + * + * @dev Since the output of the random words generated for + * @dev *requestLocalVRFRandomWords* is dependant of the collator producing the + * @dev block at fulfillment, the collator could skip its block forcing the + * @dev fulfillment to be executed by a different collator, and therefore + * @dev generating a different VRF. + * @dev However, such an attack would incur the cost of losing the block reward to + * @dev the collator. + * @dev It is also possible for a collator to be able to predict some of the + * @dev possible outcome of the VRF if the delay between the request and the + * @dev fulfillment is too short. It is for this reason that we allow to provide + * @dev a higher delay + * + * @dev Since the output of the random words generated for + * @dev *requestRelayBabeEpochRandomWords* is dependant of the relaychain + * @dev validator producing the blocks during an epoch, it is possible for + * @dev the last validator of an epoch to choose between 2 possible VRF + * @dev outputs by skipping the production of a block. + * @dev However, such an attack would incur the cost of losing the block reward to + * @dev the validator + * @dev It is not possible for a parachain collator to predict nor influence + * @dev the output of the relaychain VRF, not to censor the fulfillment as long as + * @dev there is one honest collator. + */ +abstract contract RandomnessConsumer { + error OnlyRandomnessPrecompileCanFulfill(address have, address want); + + /** + * @notice fulfillRandomness handles the VRF response. Your contract must + * @notice implement it. See "SECURITY CONSIDERATIONS" above for important + * @notice principles to keep in mind when implementing your fulfillRandomness + * @notice method. + * + * @dev RandomnessConsumer expects its subcontracts to have a method with this + * @dev signature, and will call it once it has verified the proof + * @dev associated with the randomness. (It is triggered via a call to + * @dev rawFulfillRandomness, below.) + * + * @param requestId The Id initially returned by requestLocalVRFRandomWords or requestRelayBabeEpochRandomWords + * @param randomWords The VRF output expanded to the requested number of words + */ + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) + internal + virtual; + + // rawFulfillRandomness is called by Randomness Precompile when the executeFulfillement + // is called. rawFulfillRandomness then calls fulfillRandomness, after validating + // the origin of the call + function rawFulfillRandomWords( + uint256 requestId, + uint256[] memory randomWords + ) external { + if (msg.sender != RANDOMNESS_ADDRESS) { + revert OnlyRandomnessPrecompileCanFulfill( + msg.sender, + RANDOMNESS_ADDRESS + ); + } + fulfillRandomWords(requestId, randomWords); + } +} diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 99584ad..14097af 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,5 +1,8 @@ -var Flipper = artifacts.require("Flipper"); +var RandomNumber = artifacts.require("./lib/RandomNumber"); +var Flipper = artifacts.require("./Flipper"); module.exports = function (deployer) { + // deployer.deploy(RandomnessConsumer); + deployer.deploy(RandomNumber); deployer.deploy(Flipper, false); }; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index 7fd6089..bcb4615 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -6,6 +6,7 @@ "dotenv": "^16.3.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", "truffle": "^5.10.0", - "truffle-plugin-verify": "^0.6.3" + "truffle-plugin-verify": "^0.6.3", + "web3": "^4.0.1" } } diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 8309ede..22b176c 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -1,24 +1,76 @@ // Uses Mocha and Ganache +const RandomNumber = artifacts.require("RandomNumber"); const Flipper = artifacts.require("Flipper"); +advanceBlock = () => { + return new Promise((resolve, reject) => { + web3.currentProvider.send({ + jsonrpc: '2.0', + method: 'evm_mine', + id: new Date().getTime() + }, (err, result) => { + if (err) { return reject(err) } + const newBlockHash = web3.eth.getBlock('latest').hash; + + return resolve(newBlockHash); + }) + }) +} + contract('Flipper', accounts => { - let flipper; + let randomNumberInstance; + let flipperInstance; + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 + const requiredDeposit = "1000000000000000000"; // Wei (1 Ether) const initValue = false; beforeEach(async () => { + // Create contract with 1 Ether (contract must be payable) + randomNumberInstance = await RandomNumber.new({ from: accounts[0], value: requiredDeposit }); // Deploy token contract - flipper = await Flipper.new(initValue, { from: accounts[0] }); + flipperInstance = await Flipper.new(initValue, { from: accounts[0] }); }); // Check stored value it("checks stored value", async () => { - const value = await flipper.get.call(); + const value = await flipperInstance.get.call(); assert.equal(value, initValue, 'value stored does not match initial value'); }); // Set flipped value of existing value it("should flip the value", async () => { - const previousValue = await flipper.get.call(); - await flipper.flip.call({ from: accounts[0] }); - const newValue = await flipper.flip.call(); + const previousValue = await flipperInstance.get.call(); + await flipperInstance.flip.call({ from: accounts[0] }); + const newValue = await flipperInstance.flip.call(); assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); - }) + }); + + it("requests randomness", async () => { + const fulfillmentFee = await flipperInstance.MIN_FEE.call(); + const refundAddress = await randomNumberInstance.requestRandomness.call( + { from: accounts[0] }, + { value: fulfillmentFee }, + ); + const requestId = await randomNumberInstance.requestId.call(); + + // Check status of request id from the randomness precompile + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); + + // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); + for (i=0; i=0.8.3 Compiler compilers: { solc: { - version: '^0.8.20', + version: '>=0.8.3', settings: { // Fixes `"Migrations" -- evm error: InvalidCode(Opcode(95))` // https://docs.moonbeam.network/tutorials/eth-api/truffle-start-to-end/ diff --git a/docker/quickstart-randomness.sh b/docker/quickstart-randomness.sh new file mode 100755 index 0000000..67429ff --- /dev/null +++ b/docker/quickstart-randomness.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +echo "Compiling contracts..." +cd $PARENT_DIR/dapps/evm2/flipper +PROJECT_ROOT=$PARENT_DIR/dapps/evm2/flipper +truffle compile --compile-all + +echo "Migrating contracts..." +truffle migrate --reset --compile-all --network moonbase From fd5624c49379463a9001dd89f9b694f7a2735f4f Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 24 Jun 2023 09:24:22 +1000 Subject: [PATCH 27/58] incorporate feedback from moonbuilders --- .../flipper/contracts/lib/RandomNumber.sol | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 45699c0..a86aed1 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.8.3; +// compiling with truffle automatically generates the respective ABI files for these precompiles // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol // import "../precompiles/randomness/Randomness.sol"; import {Randomness, MIN_VRF_BLOCKS_DELAY} from "../precompiles/randomness/Randomness.sol"; @@ -9,11 +10,13 @@ import {RandomnessConsumer} from "../precompiles/randomness/RandomnessConsumer.s contract RandomNumber is RandomnessConsumer { // The Randomness Precompile Interface - Randomness public randomness = - Randomness(0x0000000000000000000000000000000000000809); + + // create a wrapper to access the randomness precompile + Randomness public theRandomness; + address public constant randomnessPrecompileAddress = 0x0000000000000000000000000000000000000809; // Variables required for randomness requests - uint256 public requiredDeposit = randomness.requiredDeposit(); + uint256 public requiredDeposit = theRandomness.requiredDeposit(); uint64 public FULFILLMENT_GAS_LIMIT = 100000; // The fee can be set to any value as long as it is enough to cover // the fulfillment costs. Any leftover fees will be refunded to the @@ -30,13 +33,14 @@ contract RandomNumber is RandomnessConsumer { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. require(msg.value >= requiredDeposit); + theRandomness = Randomness(randomnessPrecompileAddress); } function requestRandomness() public payable { // Make sure that the value sent is enough require(msg.value >= MIN_FEE); // Request local VRF randomness - requestId = randomness.requestLocalVRFRandomWords( + requestId = theRandomness.requestLocalVRFRandomWords( msg.sender, // Refund address msg.value, // Fulfillment fee FULFILLMENT_GAS_LIMIT, // Gas limit for the fulfillment @@ -46,8 +50,13 @@ contract RandomNumber is RandomnessConsumer { ); } + function getRequestStatus() public view returns(Randomness.RequestStatus) { + Randomness.RequestStatus requestStatus = theRandomness.getRequestStatus(requestId); + return requestStatus; + } + function fulfillRequest() public { - randomness.fulfillRequest(requestId); + theRandomness.fulfillRequest(requestId); } function fulfillRandomWords( From d68f6d5b6ba0d5089c83c0e888340f9d2d14a945 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 24 Jun 2023 10:02:25 +1000 Subject: [PATCH 28/58] fix so only use randomness after instantiated Randomness --- .../flipper/contracts/lib/RandomNumber.sol | 11 ++- dapps/evm2/flipper/tx.log | 87 +++++++++++++++++++ 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index a86aed1..2d5dd6d 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -16,13 +16,13 @@ contract RandomNumber is RandomnessConsumer { address public constant randomnessPrecompileAddress = 0x0000000000000000000000000000000000000809; // Variables required for randomness requests - uint256 public requiredDeposit = theRandomness.requiredDeposit(); + uint256 public requiredDeposit; uint64 public FULFILLMENT_GAS_LIMIT = 100000; // The fee can be set to any value as long as it is enough to cover // the fulfillment costs. Any leftover fees will be refunded to the // refund address specified in the requestRandomness function below uint256 public MIN_FEE = FULFILLMENT_GAS_LIMIT * 5 gwei; - uint32 public VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; + uint32 public VRF_BLOCKS_DELAY; bytes32 public SALT_PREFIX = "change-me-to-anything"; // Storage variables for the current request @@ -30,10 +30,13 @@ contract RandomNumber is RandomnessConsumer { uint256[] public random; constructor() payable RandomnessConsumer() { + // Initialize use of Randomness dependency before trying to access it + theRandomness = Randomness(randomnessPrecompileAddress); + requiredDeposit = theRandomness.requiredDeposit(); // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. - require(msg.value >= requiredDeposit); - theRandomness = Randomness(randomnessPrecompileAddress); + // require(msg.value >= requiredDeposit); + VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } function requestRandomness() public payable { diff --git a/dapps/evm2/flipper/tx.log b/dapps/evm2/flipper/tx.log index ada048e..8ba97fc 100644 --- a/dapps/evm2/flipper/tx.log +++ b/dapps/evm2/flipper/tx.log @@ -66,3 +66,90 @@ Summary ======= > Total deployments: 2 > Final cost: 0.00083145825 ETH + +# truffle migrate --reset --compile-all --network moonbase + +Compiling your contracts... +=========================== +✓ Fetching solc version list from solc-bin. Attempt #1 +> Compiling ./contracts/Flipper.sol +> Compiling ./contracts/Migrations.sol +> Compiling ./contracts/lib/RandomNumber.sol +> Compiling ./contracts/precompiles/randomness/Randomness.sol +> Compiling ./contracts/precompiles/randomness/RandomnessConsumer.sol +> Artifacts written to /app/dapps/evm2/flipper/build/contracts +> Compiled successfully using: + - solc: 0.8.20+commit.a1b79de6.Emscripten.clang + + +Starting migrations... +====================== +> Network name: 'moonbase' +> Network id: 1287 +> Block gas limit: 15000000 (0xe4e1c0) + + +1_initial_migration.js +====================== + + Replacing 'Migrations' + ---------------------- + > transaction hash: 0x3d1e501f5a9ab4f7d2ceb15bec3557c13eced685cea926c1ddf0ee5bf7904fc8 + > Blocks: 1 Seconds: 20 + > contract address: 0xceD293233Fc7e338017Fbb52F1cc997E9cfD3556 + > block number: 4600259 + > block timestamp: 1687564692 + > account: 0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7 + > balance: 2.196479615972105182 + > gas used: 202971 (0x318db) + > gas price: 2.625 gwei + > value sent: 0 ETH + > total cost: 0.000532798875 ETH + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0.000532798875 ETH + + +2_deploy_contracts.js +===================== + + Deploying 'RandomNumber' + ------------------------ + > transaction hash: 0x86c46f35c890608b5eea11b9a2cbb31f02c8a5cb41a5f7f9b337f780104875d8 + > Blocks: 1 Seconds: 14 + > contract address: 0x7ae29716433406B30FB252790716a7471c1B1bBD + > block number: 4600263 + > block timestamp: 1687564746 + > account: 0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7 + > balance: 2.193912539222105182 + > gas used: 932021 (0xe38b5) + > gas price: 2.625041913 gwei + > value sent: 0 ETH + > total cost: 0.002446594188796173 ETH + + + Replacing 'Flipper' + ------------------- + > transaction hash: 0xc6605dfc04eefefa841502cfc6decf38dacdd9c381a75d4fd5b9e441530e9029 + > Blocks: 2 Seconds: 20 + > contract address: 0x610CE4456D5b7a988F1894397755F19D3918F699 + > block number: 4600265 + > block timestamp: 1687564770 + > account: 0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7 + > balance: 3.293613680347105182 + > gas used: 113851 (0x1bcbb) + > gas price: 2.625 gwei + > value sent: 0 ETH + > total cost: 0.000298858875 ETH + + > Saving migration to chain. + > Saving artifacts + ------------------------------------- + > Total cost: 0.002745453063796173 ETH + +Summary +======= +> Total deployments: 3 +> Final cost: 0.003278251938796173 ETH \ No newline at end of file From 4962720862f0509d652a39b453134ce61ed2f15e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 24 Jun 2023 10:15:22 +1000 Subject: [PATCH 29/58] try use console log --- dapps/evm2/flipper/test/test_Flipper.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 22b176c..8c7a99f 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -9,8 +9,11 @@ advanceBlock = () => { method: 'evm_mine', id: new Date().getTime() }, (err, result) => { + console.log('result: ', result); + console.log('err: ', err); if (err) { return reject(err) } const newBlockHash = web3.eth.getBlock('latest').hash; + console.log('newBlockHash: ', newBlockHash); return resolve(newBlockHash); }) @@ -18,6 +21,7 @@ advanceBlock = () => { } contract('Flipper', accounts => { + console.log('accounts: ', accounts); let randomNumberInstance; let flipperInstance; // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 From 2f663661968b4e848740b15255b1722cb927678b Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sat, 24 Jun 2023 20:13:33 +1000 Subject: [PATCH 30/58] wip errors due to https://github.com/trufflesuite/truffle/issues/3468 no more dev tokens --- dapps/evm2/flipper/README.md | 5 +++- dapps/evm2/flipper/contracts/Flipper.sol | 1 - dapps/evm2/flipper/contracts/Migrations.sol | 2 +- .../flipper/contracts/lib/RandomNumber.sol | 2 +- .../flipper/migrations/2_deploy_contracts.js | 3 -- dapps/evm2/flipper/test/test_Flipper.js | 29 +++++++++++++++---- dapps/evm2/flipper/truffle-config.js | 17 +++++++++++ 7 files changed, 46 insertions(+), 13 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index c9460d2..9b8fbf4 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -105,4 +105,7 @@ shasum -a 256 moonkey * Compile full `truffle compile --compile-all` * Migrate * Migrate full `truffle migrate --reset --compile-all --network moonbase` - +* Test + * `truffle test --verbose-rpc --network moonbase` +* References + * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md \ No newline at end of file diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol index bdf2c4f..63942b2 100644 --- a/dapps/evm2/flipper/contracts/Flipper.sol +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -1,5 +1,4 @@ // SPDX-License-Identifier: MIT - pragma solidity >=0.8.3; import "./lib/RandomNumber.sol"; diff --git a/dapps/evm2/flipper/contracts/Migrations.sol b/dapps/evm2/flipper/contracts/Migrations.sol index d8a066a..d1b7e6a 100644 --- a/dapps/evm2/flipper/contracts/Migrations.sol +++ b/dapps/evm2/flipper/contracts/Migrations.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity >=0.8.3; contract Migrations { address public owner; diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 2d5dd6d..a6a2ea4 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -35,7 +35,7 @@ contract RandomNumber is RandomnessConsumer { requiredDeposit = theRandomness.requiredDeposit(); // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. - // require(msg.value >= requiredDeposit); + require(msg.value >= requiredDeposit); VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 14097af..ade69b6 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,8 +1,5 @@ -var RandomNumber = artifacts.require("./lib/RandomNumber"); var Flipper = artifacts.require("./Flipper"); module.exports = function (deployer) { - // deployer.deploy(RandomnessConsumer); - deployer.deploy(RandomNumber); deployer.deploy(Flipper, false); }; diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 8c7a99f..8743e0f 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -1,6 +1,8 @@ // Uses Mocha and Ganache -const RandomNumber = artifacts.require("RandomNumber"); -const Flipper = artifacts.require("Flipper"); +const Randomness = artifacts.require("../build/contracts/Randomness"); +const RandomnessConsumer = artifacts.require("../build/contracts/RandomnessConsumer"); +const RandomNumber = artifacts.require("../contracts/lib/RandomNumber"); +const Flipper = artifacts.require("../contracts/lib/Flipper"); advanceBlock = () => { return new Promise((resolve, reject) => { @@ -22,20 +24,35 @@ advanceBlock = () => { contract('Flipper', accounts => { console.log('accounts: ', accounts); + let randomnessInstance; let randomNumberInstance; let flipperInstance; // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 const requiredDeposit = "1000000000000000000"; // Wei (1 Ether) + const blockTimeout = 1000000; const initValue = false; - beforeEach(async () => { + beforeEach(async (done) => { + randomnessInstance = await Randomness.at("0x0000000000000000000000000000000000000809"); + console.log('randomnessInstance.address:', randomnessInstance.address); + RandomnessConsumer.link(randomnessInstance); + RandomNumber.link(randomnessInstance); + // Create contract with 1 Ether (contract must be payable) - randomNumberInstance = await RandomNumber.new({ from: accounts[0], value: requiredDeposit }); + randomNumberInstance = await RandomNumber.deployed(); //.new({ from: accounts[0], value: requiredDeposit }); + console.log('randomNumberInstance.address:', randomNumberInstance.address); + Flipper.link(randomnessInstance); + Flipper.link(randomNumberInstance); // Deploy token contract - flipperInstance = await Flipper.new(initValue, { from: accounts[0] }); + + flipperInstance = await Flipper.deployed(); //.new(initValue, { from: accounts[0] }); + console.log('flipperInstance.address:', flipperInstance.address); + // delay each test to simulate throttle that isn't available in truffle + setTimeout(function(){ done(); }, 5000); }); // Check stored value it("checks stored value", async () => { const value = await flipperInstance.get.call(); + console.log('value:', value); assert.equal(value, initValue, 'value stored does not match initial value'); }); @@ -43,7 +60,7 @@ contract('Flipper', accounts => { it("should flip the value", async () => { const previousValue = await flipperInstance.get.call(); await flipperInstance.flip.call({ from: accounts[0] }); - const newValue = await flipperInstance.flip.call(); + const newValue = await flipperInstance.get.call(); assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); }); diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 8b1a5c2..a804327 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -50,6 +50,17 @@ module.exports = { }; return new HDWalletProvider(args); }, + // Try to overcome error + // `Uncaught Error: PollingBlockTracker - encountered an error while attempting to update latest block: + // undefined + // https://ethereum.stackexchange.com/questions/97773/truffle-migrate-rinkeby-error-pollingblocktracker-encountered-an-error-whil + confirmations: 10, + timeoutBlocks: 900000, + skipDryRun: false, + websocket: true, + gas: 5000000, + gasPrice: 40000000000, + networkCheckTimeout: 1000000000, network_id: 1287, }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet @@ -64,6 +75,12 @@ module.exports = { network_id: 81, }, }, + mocha: { + timeout: 100000000, // milliseconds + enableTimeouts: false, + bail: false, + retries: 100, + }, // Solidity >=0.8.3 Compiler compilers: { solc: { From 4df48dad78a3c338580423c03bac3efc66f1bf74 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 25 Jun 2023 18:00:58 +1000 Subject: [PATCH 31/58] stuck on error ProviderError 32603 calling requestRandomness --- dapps/evm2/flipper/.env.example | 3 + dapps/evm2/flipper/README.md | 5 + dapps/evm2/flipper/contracts/Flipper.sol | 2 +- .../flipper/contracts/lib/RandomNumber.sol | 2 +- dapps/evm2/flipper/package.json | 1 + dapps/evm2/flipper/test/test_Flipper.js | 109 ++++++++++++------ dapps/evm2/flipper/truffle-config.js | 21 +++- 7 files changed, 101 insertions(+), 42 deletions(-) diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index 27ef570..8c0a87e 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -1,2 +1,5 @@ # https://faucet.moonbeam.network/ MOONBASE_PRIVATE_KEY='0x' +# https://blastapi.io/ +MOONBASE_BLASTAPI_ENDPOINT='' +MOONBASE_BLASTAPI_NETWORK_ID= diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 9b8fbf4..e7d3af0 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -85,6 +85,11 @@ Then configure Truffle to connect to it Moonbeam Development `node_modules/.bin/ Preferably use Moonbase Alpha TestNet `node_modules/.bin/truffle migrate --network moonbase` that requires testnet tokens from the faucet https://faucet.moonbeam.network/. +Note: When running tests against Moonbase Alpha TestNet. Disconnect VPN. Try to avoid encountering errors like `Too Many Requests`, `ProviderError`, `ETIMEDOUT`, `32603`, it is important to use a dedicated endpoint that you can get for free here https://blastapi.io/ by creating an account, creating a project, choosing Moonbase Alpha Testnet from their available endpoints and clicking "Activate", and then copying either the RPC endpoint. +Note: I got error `TypeError: Cannot create property 'gasLimit' on string '0x464aff'` when tried using Blastapi WSS endpoint instead of RPC (https) endpoint. + +This is important because the public endpoint https://rpc.api.moonbase.moonbeam.network has stricter rate limiting. Ensure that you replace the public Moonbase Alpha endpoint in the truffle-config.js file with the dedicated endpoint. + Run tests ``` truffle test diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol index 63942b2..a915e8d 100644 --- a/dapps/evm2/flipper/contracts/Flipper.sol +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -14,7 +14,7 @@ contract Flipper { /// A message that can be called on instantiated contracts. /// This one flips the value of the stored `bool` from `true` /// to `false` and vice versa. - function flip() public { + function flip() public payable { value = !value; } diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index a6a2ea4..914e974 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -21,7 +21,7 @@ contract RandomNumber is RandomnessConsumer { // The fee can be set to any value as long as it is enough to cover // the fulfillment costs. Any leftover fees will be refunded to the // refund address specified in the requestRandomness function below - uint256 public MIN_FEE = FULFILLMENT_GAS_LIMIT * 5 gwei; + uint256 public MIN_FEE = FULFILLMENT_GAS_LIMIT * 5 gwei; // 0.000000001 Ether == 1 gwei uint32 public VRF_BLOCKS_DELAY; bytes32 public SALT_PREFIX = "change-me-to-anything"; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index bcb4615..2f38b79 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "dependencies": { "@truffle/hdwallet-provider": "^2.1.12", + "bn.js": "^5.2.1", "dotenv": "^16.3.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", "truffle": "^5.10.0", diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 8743e0f..9758264 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -1,9 +1,22 @@ +var Web3 = require('web3'); +const BN = require('bn.js'); +// require('dotenv').config() + // Uses Mocha and Ganache const Randomness = artifacts.require("../build/contracts/Randomness"); const RandomnessConsumer = artifacts.require("../build/contracts/RandomnessConsumer"); const RandomNumber = artifacts.require("../contracts/lib/RandomNumber"); const Flipper = artifacts.require("../contracts/lib/Flipper"); +// let web3 = new Web3(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); +// // when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` +// // https://github.com/web3/web3.js/issues/3573 +// console.log('web3.currentProvider: ', web3.currentProvider); +// Randomness.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); +// RandomnessConsumer.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); +// RandomNumber.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); +// Flipper.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); + advanceBlock = () => { return new Promise((resolve, reject) => { web3.currentProvider.send({ @@ -31,23 +44,24 @@ contract('Flipper', accounts => { const requiredDeposit = "1000000000000000000"; // Wei (1 Ether) const blockTimeout = 1000000; const initValue = false; - beforeEach(async (done) => { + beforeEach(async () => { + console.log('beforeEach'); randomnessInstance = await Randomness.at("0x0000000000000000000000000000000000000809"); - console.log('randomnessInstance.address:', randomnessInstance.address); + // console.log('randomnessInstance.address:', randomnessInstance.address); RandomnessConsumer.link(randomnessInstance); RandomNumber.link(randomnessInstance); // Create contract with 1 Ether (contract must be payable) randomNumberInstance = await RandomNumber.deployed(); //.new({ from: accounts[0], value: requiredDeposit }); - console.log('randomNumberInstance.address:', randomNumberInstance.address); + // console.log('randomNumberInstance.address:', randomNumberInstance.address); Flipper.link(randomnessInstance); Flipper.link(randomNumberInstance); // Deploy token contract flipperInstance = await Flipper.deployed(); //.new(initValue, { from: accounts[0] }); - console.log('flipperInstance.address:', flipperInstance.address); + // console.log('flipperInstance.address:', flipperInstance.address); // delay each test to simulate throttle that isn't available in truffle - setTimeout(function(){ done(); }, 5000); + // setTimeout(function(){ done(); }, 5000); }); // Check stored value it("checks stored value", async () => { @@ -58,40 +72,67 @@ contract('Flipper', accounts => { // Set flipped value of existing value it("should flip the value", async () => { - const previousValue = await flipperInstance.get.call(); - await flipperInstance.flip.call({ from: accounts[0] }); - const newValue = await flipperInstance.get.call(); - assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); + try { + const previousValue = await flipperInstance.get.call(); + const value = "1000000000000000000"; + await flipperInstance.flip.call({ from: accounts[0], value: value }); + setTimeout(function(){ done(); }, 5000); + const newValue = await flipperInstance.get.call(); + assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); + } catch (e) { + console.log('error in flip: ', e); + } }); it("requests randomness", async () => { - const fulfillmentFee = await flipperInstance.MIN_FEE.call(); - const refundAddress = await randomNumberInstance.requestRandomness.call( - { from: accounts[0] }, - { value: fulfillmentFee }, - ); - const requestId = await randomNumberInstance.requestId.call(); + // TEMP ONLY - TRYING TO GET `requestRandomness` TO WORK + try { + const randomnessPrecompileAddress = await randomNumberInstance.randomnessPrecompileAddress.call(); + console.log('randomnessPrecompileAddress: ', randomnessPrecompileAddress); + const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); + console.log('fulfillmentFee: ', fulfillmentFee.toString()); + console.log('is bn', BN.isBN(fulfillmentFee)); + console.log('web3.currentProvider: ', web3.currentProvider); + const refundAddress = await randomNumberInstance.requestRandomness.call( + { from: accounts[0] }, + // same error with large amount + // { value: "1000000000000000000" }, + { value: fulfillmentFee.toString() }, + ); + console.log('refundAddress: ', refundAddress); + const requestId = await randomNumberInstance.requestId.call(); + console.log('requestId: ', requestId); + } catch (e) { + console.log('error in requests randomness: ', e); + } - // Check status of request id from the randomness precompile - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); + // const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); + // const refundAddress = await randomNumberInstance.requestRandomness.call( + // { from: accounts[0] }, + // { value: fulfillmentFee }, + // ); + // const requestId = await randomNumberInstance.requestId.call(); + // console.log('requestId: ', requestId); + // // Check status of request id from the randomness precompile + // // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + // const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); - // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 - const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); - for (i=0; i Date: Mon, 26 Jun 2023 04:44:20 +1000 Subject: [PATCH 32/58] StatusError in tx for requestRandomness --- dapps/evm2/flipper/test/test_Flipper.js | 71 +++++++++++-------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 9758264..fbb9ea0 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -74,8 +74,9 @@ contract('Flipper', accounts => { it("should flip the value", async () => { try { const previousValue = await flipperInstance.get.call(); - const value = "1000000000000000000"; - await flipperInstance.flip.call({ from: accounts[0], value: value }); + const value = new BN("1", 10); + // do not use `.call` when doing state changes to blockchain + await flipperInstance.flip({ from: accounts[0], value: value }); setTimeout(function(){ done(); }, 5000); const newValue = await flipperInstance.get.call(); assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); @@ -87,52 +88,42 @@ contract('Flipper', accounts => { it("requests randomness", async () => { // TEMP ONLY - TRYING TO GET `requestRandomness` TO WORK try { - const randomnessPrecompileAddress = await randomNumberInstance.randomnessPrecompileAddress.call(); - console.log('randomnessPrecompileAddress: ', randomnessPrecompileAddress); const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); console.log('fulfillmentFee: ', fulfillmentFee.toString()); - console.log('is bn', BN.isBN(fulfillmentFee)); - console.log('web3.currentProvider: ', web3.currentProvider); - const refundAddress = await randomNumberInstance.requestRandomness.call( - { from: accounts[0] }, - // same error with large amount - // { value: "1000000000000000000" }, - { value: fulfillmentFee.toString() }, + console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); + // console.log('web3.currentProvider: ', web3.currentProvider); + // do not use `.call` when doing state changes to blockchain + const refundAddress = await randomNumberInstance.requestRandomness( + { from: accounts[0], value: fulfillmentFee }, ); console.log('refundAddress: ', refundAddress); const requestId = await randomNumberInstance.requestId.call(); console.log('requestId: ', requestId); - } catch (e) { - console.log('error in requests randomness: ', e); - } + // Check status of request id from the randomness precompile + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); + console.log('requestStatus: ', requestStatus); - // const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); - // const refundAddress = await randomNumberInstance.requestRandomness.call( - // { from: accounts[0] }, - // { value: fulfillmentFee }, - // ); - // const requestId = await randomNumberInstance.requestId.call(); - // console.log('requestId: ', requestId); - // // Check status of request id from the randomness precompile - // // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - // const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); + // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); + let currentBlock = await web3.eth.getBlock("latest"); + console.log('currentBlock: ', currentBlock); + for (i=0; i Date: Mon, 26 Jun 2023 17:22:13 +1000 Subject: [PATCH 33/58] try change to Websocket endpoint but error Web3WSProviderError: Request Id not defined --- dapps/evm2/flipper/README.md | 5 +- dapps/evm2/flipper/contracts/Flipper.sol | 5 + .../flipper/migrations/2_deploy_contracts.js | 15 +- dapps/evm2/flipper/test/test_Flipper.js | 130 +++++++++++------- package-lock.json | 17 +++ package.json | 5 + 6 files changed, 129 insertions(+), 48 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index e7d3af0..0a60c60 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -86,7 +86,7 @@ Then configure Truffle to connect to it Moonbeam Development `node_modules/.bin/ Preferably use Moonbase Alpha TestNet `node_modules/.bin/truffle migrate --network moonbase` that requires testnet tokens from the faucet https://faucet.moonbeam.network/. Note: When running tests against Moonbase Alpha TestNet. Disconnect VPN. Try to avoid encountering errors like `Too Many Requests`, `ProviderError`, `ETIMEDOUT`, `32603`, it is important to use a dedicated endpoint that you can get for free here https://blastapi.io/ by creating an account, creating a project, choosing Moonbase Alpha Testnet from their available endpoints and clicking "Activate", and then copying either the RPC endpoint. -Note: I got error `TypeError: Cannot create property 'gasLimit' on string '0x464aff'` when tried using Blastapi WSS endpoint instead of RPC (https) endpoint. +Note: I got error `TypeError: Cannot create property 'gasLimit' on string '0x464aff'` when tried using Blastapi WSS endpoint instead of RPC (https) endpoint. Note: If you change to WSS then you need to use `WebsocketProvider` instead of `HttpProvider` This is important because the public endpoint https://rpc.api.moonbase.moonbeam.network has stricter rate limiting. Ensure that you replace the public Moonbase Alpha endpoint in the truffle-config.js file with the dedicated endpoint. @@ -112,5 +112,8 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Test * `truffle test --verbose-rpc --network moonbase` +* Troubleshooting + * `Client network socket disconnected before secure TLS connection was established` + * Fix by running `unset https_proxy && unset http_proxy` * References * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md \ No newline at end of file diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol index a915e8d..8e278df 100644 --- a/dapps/evm2/flipper/contracts/Flipper.sol +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -5,12 +5,17 @@ import "./lib/RandomNumber.sol"; contract Flipper { bool private value; + address public randomNumberContractAddress; /// Constructor that initializes the `bool` value to the given `init_value`. constructor(bool initvalue) { value = initvalue; } + function setRandomNumberContractAddress(address _randomNumberAddress) public { + randomNumberContractAddress = _randomNumberAddress; + } + /// A message that can be called on instantiated contracts. /// This one flips the value of the stored `bool` from `true` /// to `false` and vice versa. diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index ade69b6..19e3f04 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,5 +1,18 @@ -var Flipper = artifacts.require("./Flipper"); +require('dotenv').config() +const { Web3 } = require('web3'); + +var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); +var Flipper = artifacts.require("../build/contracts/Flipper"); + +console.log('deploy_contracts'); +let wsProvider = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); +console.log('wsProvider: ', wsProvider); +let web3 = new Web3(wsProvider); +console.log('web3.currentProvider: ', web3.currentProvider); +RandomNumber.setProvider(wsProvider); +Flipper.setProvider(wsProvider); module.exports = function (deployer) { + deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); deployer.deploy(Flipper, false); }; diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index fbb9ea0..c68e2d0 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -1,6 +1,6 @@ -var Web3 = require('web3'); +require('dotenv').config() +const { Web3 } = require('web3'); const BN = require('bn.js'); -// require('dotenv').config() // Uses Mocha and Ganache const Randomness = artifacts.require("../build/contracts/Randomness"); @@ -8,14 +8,17 @@ const RandomnessConsumer = artifacts.require("../build/contracts/RandomnessConsu const RandomNumber = artifacts.require("../contracts/lib/RandomNumber"); const Flipper = artifacts.require("../contracts/lib/Flipper"); -// let web3 = new Web3(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); -// // when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` -// // https://github.com/web3/web3.js/issues/3573 -// console.log('web3.currentProvider: ', web3.currentProvider); -// Randomness.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); -// RandomnessConsumer.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); -// RandomNumber.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); -// Flipper.setProvider(new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT)); +console.log('test_Flipper'); + +let wsProvider = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); +let web3 = new Web3(); +// when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` +// https://github.com/web3/web3.js/issues/3573 +console.log('web3.currentProvider: ', web3.currentProvider); +// Randomness.setProvider(wsProvider); +// RandomnessConsumer.setProvider(wsProvider); +RandomNumber.setProvider(wsProvider); +Flipper.setProvider(wsProvider); advanceBlock = () => { return new Promise((resolve, reject) => { @@ -40,28 +43,49 @@ contract('Flipper', accounts => { let randomnessInstance; let randomNumberInstance; let flipperInstance; + let fulfillmentFee; + let refundAddress; + let gas; + let gasLimit; + let gasPrice; // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 - const requiredDeposit = "1000000000000000000"; // Wei (1 Ether) + // https://docs.web3js.org/api/web3-utils/function/toWei + const requiredDeposit = Web3.utils.toWei('1', 'ether'); const blockTimeout = 1000000; const initValue = false; beforeEach(async () => { console.log('beforeEach'); randomnessInstance = await Randomness.at("0x0000000000000000000000000000000000000809"); // console.log('randomnessInstance.address:', randomnessInstance.address); - RandomnessConsumer.link(randomnessInstance); - RandomNumber.link(randomnessInstance); + // RandomnessConsumer.link(randomnessInstance); + // RandomNumber.link(randomnessInstance); + + // gas = Web3.utils.toWei('1000000', 'wei'); + // gasLimit = Web3.utils.toWei('600000', 'wei'); + // gasPrice = Web3.utils.toWei('2000000', 'wei'); + // gas = Web3.utils.toHex(70000); + // gasLimit = Web3.utils.toHex(600000); // gwei + // gasPrice = Web3.utils.toHex(21000); + // Create contract with 1 Ether (contract must be payable) randomNumberInstance = await RandomNumber.deployed(); //.new({ from: accounts[0], value: requiredDeposit }); - // console.log('randomNumberInstance.address:', randomNumberInstance.address); - Flipper.link(randomnessInstance); - Flipper.link(randomNumberInstance); + // randomNumberInstance = await RandomNumber.new( + // { from: accounts[0], value: requiredDeposit, + // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, syncWithContext: true } + // ); + console.log('randomNumberInstance.address:', randomNumberInstance.address); + + // Flipper.link(randomnessInstance); + // Flipper.link(randomNumberInstance); + // Deploy token contract flipperInstance = await Flipper.deployed(); //.new(initValue, { from: accounts[0] }); // console.log('flipperInstance.address:', flipperInstance.address); // delay each test to simulate throttle that isn't available in truffle // setTimeout(function(){ done(); }, 5000); + await flipperInstance.setRandomNumberContractAddress(randomNumberInstance.address); }); // Check stored value it("checks stored value", async () => { @@ -74,10 +98,11 @@ contract('Flipper', accounts => { it("should flip the value", async () => { try { const previousValue = await flipperInstance.get.call(); - const value = new BN("1", 10); + const oneWei = Web3.utils.toWei('1', 'wei'); + const value = new BN(oneWei, 10); // 1 wei (so do not use up all my testnet DEV tokens) // do not use `.call` when doing state changes to blockchain await flipperInstance.flip({ from: accounts[0], value: value }); - setTimeout(function(){ done(); }, 5000); + // setTimeout(function(){ done(); }, 5000); const newValue = await flipperInstance.get.call(); assert.notEqual(previousValue, newValue, 'newValue is not opposite of previousValue'); } catch (e) { @@ -88,40 +113,53 @@ contract('Flipper', accounts => { it("requests randomness", async () => { // TEMP ONLY - TRYING TO GET `requestRandomness` TO WORK try { - const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); + fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); console.log('fulfillmentFee: ', fulfillmentFee.toString()); console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); + console.log('accounts', accounts); + // console.log('web3.currentProvider: ', web3.currentProvider); // do not use `.call` when doing state changes to blockchain - const refundAddress = await randomNumberInstance.requestRandomness( - { from: accounts[0], value: fulfillmentFee }, + // gas = Web3.utils.toWei('1000000', 'wei'); + // gasLimit = Web3.utils.toWei('600000', 'wei'); + // gasPrice = Web3.utils.toWei('2000000', 'wei'); + gas = Web3.utils.toHex(150000); + gasLimit = Web3.utils.toHex(600000); + gasPrice = Web3.utils.toHex(21000); + refundAddress = await randomNumberInstance.requestRandomness( + { + from: accounts[0], + value: fulfillmentFee, + gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, + syncWithContext: true + } ); console.log('refundAddress: ', refundAddress); - const requestId = await randomNumberInstance.requestId.call(); - console.log('requestId: ', requestId); - // Check status of request id from the randomness precompile - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); - console.log('requestStatus: ', requestStatus); - - // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 - const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); - let currentBlock = await web3.eth.getBlock("latest"); - console.log('currentBlock: ', currentBlock); - for (i=0; i Date: Mon, 26 Jun 2023 19:07:50 +1000 Subject: [PATCH 34/58] MethodNotImplementedError: The method you're trying to call is not implemented --- dapps/evm2/flipper/.env.example | 2 +- dapps/evm2/flipper/README.md | 4 +++- dapps/evm2/flipper/contracts/Flipper.sol | 8 ++++---- dapps/evm2/flipper/migrations/2_deploy_contracts.js | 12 ++++++------ dapps/evm2/flipper/test/test_Flipper.js | 12 ++++++------ dapps/evm2/flipper/truffle-config.js | 5 ++++- 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index 8c0a87e..fe04628 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -1,5 +1,5 @@ # https://faucet.moonbeam.network/ MOONBASE_PRIVATE_KEY='0x' +MOONSCAN_API_KEY='' # https://blastapi.io/ MOONBASE_BLASTAPI_ENDPOINT='' -MOONBASE_BLASTAPI_NETWORK_ID= diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 0a60c60..d3b0ae4 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -116,4 +116,6 @@ shasum -a 256 moonkey * `Client network socket disconnected before secure TLS connection was established` * Fix by running `unset https_proxy && unset http_proxy` * References - * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md \ No newline at end of file + * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md + * https://docs.web3js.org/ + * https://evmdocs.acala.network/tutorials/hardhat-tutorials/precompiledtoken-tutorial diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/flipper/contracts/Flipper.sol index 8e278df..bf04d0c 100644 --- a/dapps/evm2/flipper/contracts/Flipper.sol +++ b/dapps/evm2/flipper/contracts/Flipper.sol @@ -5,16 +5,16 @@ import "./lib/RandomNumber.sol"; contract Flipper { bool private value; - address public randomNumberContractAddress; + // address public randomNumberContractAddress; /// Constructor that initializes the `bool` value to the given `init_value`. constructor(bool initvalue) { value = initvalue; } - function setRandomNumberContractAddress(address _randomNumberAddress) public { - randomNumberContractAddress = _randomNumberAddress; - } + // function setRandomNumberContractAddress(address _randomNumberAddress) public { + // randomNumberContractAddress = _randomNumberAddress; + // } /// A message that can be called on instantiated contracts. /// This one flips the value of the stored `bool` from `true` diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 19e3f04..0daeb63 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -5,13 +5,13 @@ var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); var Flipper = artifacts.require("../build/contracts/Flipper"); console.log('deploy_contracts'); -let wsProvider = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); -console.log('wsProvider: ', wsProvider); -let web3 = new Web3(wsProvider); +let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); +console.log('providerInstance: ', providerInstance); +let web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); -RandomNumber.setProvider(wsProvider); -Flipper.setProvider(wsProvider); - +RandomNumber.setProvider(providerInstance); +Flipper.setProvider(providerInstance); +console.log('deploying...'); module.exports = function (deployer) { deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); deployer.deploy(Flipper, false); diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index c68e2d0..d1595c9 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -10,15 +10,15 @@ const Flipper = artifacts.require("../contracts/lib/Flipper"); console.log('test_Flipper'); -let wsProvider = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); +let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); let web3 = new Web3(); // when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` // https://github.com/web3/web3.js/issues/3573 console.log('web3.currentProvider: ', web3.currentProvider); -// Randomness.setProvider(wsProvider); -// RandomnessConsumer.setProvider(wsProvider); -RandomNumber.setProvider(wsProvider); -Flipper.setProvider(wsProvider); +// Randomness.setProvider(providerInstance); +// RandomnessConsumer.setProvider(providerInstance); +RandomNumber.setProvider(providerInstance); +Flipper.setProvider(providerInstance); advanceBlock = () => { return new Promise((resolve, reject) => { @@ -85,7 +85,7 @@ contract('Flipper', accounts => { // console.log('flipperInstance.address:', flipperInstance.address); // delay each test to simulate throttle that isn't available in truffle // setTimeout(function(){ done(); }, 5000); - await flipperInstance.setRandomNumberContractAddress(randomNumberInstance.address); + // await flipperInstance.setRandomNumberContractAddress(randomNumberInstance.address); }); // Check stored value it("checks stored value", async () => { diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 94aca67..104d54a 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -70,7 +70,6 @@ module.exports = { networkCheckTimeout: 1000000000, deploymentPollingInterval: 8000, network_id: defaultMoonbaseNetworkId, - // network_id: process.env.MOONBASE_BLASTAPI_NETWORK_ID, }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet astar_shibuya: { @@ -104,4 +103,8 @@ module.exports = { }, // Moonbeam Truffle Plugin & Truffle Plugin for Verifying Smart Contracts plugins: ['moonbeam-truffle-plugin', 'truffle-plugin-verify'], + // https://docs.moonbeam.network/builders/build/eth-api/verify-contracts/etherscan-plugins/#using-the-truffle-verify-plugin + api_keys: { + moonscan: process.env.MOONSCAN_API_KEY + } }; From 49f7632a8420e39d86ee94d2fa9a92bab1991fc4 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 27 Jun 2023 01:32:04 +1000 Subject: [PATCH 35/58] timeouts --- .../flipper/migrations/2_deploy_contracts.js | 27 +++++++++++++------ dapps/evm2/flipper/package.json | 1 + dapps/evm2/flipper/test/test_Flipper.js | 3 ++- dapps/evm2/flipper/truffle-config.js | 14 +++++----- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 0daeb63..4b508a5 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,18 +1,29 @@ require('dotenv').config() const { Web3 } = require('web3'); +const contract = require("@truffle/contract"); var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); var Flipper = artifacts.require("../build/contracts/Flipper"); -console.log('deploy_contracts'); -let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); -console.log('providerInstance: ', providerInstance); -let web3 = new Web3(providerInstance); -console.log('web3.currentProvider: ', web3.currentProvider); -RandomNumber.setProvider(providerInstance); -Flipper.setProvider(providerInstance); console.log('deploying...'); -module.exports = function (deployer) { +module.exports = async function (deployer) { + + console.log('deploy_contracts'); + let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); + console.log('providerInstance: ', providerInstance); + let web3 = new Web3(providerInstance); + console.log('web3.currentProvider: ', web3.currentProvider); + // let networkId = await web3.eth.net.getId(); + // console.log('networkId: ', networkId); + // RandomNumber.setNetwork(networkId); + // RandomNumber.setProvider(providerInstance); + // Flipper.setNetwork(networkId); + // Flipper.setProvider(providerInstance); + // console.log('web3.eth', web3.eth); + // const accounts = await web3.eth.getAccounts(); + // console.log('accounts: ', accounts); + // deployer.deploy(RandomNumber, { from: accounts[0], value: Web3.utils.toWei('1', 'ether') }); deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); + // deployer.link(RandomNumber, Flipper); deployer.deploy(Flipper, false); }; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index 2f38b79..39e977e 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -2,6 +2,7 @@ "name": "flipper", "version": "1.0.0", "dependencies": { + "@truffle/contract": "^4.6.25", "@truffle/hdwallet-provider": "^2.1.12", "bn.js": "^5.2.1", "dotenv": "^16.3.1", diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index d1595c9..be4bf1f 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -11,7 +11,8 @@ const Flipper = artifacts.require("../contracts/lib/Flipper"); console.log('test_Flipper'); let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); -let web3 = new Web3(); +console.log('providerInstance: ', providerInstance); +let web3 = new Web3(providerInstance); // when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` // https://github.com/web3/web3.js/issues/3573 console.log('web3.currentProvider: ', web3.currentProvider); diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 104d54a..7f940fe 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -51,7 +51,7 @@ module.exports = { privateKeys: [privateKeyMoonbase], // providerOrUrl: defaultMoonbaseEndpoint, providerOrUrl: process.env.MOONBASE_BLASTAPI_ENDPOINT, - pollingInterval: 20000, // default only 4000, modifying doesn't help + // pollingInterval: 20000, // default only 4000, modifying doesn't help retryTimeout: 10000, // default 400, modifying doesn't help }; return new HDWalletProvider(args); @@ -61,14 +61,14 @@ module.exports = { // `Uncaught Error: PollingBlockTracker - encountered an error while attempting to update latest block: // undefined // https://ethereum.stackexchange.com/questions/97773/truffle-migrate-rinkeby-error-pollingblocktracker-encountered-an-error-whil - confirmations: 10, + // confirmations: 10, timeoutBlocks: 900000, - skipDryRun: true, - websocket: true, - gas: 5000000, - gasPrice: 50000000000, // 50 Gwei + // skipDryRun: true, + // websocket: true, + // gas: 5000000, + // gasPrice: 50000000000, // 50 Gwei networkCheckTimeout: 1000000000, - deploymentPollingInterval: 8000, + // deploymentPollingInterval: 8000, network_id: defaultMoonbaseNetworkId, }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet From 2efa2e608ab3740ec8f413c4120c39396efb3f3f Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 27 Jun 2023 09:32:23 +1000 Subject: [PATCH 36/58] works up to getting requestId but still often get error PollingBlockTracker --- dapps/evm2/flipper/README.md | 3 +- dapps/evm2/flipper/test/test_Flipper.js | 51 +++++++++++++------------ 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index d3b0ae4..68ce5a1 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -114,7 +114,8 @@ shasum -a 256 moonkey * `truffle test --verbose-rpc --network moonbase` * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` - * Fix by running `unset https_proxy && unset http_proxy` + * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me + * If you get error `PollingBlockTracker` then try connecting to a different ISP and disable VPN and stop using a proxy and restart access to your internet * References * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md * https://docs.web3js.org/ diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index be4bf1f..413c76b 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -18,8 +18,8 @@ let web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); // Randomness.setProvider(providerInstance); // RandomnessConsumer.setProvider(providerInstance); -RandomNumber.setProvider(providerInstance); -Flipper.setProvider(providerInstance); +// RandomNumber.setProvider(providerInstance); +// Flipper.setProvider(providerInstance); advanceBlock = () => { return new Promise((resolve, reject) => { @@ -127,28 +127,31 @@ contract('Flipper', accounts => { gas = Web3.utils.toHex(150000); gasLimit = Web3.utils.toHex(600000); gasPrice = Web3.utils.toHex(21000); - refundAddress = await randomNumberInstance.requestRandomness( - { - from: accounts[0], - value: fulfillmentFee, - gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, - syncWithContext: true - } - ); - console.log('refundAddress: ', refundAddress); - // const requestId = await randomNumberInstance.requestId.call(); - // console.log('requestId: ', requestId); - // // Check status of request id from the randomness precompile - // // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - // const requestStatus = await randomNumberInstance.getRequestStatus.call(requestId); - // console.log('requestStatus: ', requestStatus); - - // // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY - // // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 - // // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 - // const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); - // let currentBlock = await web3.eth.getBlock("latest"); - // console.log('currentBlock: ', currentBlock); + refundAddress = await randomNumberInstance.requestRandomness({ from: accounts[0], value: fulfillmentFee }); + // refundAddress = await randomNumberInstance.requestRandomness( + // { + // from: accounts[0], + // value: fulfillmentFee, + // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, + // syncWithContext: true + // } + // ); + // console.log('refundAddress: ', refundAddress); + + const requestId = await randomNumberInstance.requestId.call(); + console.log('requestId: ', requestId); + // Check status of request id from the randomness precompile + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + const requestStatus = await randomNumberInstance.getRequestStatus.call(); + console.log('requestStatus: ', requestStatus); + + // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); + console.log('MIN_VRF_BLOCKS_DELAY: ', MIN_VRF_BLOCKS_DELAY); + let currentBlock = await web3.eth.getBlock("latest"); + console.log('currentBlock: ', currentBlock); // for (i=0; i Date: Tue, 27 Jun 2023 14:56:32 +1000 Subject: [PATCH 37/58] tests working enough to generate random number --- dapps/evm2/flipper/README.md | 6 +- .../flipper/migrations/2_deploy_contracts.js | 2 +- dapps/evm2/flipper/test/test_Flipper.js | 77 +++++++++++++------ dapps/evm2/flipper/truffle-config.js | 9 ++- 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 68ce5a1..77bd0ff 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -86,7 +86,7 @@ Then configure Truffle to connect to it Moonbeam Development `node_modules/.bin/ Preferably use Moonbase Alpha TestNet `node_modules/.bin/truffle migrate --network moonbase` that requires testnet tokens from the faucet https://faucet.moonbeam.network/. Note: When running tests against Moonbase Alpha TestNet. Disconnect VPN. Try to avoid encountering errors like `Too Many Requests`, `ProviderError`, `ETIMEDOUT`, `32603`, it is important to use a dedicated endpoint that you can get for free here https://blastapi.io/ by creating an account, creating a project, choosing Moonbase Alpha Testnet from their available endpoints and clicking "Activate", and then copying either the RPC endpoint. -Note: I got error `TypeError: Cannot create property 'gasLimit' on string '0x464aff'` when tried using Blastapi WSS endpoint instead of RPC (https) endpoint. Note: If you change to WSS then you need to use `WebsocketProvider` instead of `HttpProvider` +Note: I got error `TypeError: Cannot create property 'gasLimit' on string '0x464aff'` when tried using Blastapi WSS endpoint instead of RPC (https) endpoint. Note: If you change to WSS then you need to use `WebsocketProvider` instead of `HttpProvider`. Solved this error by using `gasLimit` in truffle-config.js (it was not necessary for HTTPS) This is important because the public endpoint https://rpc.api.moonbase.moonbeam.network has stricter rate limiting. Ensure that you replace the public Moonbase Alpha endpoint in the truffle-config.js file with the dedicated endpoint. @@ -116,7 +116,11 @@ shasum -a 256 moonkey * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me * If you get error `PollingBlockTracker` then try connecting to a different ISP and disable VPN and stop using a proxy and restart access to your internet + * Sometimes when you run `truffle test --network moonbase` after changing some CLI options it outputs `Error: The network id specified in the truffle config (1287) does not match the one returned by the network (4619453). Ensure that both the network and the provider are properly configured`, even though the network id in the truffle-config.js is in fact 1287, but when you run it again it might works. So just keep running the command again until it + works or change internet connection. * References * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md * https://docs.web3js.org/ * https://evmdocs.acala.network/tutorials/hardhat-tutorials/precompiledtoken-tutorial + * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial + * Chainlink Faucet https://faucets.chain.link/ diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 4b508a5..ca64741 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -9,7 +9,7 @@ console.log('deploying...'); module.exports = async function (deployer) { console.log('deploy_contracts'); - let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); + let providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); console.log('providerInstance: ', providerInstance); let web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 413c76b..da8405e 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -10,7 +10,7 @@ const Flipper = artifacts.require("../contracts/lib/Flipper"); console.log('test_Flipper'); -let providerInstance = new Web3.providers.HttpProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 10 }); +let providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); console.log('providerInstance: ', providerInstance); let web3 = new Web3(providerInstance); // when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` @@ -21,23 +21,23 @@ console.log('web3.currentProvider: ', web3.currentProvider); // RandomNumber.setProvider(providerInstance); // Flipper.setProvider(providerInstance); -advanceBlock = () => { - return new Promise((resolve, reject) => { - web3.currentProvider.send({ - jsonrpc: '2.0', - method: 'evm_mine', - id: new Date().getTime() - }, (err, result) => { - console.log('result: ', result); - console.log('err: ', err); - if (err) { return reject(err) } - const newBlockHash = web3.eth.getBlock('latest').hash; - console.log('newBlockHash: ', newBlockHash); - - return resolve(newBlockHash); - }) - }) -} +// advanceBlock = () => { +// return new Promise((resolve, reject) => { +// web3.currentProvider.send({ +// jsonrpc: '2.0', +// method: 'evm_mine', +// id: new Date().getTime() +// }, (err, result) => { +// console.log('result: ', result); +// console.log('err: ', err); +// if (err) { return reject(err) } +// const newBlockHash = web3.eth.getBlock('latest').hash; +// console.log('newBlockHash: ', newBlockHash); + +// return resolve(newBlockHash); +// }) +// }) +// } contract('Flipper', accounts => { console.log('accounts: ', accounts); @@ -49,6 +49,8 @@ contract('Flipper', accounts => { let gas; let gasLimit; let gasPrice; + let currentBlockNumber; + let nextBlockNumber; // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 // https://docs.web3js.org/api/web3-utils/function/toWei const requiredDeposit = Web3.utils.toWei('1', 'ether'); @@ -143,22 +145,47 @@ contract('Flipper', accounts => { // Check status of request id from the randomness precompile // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 const requestStatus = await randomNumberInstance.getRequestStatus.call(); - console.log('requestStatus: ', requestStatus); + console.log('requestStatus: ', requestStatus.toString()); // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 - const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.MIN_VRF_BLOCKS_DELAY.call(); + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.VRF_BLOCKS_DELAY.call(); console.log('MIN_VRF_BLOCKS_DELAY: ', MIN_VRF_BLOCKS_DELAY); - let currentBlock = await web3.eth.getBlock("latest"); - console.log('currentBlock: ', currentBlock); + // let currentBlock = await web3.eth.getBlock("latest"); + currentBlockNumber = await web3.eth.getBlockNumber(); + console.log('currentBlockNumber: ', currentBlockNumber.toString()); + // remove 'n' character from end of blocknumber + currentBlockNumber = currentBlockNumber.toString().replace(/[^0-9.]/g, ''); + let firstBlockNumber = currentBlockNumber; + console.log('firstBlockNumber: ', firstBlockNumber); + assert.equal(requestStatus, 1, 'should still be pending'); // where 1 in enum is 'PENDING' + // evm_mine not defined, since can only do on Ganache not live testnet // for (i=0; i Date: Tue, 27 Jun 2023 16:38:13 +1000 Subject: [PATCH 38/58] update readme --- dapps/evm2/flipper/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 77bd0ff..f4bc613 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -112,6 +112,12 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Test * `truffle test --verbose-rpc --network moonbase` + +* Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial + * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 + * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription + * Prepay Subscription https://vrf.chain.link/ + * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me From 3b01dd06539fb986be4403e1fdab8b694c80b24e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 03:38:04 +1000 Subject: [PATCH 39/58] add vrf template contracts --- .../lib/VRFRandomNumberChainlink.sol | 172 ++++++++++++++++++ .../contracts/vrf/VRFConsumerBaseV2.sol | 135 ++++++++++++++ .../interfaces/VRFCoordinatorV2Interface.sol | 114 ++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol create mode 100644 dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol create mode 100644 dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol diff --git a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol new file mode 100644 index 0000000..0a12fc9 --- /dev/null +++ b/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; +import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; + +/** + * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling + * of a 20 sided dice + */ + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +contract VRFD20 is VRFConsumerBaseV2 { + uint256 private constant ROLL_IN_PROGRESS = 42; + + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 s_keyHash = + 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 40,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 40000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 1 random value in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 1; + address s_owner; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + + /** + * @notice Constructor inherits VRFConsumerBaseV2 + * + * @dev NETWORK: Sepolia + * + * @param subscriptionId subscription id that this consumer contract can use + */ + constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + s_owner = msg.sender; + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly + * as that would give miners/VRF operators latitude about which VRF response arrives first. + * @dev You must review your implementation details with extreme care. + * + * @param roller address of the roller + */ + function rollDice( + address roller + ) public onlyOwner returns (uint256 requestId) { + require(s_results[roller] == 0, "Already rolled"); + // Will revert if subscription is not set and funded. + requestId = COORDINATOR.requestRandomWords( + s_keyHash, + s_subscriptionId, + requestConfirmations, + callbackGasLimit, + numWords + ); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); + } + + /** + * @notice Callback function used by VRF Coordinator to return the random number to this contract. + * + * @dev Some action on the contract state should be taken here, like storing the result. + * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result + * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage + * by controlling the order. + * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBaseV2 + * contract ensures that this method only receives randomness from the designated VRFCoordinator. + * + * @param requestId uint256 + * @param randomWords uint256[] The random result returned by the oracle. + */ + function fulfillRandomWords( + uint256 requestId, + uint256[] memory randomWords + ) internal override { + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + emit DiceLanded(requestId, d20Value); + } + + /** + * @notice Get the house assigned to the player once the address has rolled + * @param player address + * @return house as a string + */ + function house(address player) public view returns (string memory) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return getHouseName(s_results[player]); + } + + /** + * @notice Get the house name from the id + * @param id uint256 + * @return house name string + */ + function getHouseName(uint256 id) private pure returns (string memory) { + string[20] memory houseNames = [ + "Targaryen", + "Lannister", + "Stark", + "Tyrell", + "Baratheon", + "Martell", + "Tully", + "Bolton", + "Greyjoy", + "Arryn", + "Frey", + "Mormont", + "Tarley", + "Dayne", + "Umber", + "Valeryon", + "Manderly", + "Clegane", + "Glover", + "Karstark" + ]; + return houseNames[id - 1]; + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; + } +} diff --git a/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol b/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol new file mode 100644 index 0000000..f8d81a0 --- /dev/null +++ b/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +// Reference: https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol + +/** **************************************************************************** + * @notice Interface for contracts using VRF randomness + * ***************************************************************************** + * @dev PURPOSE + * + * @dev Reggie the Random Oracle (not his real job) wants to provide randomness + * @dev to Vera the verifier in such a way that Vera can be sure he's not + * @dev making his output up to suit himself. Reggie provides Vera a public key + * @dev to which he knows the secret key. Each time Vera provides a seed to + * @dev Reggie, he gives back a value which is computed completely + * @dev deterministically from the seed and the secret key. + * + * @dev Reggie provides a proof by which Vera can verify that the output was + * @dev correctly computed once Reggie tells it to her, but without that proof, + * @dev the output is indistinguishable to her from a uniform random sample + * @dev from the output space. + * + * @dev The purpose of this contract is to make it easy for unrelated contracts + * @dev to talk to Vera the verifier about the work Reggie is doing, to provide + * @dev simple access to a verifiable source of randomness. It ensures 2 things: + * @dev 1. The fulfillment came from the VRFCoordinator + * @dev 2. The consumer contract implements fulfillRandomWords. + * ***************************************************************************** + * @dev USAGE + * + * @dev Calling contracts must inherit from VRFConsumerBase, and can + * @dev initialize VRFConsumerBase's attributes in their constructor as + * @dev shown: + * + * @dev contract VRFConsumer { + * @dev constructor(, address _vrfCoordinator, address _link) + * @dev VRFConsumerBase(_vrfCoordinator) public { + * @dev + * @dev } + * @dev } + * + * @dev The oracle will have given you an ID for the VRF keypair they have + * @dev committed to (let's call it keyHash). Create subscription, fund it + * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface + * @dev subscription management functions). + * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, + * @dev callbackGasLimit, numWords), + * @dev see (VRFCoordinatorInterface for a description of the arguments). + * + * @dev Once the VRFCoordinator has received and validated the oracle's response + * @dev to your request, it will call your contract's fulfillRandomWords method. + * + * @dev The randomness argument to fulfillRandomWords is a set of random words + * @dev generated from your requestId and the blockHash of the request. + * + * @dev If your contract could have concurrent requests open, you can use the + * @dev requestId returned from requestRandomWords to track which response is associated + * @dev with which randomness request. + * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, + * @dev if your contract could have multiple requests in flight simultaneously. + * + * @dev Colliding `requestId`s are cryptographically impossible as long as seeds + * @dev differ. + * + * ***************************************************************************** + * @dev SECURITY CONSIDERATIONS + * + * @dev A method with the ability to call your fulfillRandomness method directly + * @dev could spoof a VRF response with any random value, so it's critical that + * @dev it cannot be directly called by anything other than this base contract + * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). + * + * @dev For your users to trust that your contract's random behavior is free + * @dev from malicious interference, it's best if you can write it so that all + * @dev behaviors implied by a VRF response are executed *during* your + * @dev fulfillRandomness method. If your contract must store the response (or + * @dev anything derived from it) and use it later, you must ensure that any + * @dev user-significant behavior which depends on that stored value cannot be + * @dev manipulated by a subsequent VRF request. + * + * @dev Similarly, both miners and the VRF oracle itself have some influence + * @dev over the order in which VRF responses appear on the blockchain, so if + * @dev your contract could have multiple VRF requests in flight simultaneously, + * @dev you must ensure that the order in which the VRF responses arrive cannot + * @dev be used to manipulate your contract's user-significant behavior. + * + * @dev Since the block hash of the block which contains the requestRandomness + * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful + * @dev miner could, in principle, fork the blockchain to evict the block + * @dev containing the request, forcing the request to be included in a + * @dev different block with a different hash, and therefore a different input + * @dev to the VRF. However, such an attack would incur a substantial economic + * @dev cost. This cost scales with the number of blocks the VRF oracle waits + * @dev until it calls responds to a request. It is for this reason that + * @dev that you can signal to an oracle you'd like them to wait longer before + * @dev responding to the request (however this is not enforced in the contract + * @dev and so remains effective only in the case of unmodified oracle software). + */ +abstract contract VRFConsumerBaseV2 { + error OnlyCoordinatorCanFulfill(address have, address want); + address private immutable vrfCoordinator; + + /** + * @param _vrfCoordinator address of VRFCoordinator contract + */ + constructor(address _vrfCoordinator) { + vrfCoordinator = _vrfCoordinator; + } + + /** + * @notice fulfillRandomness handles the VRF response. Your contract must + * @notice implement it. See "SECURITY CONSIDERATIONS" above for important + * @notice principles to keep in mind when implementing your fulfillRandomness + * @notice method. + * + * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this + * @dev signature, and will call it once it has verified the proof + * @dev associated with the randomness. (It is triggered via a call to + * @dev rawFulfillRandomness, below.) + * + * @param requestId The Id initially returned by requestRandomness + * @param randomWords the VRF output expanded to the requested number of words + */ + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; + + // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF + // proof. rawFulfillRandomness then calls fulfillRandomness, after validating + // the origin of the call + function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { + if (msg.sender != vrfCoordinator) { + revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); + } + fulfillRandomWords(requestId, randomWords); + } +} diff --git a/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol b/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol new file mode 100644 index 0000000..f5afd5f --- /dev/null +++ b/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Reference: https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol + +interface VRFCoordinatorV2Interface { + /** + * @notice Get configuration relevant for making requests + * @return minimumRequestConfirmations global min for request confirmations + * @return maxGasLimit global max for request gas limit + * @return s_provingKeyHashes list of registered key hashes + */ + function getRequestConfig() external view returns (uint16, uint32, bytes32[] memory); + + /** + * @notice Request a set of random words. + * @param keyHash - Corresponds to a particular oracle job which uses + * that key for generating the VRF proof. Different keyHash's have different gas price + * ceilings, so you can select a specific one to bound your maximum per request cost. + * @param subId - The ID of the VRF subscription. Must be funded + * with the minimum subscription balance required for the selected keyHash. + * @param minimumRequestConfirmations - How many blocks you'd like the + * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS + * for why you may want to request more. The acceptable range is + * [minimumRequestBlockConfirmations, 200]. + * @param callbackGasLimit - How much gas you'd like to receive in your + * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords + * may be slightly less than this amount because of gas used calling the function + * (argument decoding etc.), so you may need to request slightly more than you expect + * to have inside fulfillRandomWords. The acceptable range is + * [0, maxGasLimit] + * @param numWords - The number of uint256 random values you'd like to receive + * in your fulfillRandomWords callback. Note these numbers are expanded in a + * secure way by the VRFCoordinator from a single random value supplied by the oracle. + * @return requestId - A unique identifier of the request. Can be used to match + * a request to a response in fulfillRandomWords. + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external returns (uint256 requestId); + + /** + * @notice Create a VRF subscription. + * @return subId - A unique subscription id. + * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + * @dev Note to fund the subscription, use transferAndCall. For example + * @dev LINKTOKEN.transferAndCall( + * @dev address(COORDINATOR), + * @dev amount, + * @dev abi.encode(subId)); + */ + function createSubscription() external returns (uint64 subId); + + /** + * @notice Get a VRF subscription. + * @param subId - ID of the subscription + * @return balance - LINK balance of the subscription in juels. + * @return reqCount - number of requests for this subscription, determines fee tier. + * @return owner - owner of the subscription. + * @return consumers - list of consumer address which are able to use this subscription. + */ + function getSubscription( + uint64 subId + ) external view returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers); + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @param newOwner - proposed new owner of the subscription + */ + function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @dev will revert if original owner of subId has + * not requested that msg.sender become the new owner. + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external; + + /** + * @notice Add a consumer to a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - New consumer which can use the subscription + */ + function addConsumer(uint64 subId, address consumer) external; + + /** + * @notice Remove a consumer from a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - Consumer to remove from the subscription + */ + function removeConsumer(uint64 subId, address consumer) external; + + /** + * @notice Cancel a subscription + * @param subId - ID of the subscription + * @param to - Where to send the remaining LINK to + */ + function cancelSubscription(uint64 subId, address to) external; + + /* + * @notice Check to see if there exists a request commitment consumers + * for all consumers and keyhashes for a given sub. + * @param subId - ID of the subscription + * @return true if there exists at least one unfulfilled request for the subscription, false + * otherwise. + */ + function pendingRequestExists(uint64 subId) external view returns (bool); +} From fb3d91f6a01392b3d35796b76c6f1389bc8e9e7a Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 06:41:11 +1000 Subject: [PATCH 40/58] wip Chainlink VRF Sepolia --- dapps/evm2/flipper/.env.example | 2 + dapps/evm2/flipper/README.md | 4 ++ .../flipper/contracts/lib/RandomNumber.sol | 44 ++++++++++++++-- ...omNumberChainlink.sol => VRFChainlink.sol} | 51 ++++--------------- .../flipper/migrations/2_deploy_contracts.js | 31 +++++------ dapps/evm2/flipper/test/test_ChainlinkVRF.js | 46 +++++++++++++++++ dapps/evm2/flipper/test/test_Flipper.js | 4 +- dapps/evm2/flipper/truffle-config.js | 11 ++++ 8 files changed, 133 insertions(+), 60 deletions(-) rename dapps/evm2/flipper/contracts/lib/{VRFRandomNumberChainlink.sol => VRFChainlink.sol} (79%) create mode 100644 dapps/evm2/flipper/test/test_ChainlinkVRF.js diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index fe04628..78cc6fa 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -3,3 +3,5 @@ MOONBASE_PRIVATE_KEY='0x' MOONSCAN_API_KEY='' # https://blastapi.io/ MOONBASE_BLASTAPI_ENDPOINT='' +# obtain from https://dashboard.alchemy.com/ under Ethereum > Ethereum Sepolia +CHAINLINK_SEPOLIA_ENDPOINT='https://rpc.sepolia.org' diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index f4bc613..c86f48e 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -110,13 +110,17 @@ shasum -a 256 moonkey * Compile full `truffle compile --compile-all` * Migrate * Migrate full `truffle migrate --reset --compile-all --network moonbase` + * Migrate full `truffle migrate --reset --compile-all --network sepolia` * Test * `truffle test --verbose-rpc --network moonbase` + * `truffle test --verbose-rpc --network sepolia` * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription * Prepay Subscription https://vrf.chain.link/ + * Receipt https://sepolia.etherscan.io/tx/0xcc2cd9edf90e0f3351f3398b7013a7259c0acc7cfbfc38454192324fcfdb7d6a + * Reference v2 contract (not implemented): https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2Consumer.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 914e974..36bfaf8 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -25,10 +25,22 @@ contract RandomNumber is RandomnessConsumer { uint32 public VRF_BLOCKS_DELAY; bytes32 public SALT_PREFIX = "change-me-to-anything"; + uint256 private constant ROLL_IN_PROGRESS = 42; + // Storage variables for the current request uint256 public requestId; uint256[] public random; + address s_owner; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + constructor() payable RandomnessConsumer() { // Initialize use of Randomness dependency before trying to access it theRandomness = Randomness(randomnessPrecompileAddress); @@ -36,10 +48,14 @@ contract RandomNumber is RandomnessConsumer { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. require(msg.value >= requiredDeposit); + s_owner = msg.sender; VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } - function requestRandomness() public payable { + function requestRandomness( + address roller + ) public onlyOwner payable { + require(s_results[roller] == 0, "Already rolled"); // Make sure that the value sent is enough require(msg.value >= MIN_FEE); // Request local VRF randomness @@ -51,6 +67,10 @@ contract RandomNumber is RandomnessConsumer { 1, // Number of random words VRF_BLOCKS_DELAY // Delay before request can be fulfilled ); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); } function getRequestStatus() public view returns(Randomness.RequestStatus) { @@ -63,10 +83,28 @@ contract RandomNumber is RandomnessConsumer { } function fulfillRandomWords( - uint256, /* requestId */ + uint256 requestId, /* requestId */ uint256[] memory randomWords ) internal override { // Save the randomness results - random = randomWords; + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + // random = randomWords; + } + + /** + * @notice Get the value rolled by a player once the address has rolled + * @param player address + * @return id as a string + */ + function getRolledValueForPlayer(address player) public view returns (uint256) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return s_results[player]; + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; } } diff --git a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol similarity index 79% rename from dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol rename to dapps/evm2/flipper/contracts/lib/VRFChainlink.sol index 0a12fc9..306ccaa 100644 --- a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol +++ b/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; -import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; -import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; +// Reference: https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFD20.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js +import "../vrf/interfaces/VRFCoordinatorV2Interface.sol"; +import "../vrf/VRFConsumerBaseV2.sol"; /** * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling @@ -26,7 +27,7 @@ contract VRFD20 is VRFConsumerBaseV2 { VRFCoordinatorV2Interface COORDINATOR; // Your subscription ID. - uint64 s_subscriptionId; + uint64 public s_subscriptionId; // Sepolia coordinator. For other networks, // see https://docs.chain.link/docs/vrf-contracts/#configurations @@ -52,7 +53,7 @@ contract VRFD20 is VRFConsumerBaseV2 { // For this example, retrieve 1 random value in one request. // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. uint32 numWords = 1; - address s_owner; + address public s_owner; // map rollers to requestIds mapping(uint256 => address) private s_rollers; @@ -69,8 +70,9 @@ contract VRFD20 is VRFConsumerBaseV2 { * * @param subscriptionId subscription id that this consumer contract can use */ - constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) { + constructor(uint64 subscriptionId) payable VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + require(msg.value > 0); s_owner = msg.sender; s_subscriptionId = subscriptionId; } @@ -124,45 +126,14 @@ contract VRFD20 is VRFConsumerBaseV2 { } /** - * @notice Get the house assigned to the player once the address has rolled + * @notice Get the value rolled by a player once the address has rolled * @param player address - * @return house as a string + * @return id as a string */ - function house(address player) public view returns (string memory) { + function getRolledValueForPlayer(address player) public view returns (uint256) { require(s_results[player] != 0, "Dice not rolled"); require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); - return getHouseName(s_results[player]); - } - - /** - * @notice Get the house name from the id - * @param id uint256 - * @return house name string - */ - function getHouseName(uint256 id) private pure returns (string memory) { - string[20] memory houseNames = [ - "Targaryen", - "Lannister", - "Stark", - "Tyrell", - "Baratheon", - "Martell", - "Tully", - "Bolton", - "Greyjoy", - "Arryn", - "Frey", - "Mormont", - "Tarley", - "Dayne", - "Umber", - "Valeryon", - "Manderly", - "Clegane", - "Glover", - "Karstark" - ]; - return houseNames[id - 1]; + return s_results[player]; } modifier onlyOwner() { diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index ca64741..62e319e 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -2,28 +2,29 @@ require('dotenv').config() const { Web3 } = require('web3'); const contract = require("@truffle/contract"); +var VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); var Flipper = artifacts.require("../build/contracts/Flipper"); console.log('deploying...'); module.exports = async function (deployer) { - - console.log('deploy_contracts'); - let providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + let providerInstance; + let web3; + console.log('deploy_contracts to Moonbase Alpha'); + + providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); console.log('providerInstance: ', providerInstance); - let web3 = new Web3(providerInstance); + + web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); - // let networkId = await web3.eth.net.getId(); - // console.log('networkId: ', networkId); - // RandomNumber.setNetwork(networkId); - // RandomNumber.setProvider(providerInstance); - // Flipper.setNetwork(networkId); - // Flipper.setProvider(providerInstance); - // console.log('web3.eth', web3.eth); - // const accounts = await web3.eth.getAccounts(); - // console.log('accounts: ', accounts); - // deployer.deploy(RandomNumber, { from: accounts[0], value: Web3.utils.toWei('1', 'ether') }); deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); - // deployer.link(RandomNumber, Flipper); deployer.deploy(Flipper, false); + + console.log('deploy_contracts to Chainlink Sepolia'); + providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + console.log('providerInstance: ', providerInstance); + web3 = new Web3(providerInstance); + console.log('web3.currentProvider: ', web3.currentProvider); + const subscriptionId = 3217; // https://vrf.chain.link/ + deployer.deploy(VRFChainlink, { subscriptionId: subscriptionId, value: web3.utils.toWei('0.001', 'ether') }); }; diff --git a/dapps/evm2/flipper/test/test_ChainlinkVRF.js b/dapps/evm2/flipper/test/test_ChainlinkVRF.js new file mode 100644 index 0000000..2b18c8f --- /dev/null +++ b/dapps/evm2/flipper/test/test_ChainlinkVRF.js @@ -0,0 +1,46 @@ +require('dotenv').config() +const { Web3 } = require('web3'); +const BN = require('bn.js'); + +// Uses Mocha and Ganache +const VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); + +console.log('test_ChainlinkVRF'); + +let providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); +console.log('providerInstance: ', providerInstance); +let web3 = new Web3(providerInstance); +console.log('web3.currentProvider: ', web3.currentProvider); + +contract('VRFChainlink', accounts => { + console.log('accounts: ', accounts); + let vrfChainlinkInstance; + let gas; + let gasLimit; + let gasPrice; + + beforeEach(async () => { + console.log('beforeEach'); + + vrfChainlinkInstance = await VRFChainlink.deployed(); + console.log('vrfChainlinkInstance.address:', vrfChainlinkInstance.address); + }); + + it("requests random VRF", async () => { + try { + let s_subscriptionId = await vrfChainlinkInstance.s_subscriptionId.call(); + console.log('s_subscriptionId: ', s_subscriptionId.toString()); + console.log('s_subscriptionId is bn', BN.isBN(s_subscriptionId)); + console.log('accounts', accounts); + + let s_owner = await vrfChainlinkInstance.s_owner.call(); + console.log('s_owner: ', s_owner.toString()); + + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + requestId = await randomNumberInstance.rollDice(roller, { from: accounts[0], value: fulfillmentFee }); + console.log('requestId: ', requestId); + } catch (e) { + console.log('error in requests random VRF: ', e); + } + }); +}); diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index da8405e..8102e21 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -114,7 +114,6 @@ contract('Flipper', accounts => { }); it("requests randomness", async () => { - // TEMP ONLY - TRYING TO GET `requestRandomness` TO WORK try { fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); console.log('fulfillmentFee: ', fulfillmentFee.toString()); @@ -129,7 +128,8 @@ contract('Flipper', accounts => { gas = Web3.utils.toHex(150000); gasLimit = Web3.utils.toHex(600000); gasPrice = Web3.utils.toHex(21000); - refundAddress = await randomNumberInstance.requestRandomness({ from: accounts[0], value: fulfillmentFee }); + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + refundAddress = await randomNumberInstance.requestRandomness(roller, { from: accounts[0], value: fulfillmentFee }); // refundAddress = await randomNumberInstance.requestRandomness( // { // from: accounts[0], diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 1aa0fee..32b7c91 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -76,6 +76,17 @@ module.exports = { // deploymentPollingInterval: 8000, network_id: defaultMoonbaseNetworkId, }, + // Chainlink Sepolia + sepolia: { + provider: () => { + let args = { + privateKeys: [privateKeyMoonbase], + providerOrUrl: process.env.CHAINLINK_SEPOLIA_ENDPOINT, + }; + return new HDWalletProvider(args); + }, + network_id: 11155111, + }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet astar_shibuya: { provider: () => { From 2a2cd51b76d81e83630df8facd824e56845aa43b Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 09:13:31 +1000 Subject: [PATCH 41/58] Uncaught Error: invalid 1st argument: block_number value was not valid block tag or block number --- dapps/evm2/flipper/.env.example | 1 + dapps/evm2/flipper/README.md | 10 +++-- .../flipper/contracts/lib/RandomNumber.sol | 22 +++++----- .../lib/{VRFChainlink.sol => VRFD20.sol} | 2 +- .../flipper/migrations/2_deploy_contracts.js | 29 +++++++----- dapps/evm2/flipper/package.json | 1 + dapps/evm2/flipper/scripts/demo.js | 44 +++++++++++++++++++ dapps/evm2/flipper/scripts/package.json | 15 +++++++ dapps/evm2/flipper/test/test_ChainlinkVRF.js | 11 +++-- dapps/evm2/flipper/truffle-config.js | 4 ++ 10 files changed, 107 insertions(+), 32 deletions(-) rename dapps/evm2/flipper/contracts/lib/{VRFChainlink.sol => VRFD20.sol} (99%) create mode 100644 dapps/evm2/flipper/scripts/demo.js create mode 100644 dapps/evm2/flipper/scripts/package.json diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index 78cc6fa..ac359b7 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -5,3 +5,4 @@ MOONSCAN_API_KEY='' MOONBASE_BLASTAPI_ENDPOINT='' # obtain from https://dashboard.alchemy.com/ under Ethereum > Ethereum Sepolia CHAINLINK_SEPOLIA_ENDPOINT='https://rpc.sepolia.org' +ALCHEMY_API_KEY='' diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index c86f48e..ea4f6aa 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -112,8 +112,11 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Migrate full `truffle migrate --reset --compile-all --network sepolia` * Test - * `truffle test --verbose-rpc --network moonbase` - * `truffle test --verbose-rpc --network sepolia` + * **Important:** It is necessary to first comment-out the code that is **not being compiled** in 2_deploy_contracts.j + * `truffle test ./test/test_Flipper.js --verbose-rpc --network moonbase` + * `truffle test ./test/test_ChainlinkVRF.js --network sepolia` +* Run + * node ./scripts/demo.js * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 @@ -126,7 +129,8 @@ shasum -a 256 moonkey * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me * If you get error `PollingBlockTracker` then try connecting to a different ISP and disable VPN and stop using a proxy and restart access to your internet - * Sometimes when you run `truffle test --network moonbase` after changing some CLI options it outputs `Error: The network id specified in the truffle config (1287) does not match the one returned by the network (4619453). Ensure that both the network and the provider are properly configured`, even though the network id in the truffle-config.js is in fact 1287, but when you run it again it might works. So just keep running the command again until it + * Sometimes when you run `truffle test --network moonbase` after changing some CLI options it outputs `Error: The network id specified in the truffle config (1287) does not match the one returned by the network (4619453). Ensure that both the network and the provider are properly configured`, even though the network id in the truffle-config.js is in fact 1287 (for some reason it confuses the block number for the network id), but when you run it again it might works. So just keep running the command again until it. Or run `truffle test --network sepolia` instead of + `truffle test --verbose-rpc --network sepolia` works or change internet connection. * References * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 36bfaf8..16bf121 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -31,7 +31,7 @@ contract RandomNumber is RandomnessConsumer { uint256 public requestId; uint256[] public random; - address s_owner; + // address public s_owner; // map rollers to requestIds mapping(uint256 => address) private s_rollers; @@ -48,13 +48,14 @@ contract RandomNumber is RandomnessConsumer { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. require(msg.value >= requiredDeposit); - s_owner = msg.sender; + // s_owner = msg.sender; VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } function requestRandomness( address roller - ) public onlyOwner payable { + ) public payable { + // ) public onlyOwner payable { require(s_results[roller] == 0, "Already rolled"); // Make sure that the value sent is enough require(msg.value >= MIN_FEE); @@ -83,13 +84,14 @@ contract RandomNumber is RandomnessConsumer { } function fulfillRandomWords( - uint256 requestId, /* requestId */ + uint256 reqId, /* requestId */ uint256[] memory randomWords ) internal override { // Save the randomness results uint256 d20Value = (randomWords[0] % 20) + 1; - s_results[s_rollers[requestId]] = d20Value; - // random = randomWords; + s_results[s_rollers[reqId]] = d20Value; + // Save the latest for comparison + random = randomWords; } /** @@ -103,8 +105,8 @@ contract RandomNumber is RandomnessConsumer { return s_results[player]; } - modifier onlyOwner() { - require(msg.sender == s_owner); - _; - } + // modifier onlyOwner() { + // require(msg.sender == s_owner); + // _; + // } } diff --git a/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFD20.sol similarity index 99% rename from dapps/evm2/flipper/contracts/lib/VRFChainlink.sol rename to dapps/evm2/flipper/contracts/lib/VRFD20.sol index 306ccaa..415c70c 100644 --- a/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol +++ b/dapps/evm2/flipper/contracts/lib/VRFD20.sol @@ -72,7 +72,7 @@ contract VRFD20 is VRFConsumerBaseV2 { */ constructor(uint64 subscriptionId) payable VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); - require(msg.value > 0); + // require(msg.value > 0); s_owner = msg.sender; s_subscriptionId = subscriptionId; } diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 62e319e..cb7aea3 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,24 +1,26 @@ require('dotenv').config() const { Web3 } = require('web3'); -const contract = require("@truffle/contract"); +const BN = require('bn.js'); -var VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); -var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); -var Flipper = artifacts.require("../build/contracts/Flipper"); +// const contract = require("@truffle/contract"); + +var VRFD20 = artifacts.require("../build/contracts/VRFD20"); +// var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); +// var Flipper = artifacts.require("../build/contracts/Flipper"); console.log('deploying...'); module.exports = async function (deployer) { let providerInstance; let web3; - console.log('deploy_contracts to Moonbase Alpha'); + // console.log('deploy_contracts to Moonbase Alpha'); - providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); - console.log('providerInstance: ', providerInstance); + // providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + // console.log('providerInstance: ', providerInstance); - web3 = new Web3(providerInstance); - console.log('web3.currentProvider: ', web3.currentProvider); - deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); - deployer.deploy(Flipper, false); + // web3 = new Web3(providerInstance); + // console.log('web3.currentProvider: ', web3.currentProvider); + // deployer.deploy(RandomNumber, { value: web3.utils.toWei('0.000001', 'ether') }); + // deployer.deploy(Flipper, false); console.log('deploy_contracts to Chainlink Sepolia'); providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); @@ -26,5 +28,8 @@ module.exports = async function (deployer) { web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); const subscriptionId = 3217; // https://vrf.chain.link/ - deployer.deploy(VRFChainlink, { subscriptionId: subscriptionId, value: web3.utils.toWei('0.001', 'ether') }); + // wants 128620983229604640 wei + const value = web3.utils.toWei('0.000001', 'ether'); + const amount = new BN(value, 10); + deployer.deploy(VRFD20, subscriptionId, { value: amount }); }; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index 39e977e..2ec6446 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -4,6 +4,7 @@ "dependencies": { "@truffle/contract": "^4.6.25", "@truffle/hdwallet-provider": "^2.1.12", + "alchemy-sdk": "^2.9.1", "bn.js": "^5.2.1", "dotenv": "^16.3.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js new file mode 100644 index 0000000..47ea7e8 --- /dev/null +++ b/dapps/evm2/flipper/scripts/demo.js @@ -0,0 +1,44 @@ +require('dotenv').config() +const { Network, Alchemy } = require('alchemy-sdk'); + +const config = { + apiKey: process.env.ALCHEMY_API_KEY, + network: Network.ETH_SEPOLIA, +}; + +const alchemy = new Alchemy(config); +// console.log('alchemy', alchemy); + +// Get the latest block +const latestBlock = alchemy.core.getBlockNumber(); +console.log('latestBlock', latestBlock); + +alchemy.core + .getTokenBalances("0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7") + .then(console.log); + +// Listen to all new pending transactions +alchemy.ws.on( + { + method: "alchemy_pendingTransactions", + fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" + }, + (res) => console.log('detected pending tx from account:', res), +); + +// Example of using the call method +const main = async () => { + // //Initialize a variable for the transaction object + // let tx = { + // to: "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41", + // gas: "0x76c0", + // gasPrice: "0x9184e72a000", + // data: "0x3b3b57debf074faa138b72c65adbdcfb329847e4f2c04bde7f7dd7fcad5a52d2f395a558", + // } + // let response = await alchemy.core.call(tx) + + // //Logging the response to the console + // console.log(response) + }; + + main(); \ No newline at end of file diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json new file mode 100644 index 0000000..e45668c --- /dev/null +++ b/dapps/evm2/flipper/scripts/package.json @@ -0,0 +1,15 @@ +{ + "name": "flipper", + "version": "1.0.0", + "description": "", + "main": "demo.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "ltfschoen", + "license": "MIT", + "dependencies": { + "alchemy-sdk": "^2.9.1", + "web3": "^4.0.2" + } +} diff --git a/dapps/evm2/flipper/test/test_ChainlinkVRF.js b/dapps/evm2/flipper/test/test_ChainlinkVRF.js index 2b18c8f..9bd18a5 100644 --- a/dapps/evm2/flipper/test/test_ChainlinkVRF.js +++ b/dapps/evm2/flipper/test/test_ChainlinkVRF.js @@ -3,7 +3,7 @@ const { Web3 } = require('web3'); const BN = require('bn.js'); // Uses Mocha and Ganache -const VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); +const VRFD20 = artifacts.require("../build/contracts/VRFD20"); console.log('test_ChainlinkVRF'); @@ -12,17 +12,16 @@ console.log('providerInstance: ', providerInstance); let web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); -contract('VRFChainlink', accounts => { +contract('VRFD20', accounts => { console.log('accounts: ', accounts); let vrfChainlinkInstance; - let gas; - let gasLimit; - let gasPrice; beforeEach(async () => { + // error `Uncaught Error: invalid 1st argument: block_number value was not valid block tag or block number` + console.log('beforeEach'); - vrfChainlinkInstance = await VRFChainlink.deployed(); + vrfChainlinkInstance = await VRFD20.deployed(); console.log('vrfChainlinkInstance.address:', vrfChainlinkInstance.address); }); diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 32b7c91..c05ee40 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -82,9 +82,13 @@ module.exports = { let args = { privateKeys: [privateKeyMoonbase], providerOrUrl: process.env.CHAINLINK_SEPOLIA_ENDPOINT, + retryTimeout: 10000, }; return new HDWalletProvider(args); }, + websocket: true, + gasLimit: 5000000, + networkCheckTimeout: 1000000000, network_id: 11155111, }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet From dd0d6abbc167056fa094a088be71d97de0dc6ce4 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 09:28:49 +1000 Subject: [PATCH 42/58] success deploying chainlink VRF to Sepolia --- dapps/evm2/flipper/README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index ea4f6aa..27b09af 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -115,6 +115,42 @@ shasum -a 256 moonkey * **Important:** It is necessary to first comment-out the code that is **not being compiled** in 2_deploy_contracts.j * `truffle test ./test/test_Flipper.js --verbose-rpc --network moonbase` * `truffle test ./test/test_ChainlinkVRF.js --network sepolia` +* Verify Contract - Moonbase Precompile + +``` +# truffle run verify Flipper --network moonbase +Verifying contracts on moonscan + Verifying Flipper + Pass - Verified: https://moonbase.moonscan.io/address/0x1c440D264DcCBe9b7AC84edCEC99De926Db98753#code + Successfully verified 1 contract(s). +Verifying contracts on sourcify + Failed to connect to Sourcify API at url https://sourcify.dev/server/chains +root@ink:/app/dapps/evm2/flipper# truffle run verify RandomNumber --network moonbase +Verifying contracts on moonscan + Verifying RandomNumber + Pass - Verified: https://moonbase.moonscan.io/address/0x4027755C05514421fe00f4Fde0bD3F8475ce8A6b#code + Successfully verified 1 contract(s). +Verifying contracts on sourcify + Failed to connect to Sourcify API at url https://sourcify.dev/server/chains +``` + +* Verify Contract - Chainlink VRF +``` +# truffle run verify VRFD20 --network sepolia + +Verifying contracts on etherscan + No etherscan or sepolia_etherscan API Key provided +Verifying contracts on sourcify + Verifying VRFD20 + Pass - Verified: https://sourcify.dev/#/lookup/0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6 + Successfully verified 1 contract(s). +``` + +* Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial + * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 + * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription + * Prepay Subscription https://vrf.chain.link/ + * Run * node ./scripts/demo.js From 039630ffe99b903f1475e5dd7a9ee7f3d2bfc0a7 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 10:00:40 +1000 Subject: [PATCH 43/58] trying to interact with vrf to play game --- dapps/evm2/flipper/package.json | 1 + dapps/evm2/flipper/scripts/demo.js | 51 +++++++++++++++---------- dapps/evm2/flipper/scripts/package.json | 1 + 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index 2ec6446..af96346 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -7,6 +7,7 @@ "alchemy-sdk": "^2.9.1", "bn.js": "^5.2.1", "dotenv": "^16.3.1", + "ethers": "^6.6.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", "truffle": "^5.10.0", "truffle-plugin-verify": "^0.6.3", diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 47ea7e8..29befca 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -1,5 +1,26 @@ require('dotenv').config() const { Network, Alchemy } = require('alchemy-sdk'); +const ethers = require('ethers'); + +// https://docs.alchemy.com/docs/interacting-with-a-smart-contract +const VRFD20ContractBuilt = require("../build/contracts/VRFD20.json"); + +// Provider +// https://docs.ethers.org/v6/api/providers/#WebSocketProvider +const alchemyProvider = new ethers.AlchemyProvider( + chainId=11155111, + // url=process.env.CHAINLINK_SEPOLIA_ENDPOINT, + // network=Network.ETH_SEPOLIA, + // "eth-sepolia", + process.env.ALCHEMY_API_KEY +); + +// Signer +const signer = new ethers.Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); + +// Contract +const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; +const VRFD20Contract = new ethers.Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); const config = { apiKey: process.env.ALCHEMY_API_KEY, @@ -9,14 +30,6 @@ const config = { const alchemy = new Alchemy(config); // console.log('alchemy', alchemy); -// Get the latest block -const latestBlock = alchemy.core.getBlockNumber(); -console.log('latestBlock', latestBlock); - -alchemy.core - .getTokenBalances("0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7") - .then(console.log); - // Listen to all new pending transactions alchemy.ws.on( { @@ -28,17 +41,13 @@ alchemy.ws.on( // Example of using the call method const main = async () => { - // //Initialize a variable for the transaction object - // let tx = { - // to: "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41", - // gas: "0x76c0", - // gasPrice: "0x9184e72a000", - // data: "0x3b3b57debf074faa138b72c65adbdcfb329847e4f2c04bde7f7dd7fcad5a52d2f395a558", - // } - // let response = await alchemy.core.call(tx) - - // //Logging the response to the console - // console.log(response) - }; + // Get the latest block + const latestBlock = alchemy.core.getBlockNumber(); + console.log('latestBlock', latestBlock); + + // Interact with VRFD20 + const s_owner = await VRFD20Contract.s_owner(); + console.log("The s_owner is: ", s_owner); +}; - main(); \ No newline at end of file +main(); diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json index e45668c..cfa9b78 100644 --- a/dapps/evm2/flipper/scripts/package.json +++ b/dapps/evm2/flipper/scripts/package.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "alchemy-sdk": "^2.9.1", + "ethers": "^6.6.1", "web3": "^4.0.2" } } From e8992e4ca042ae7ae2ae8c252a672fdcd836c978 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 10:10:12 +1000 Subject: [PATCH 44/58] able to get instance of vrf contract --- dapps/evm2/flipper/scripts/demo.js | 58 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 29befca..4f8a646 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -5,45 +5,47 @@ const ethers = require('ethers'); // https://docs.alchemy.com/docs/interacting-with-a-smart-contract const VRFD20ContractBuilt = require("../build/contracts/VRFD20.json"); -// Provider -// https://docs.ethers.org/v6/api/providers/#WebSocketProvider -const alchemyProvider = new ethers.AlchemyProvider( - chainId=11155111, - // url=process.env.CHAINLINK_SEPOLIA_ENDPOINT, - // network=Network.ETH_SEPOLIA, - // "eth-sepolia", - process.env.ALCHEMY_API_KEY -); +const config = { + apiKey: process.env.ALCHEMY_API_KEY, + network: Network.ETH_SEPOLIA, +}; + +const alchemyProvider = new Alchemy(config); +console.log('alchemyProvider', alchemyProvider); + +// // Provider +// // https://docs.ethers.org/v6/api/providers/#WebSocketProvider +// const alchemyProvider = new ethers.AlchemyProvider( +// // _network: 11155111, +// // url=process.env.CHAINLINK_SEPOLIA_ENDPOINT, +// _network=Network.ETH_SEPOLIA, +// // "eth-sepolia", +// process.env.ALCHEMY_API_KEY +// ); // Signer const signer = new ethers.Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); +console.log('signer', signer); // Contract const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; const VRFD20Contract = new ethers.Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); +console.log('VRFD20Contract', VRFD20Contract); -const config = { - apiKey: process.env.ALCHEMY_API_KEY, - network: Network.ETH_SEPOLIA, -}; - -const alchemy = new Alchemy(config); -// console.log('alchemy', alchemy); - -// Listen to all new pending transactions -alchemy.ws.on( - { - method: "alchemy_pendingTransactions", - fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" - }, - (res) => console.log('detected pending tx from account:', res), -); +// // Listen to all new pending transactions +// alchemy.ws.on( +// { +// method: "alchemy_pendingTransactions", +// fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" +// }, +// (res) => console.log('detected pending tx from account:', res), +// ); // Example of using the call method const main = async () => { - // Get the latest block - const latestBlock = alchemy.core.getBlockNumber(); - console.log('latestBlock', latestBlock); + // // Get the latest block + // const latestBlock = alchemy.core.getBlockNumber(); + // console.log('latestBlock', latestBlock); // Interact with VRFD20 const s_owner = await VRFD20Contract.s_owner(); From 3a8541b472d7300f64024d75dd1d9221886b5400 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 11:28:14 +1000 Subject: [PATCH 45/58] fix use of correct alchemy key --- .../flipper/migrations/2_deploy_contracts.js | 2 - dapps/evm2/flipper/scripts/demo.js | 48 +++++++++---------- dapps/evm2/flipper/scripts/package.json | 1 + 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index cb7aea3..2b31c32 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -2,8 +2,6 @@ require('dotenv').config() const { Web3 } = require('web3'); const BN = require('bn.js'); -// const contract = require("@truffle/contract"); - var VRFD20 = artifacts.require("../build/contracts/VRFD20"); // var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); // var Flipper = artifacts.require("../build/contracts/Flipper"); diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 4f8a646..58e6bcc 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -1,8 +1,6 @@ require('dotenv').config() const { Network, Alchemy } = require('alchemy-sdk'); const ethers = require('ethers'); - -// https://docs.alchemy.com/docs/interacting-with-a-smart-contract const VRFD20ContractBuilt = require("../build/contracts/VRFD20.json"); const config = { @@ -11,7 +9,27 @@ const config = { }; const alchemyProvider = new Alchemy(config); -console.log('alchemyProvider', alchemyProvider); +// console.log('alchemyProvider', alchemyProvider); + +// Signer +const signer = new ethers.Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); +// console.log('signer', signer); + +// Contract +const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; +const VRFD20Contract = new ethers.Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); +// console.log('VRFD20Contract', VRFD20Contract); + +// Example of using the call method +const main = async () => { + // Get the latest block + const latestBlock = await alchemyProvider.core.getBlockNumber(); + console.log('latestBlock', latestBlock); +}; + +main(); + +// https://docs.alchemy.com/docs/interacting-with-a-smart-contract // // Provider // // https://docs.ethers.org/v6/api/providers/#WebSocketProvider @@ -23,15 +41,6 @@ console.log('alchemyProvider', alchemyProvider); // process.env.ALCHEMY_API_KEY // ); -// Signer -const signer = new ethers.Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); -console.log('signer', signer); - -// Contract -const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; -const VRFD20Contract = new ethers.Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); -console.log('VRFD20Contract', VRFD20Contract); - // // Listen to all new pending transactions // alchemy.ws.on( // { @@ -41,15 +50,6 @@ console.log('VRFD20Contract', VRFD20Contract); // (res) => console.log('detected pending tx from account:', res), // ); -// Example of using the call method -const main = async () => { - // // Get the latest block - // const latestBlock = alchemy.core.getBlockNumber(); - // console.log('latestBlock', latestBlock); - - // Interact with VRFD20 - const s_owner = await VRFD20Contract.s_owner(); - console.log("The s_owner is: ", s_owner); -}; - -main(); + // // Interact with VRFD20 + // const s_owner = await VRFD20Contract.s_owner(); + // console.log("The s_owner is: ", s_owner); diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json index cfa9b78..c6a0a41 100644 --- a/dapps/evm2/flipper/scripts/package.json +++ b/dapps/evm2/flipper/scripts/package.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "alchemy-sdk": "^2.9.1", + "dotenv": "^16.3.1", "ethers": "^6.6.1", "web3": "^4.0.2" } From 5d3b2c3a55374fcc32800994a9798777966ae7f8 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 29 Jun 2023 10:14:11 +1000 Subject: [PATCH 46/58] fix migration, requires min deposit of 1 eth to not error --- .../flipper/migrations/2_deploy_contracts.js | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 2b31c32..8672f3a 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -2,32 +2,37 @@ require('dotenv').config() const { Web3 } = require('web3'); const BN = require('bn.js'); -var VRFD20 = artifacts.require("../build/contracts/VRFD20"); -// var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); -// var Flipper = artifacts.require("../build/contracts/Flipper"); - console.log('deploying...'); module.exports = async function (deployer) { let providerInstance; let web3; - // console.log('deploy_contracts to Moonbase Alpha'); - - // providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); - // console.log('providerInstance: ', providerInstance); + if (deployer.network == "moonbase") { + console.log('deploy_contracts to Moonbase Alpha'); + + const RandomNumber = artifacts.require("../build/contracts/RandomNumber"); + const Flipper = artifacts.require("../build/contracts/Flipper"); - // web3 = new Web3(providerInstance); - // console.log('web3.currentProvider: ', web3.currentProvider); - // deployer.deploy(RandomNumber, { value: web3.utils.toWei('0.000001', 'ether') }); - // deployer.deploy(Flipper, false); + providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + console.log('providerInstance: ', providerInstance); + + web3 = new Web3(providerInstance); + console.log('web3.currentProvider: ', web3.currentProvider); + // must be at least 1 ether since it must be greater than `REQUEST_DEPOSIT_AMOUNT` + deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); + deployer.deploy(Flipper, false); + } else if (deployer.network == "sepolia") { + console.log('deploy_contracts to Chainlink Sepolia'); + + const VRFD20 = artifacts.require("../build/contracts/VRFD20"); - console.log('deploy_contracts to Chainlink Sepolia'); - providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); - console.log('providerInstance: ', providerInstance); - web3 = new Web3(providerInstance); - console.log('web3.currentProvider: ', web3.currentProvider); - const subscriptionId = 3217; // https://vrf.chain.link/ - // wants 128620983229604640 wei - const value = web3.utils.toWei('0.000001', 'ether'); - const amount = new BN(value, 10); - deployer.deploy(VRFD20, subscriptionId, { value: amount }); + providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + console.log('providerInstance: ', providerInstance); + web3 = new Web3(providerInstance); + console.log('web3.currentProvider: ', web3.currentProvider); + const subscriptionId = 3217; // https://vrf.chain.link/ + // wants 128620983229604640 wei + const value = web3.utils.toWei('0.000001', 'ether'); + const amount = new BN(value, 10); + deployer.deploy(VRFD20, subscriptionId, { value: amount }); + } }; From 34e8cf52e9c8023468e29cd0aedcc6d15f504f3d Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 2 Jul 2023 12:54:33 +1000 Subject: [PATCH 47/58] fix use of alchemy but error when creating chainlink subscription to add consumer in UI --- dapps/evm2/flipper/README.md | 29 ++++++++++- dapps/evm2/flipper/package.json | 1 - dapps/evm2/flipper/scripts/demo.js | 81 ++++++++++++++++++------------ 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 27b09af..875f295 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -169,8 +169,33 @@ Verifying contracts on sourcify `truffle test --verbose-rpc --network sepolia` works or change internet connection. * References + * Hackathon submission + * https://moonbeam.hackerearth.com/challenges/hackathon/moonbeam-hackathon-2/dashboard * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md * https://docs.web3js.org/ * https://evmdocs.acala.network/tutorials/hardhat-tutorials/precompiledtoken-tutorial - * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial - * Chainlink Faucet https://faucets.chain.link/ + * Chainlink + * https://vrf.chain.link/ + * VRF https://docs.chain.link/getting-started/intermediates-tutorial + * Faucet https://faucets.chain.link/ + * https://docs.chain.link/getting-started/advanced-tutorial + * https://docs.chain.link/vrf/v2/subscription/supported-networks/#configurations + * https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription + * Alchemy + * https://dashboard.alchemy.com/apps + * https://docs.alchemy.com/reference/api-overview + * https://github.com/alchemyplatform/alchemy-sdk-js + * https://docs.alchemy.com/docs/smart-contract-basics + * https://docs.alchemy.com/docs/ethers-js-provider + * https://docs.alchemy.com/docs/interacting-with-a-smart-contract + * Ethers + * https://docs.ethers.org/v6/api/providers/#WebSocketProvider + * XCM + * https://docs.moonbeam.network/builders/interoperability/xcm/overview/ + * https://github.com/AstarNetwork/ink-xvm-sdk/tree/main + * Polkadot.js + * https://docs.moonbeam.network/builders/build/substrate-api/polkadot-js-api/ + + * Other + * https://github.com/HCastano/urban-planning-in-the-paraverse-with-ink + * https://www.rob.tech/blog/hybrid-chains/ \ No newline at end of file diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index af96346..2ec6446 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -7,7 +7,6 @@ "alchemy-sdk": "^2.9.1", "bn.js": "^5.2.1", "dotenv": "^16.3.1", - "ethers": "^6.6.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", "truffle": "^5.10.0", "truffle-plugin-verify": "^0.6.3", diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 58e6bcc..048334d 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -1,8 +1,9 @@ require('dotenv').config() -const { Network, Alchemy } = require('alchemy-sdk'); -const ethers = require('ethers'); +// https://docs.alchemy.com/reference/alchemy-sdk-api-surface-overview#api-surface +const { Network, Alchemy, Contract, Utils, Wallet } = require('alchemy-sdk'); const VRFD20ContractBuilt = require("../build/contracts/VRFD20.json"); +// https://www.npmjs.com/package/alchemy-sdk const config = { apiKey: process.env.ALCHEMY_API_KEY, network: Network.ETH_SEPOLIA, @@ -11,45 +12,63 @@ const config = { const alchemyProvider = new Alchemy(config); // console.log('alchemyProvider', alchemyProvider); +// Listen to all new pending transactions +// Note: Alchemy wraps ethers API +// https://docs.alchemy.com/reference/alchemy-sdk-api-surface-overview#alchemy-websockets +// https://docs.ethers.org/v6/api/providers/#WebSocketProvider +alchemyProvider.ws.on( + { + method: "alchemy_pendingTransactions", + fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" + }, + (res) => console.log('detected pending tx from account:', res), +); + // Signer -const signer = new ethers.Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); -// console.log('signer', signer); +const signer = new Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); +console.log('signer', signer); // Contract const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; -const VRFD20Contract = new ethers.Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); -// console.log('VRFD20Contract', VRFD20Contract); +// https://docs.ethers.org/v5/api/contract/example/#example-erc-20-contract--connecting-to-a-contract +const VRFD20ContractRW = new Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); +console.log('VRFD20ContractRW', VRFD20ContractRW); + +// VRFD20ContractRW.on('DiceRolled', +// (res) => console.log('detected DiceRolled:', res)); + +// VRFD20ContractRW.on('DiceLanded', +// (res) => console.log('detected DiceLanded:', res)); // Example of using the call method const main = async () => { // Get the latest block const latestBlock = await alchemyProvider.core.getBlockNumber(); console.log('latestBlock', latestBlock); + + const ethersProvider = await alchemyProvider.config.getProvider(); + console.log(ethersProvider.formatter); + + // Interact with VRFD20 + const s_owner = await VRFD20ContractRW.s_owner(); + console.log("The s_owner is: ", s_owner); + + // let gasLimit = await VRFD20ContractRW.estimateGas.rollDice(signer.address); + const overrides = { + // gasLimit: gasLimit, + gasLimit: 600000, + gasPrice: 100000, + }; + // Important: Must have added the latest VRFD20 contract as an approved consumer + // contract so it can use the subscription balance when requesting randomness + // https://vrf.chain.link/ + // tx 0xc1ccfd1ea081c846fa3912cb1f610c23fab3ef3ddc5151cea6fa8bd2297e9b84 + const requestId = await VRFD20ContractRW.rollDice(signer.address, overrides); + console.log("The requestId is: ", requestId.value.toString()); + + const valueRolled = await VRFD20ContractRW + .getRolledValueForPlayer(signer.address); + console.log(`The valueRolled by ${signer.address} is: `, valueRolled); }; main(); - -// https://docs.alchemy.com/docs/interacting-with-a-smart-contract - -// // Provider -// // https://docs.ethers.org/v6/api/providers/#WebSocketProvider -// const alchemyProvider = new ethers.AlchemyProvider( -// // _network: 11155111, -// // url=process.env.CHAINLINK_SEPOLIA_ENDPOINT, -// _network=Network.ETH_SEPOLIA, -// // "eth-sepolia", -// process.env.ALCHEMY_API_KEY -// ); - -// // Listen to all new pending transactions -// alchemy.ws.on( -// { -// method: "alchemy_pendingTransactions", -// fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" -// }, -// (res) => console.log('detected pending tx from account:', res), -// ); - - // // Interact with VRFD20 - // const s_owner = await VRFD20Contract.s_owner(); - // console.log("The s_owner is: ", s_owner); From a7a79717ab9278c9cd8c940103c3ae15da15662e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 2 Jul 2023 14:00:06 +1000 Subject: [PATCH 48/58] wait a few blocks before get rolled value for player --- dapps/evm2/flipper/scripts/demo.js | 38 +++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 048334d..7486e3c 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -32,7 +32,7 @@ console.log('signer', signer); const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; // https://docs.ethers.org/v5/api/contract/example/#example-erc-20-contract--connecting-to-a-contract const VRFD20ContractRW = new Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); -console.log('VRFD20ContractRW', VRFD20ContractRW); +// console.log('VRFD20ContractRW', VRFD20ContractRW); // VRFD20ContractRW.on('DiceRolled', // (res) => console.log('detected DiceRolled:', res)); @@ -40,14 +40,27 @@ console.log('VRFD20ContractRW', VRFD20ContractRW); // VRFD20ContractRW.on('DiceLanded', // (res) => console.log('detected DiceLanded:', res)); -// Example of using the call method -const main = async () => { +const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => { + setTimeout(() => { + cb(); + resolve(); + }, timeout); +}); + +const getRolledValueForPlayer = async () => { // Get the latest block - const latestBlock = await alchemyProvider.core.getBlockNumber(); + let latestBlock = await alchemyProvider.core.getBlockNumber(); console.log('latestBlock', latestBlock); + const valueRolled = await VRFD20ContractRW + .getRolledValueForPlayer(signer.address); + console.log(`The valueRolled by ${signer.address} is: `, valueRolled); +} + +// Example of using the call method +const main = async () => { const ethersProvider = await alchemyProvider.config.getProvider(); - console.log(ethersProvider.formatter); + // console.log('ethersProvider: ', ethersProvider.formatter); // Interact with VRFD20 const s_owner = await VRFD20ContractRW.s_owner(); @@ -66,9 +79,18 @@ const main = async () => { const requestId = await VRFD20ContractRW.rollDice(signer.address, overrides); console.log("The requestId is: ", requestId.value.toString()); - const valueRolled = await VRFD20ContractRW - .getRolledValueForPlayer(signer.address); - console.log(`The valueRolled by ${signer.address} is: `, valueRolled); + // Get the latest block + let latestBlock = await alchemyProvider.core.getBlockNumber(); + console.log('latestBlock', latestBlock); + + // Wait a few blocks before getting the rolled value for a player + await setAsyncTimeout(async () => { + console.log('getRolledValueForPlayer'); + await getRolledValueForPlayer(); + }, 60000); + }; + + main(); From 79af1501de1b8fbaa32670182f95d6b2442b56a9 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 2 Jul 2023 14:01:22 +1000 Subject: [PATCH 49/58] show current error --- dapps/evm2/flipper/scripts/demo.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 7486e3c..5c30fe5 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -86,6 +86,8 @@ const main = async () => { // Wait a few blocks before getting the rolled value for a player await setAsyncTimeout(async () => { console.log('getRolledValueForPlayer'); + + // Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Dice not rolled" await getRolledValueForPlayer(); }, 60000); From 991b0cd20c7dffd16a13ab4c55c62cdde635e980 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Sun, 2 Jul 2023 22:52:41 +1000 Subject: [PATCH 50/58] wip --- .../flipper/scripts/demo-moonbase-ethers.js | 119 ++++++++++++++++++ dapps/evm2/flipper/scripts/demo.js | 7 +- dapps/evm2/flipper/scripts/package.json | 3 +- 3 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 dapps/evm2/flipper/scripts/demo-moonbase-ethers.js diff --git a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js new file mode 100644 index 0000000..c38d2e4 --- /dev/null +++ b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js @@ -0,0 +1,119 @@ +require('dotenv').config({ path: '../.env'}) +const ethers = require('ethers'); +const { Wallet } = require('ethers'); +const BN = require('bn.js'); + +// https://docs.moonbeam.network/builders/build/eth-api/libraries/ethersjs/ +const providerRPCMoonbaseAlphaConfig = { + moonbase: { + name: 'moonbase-alpha', + rpc: 'https://rpc.api.moonbase.moonbeam.network', + chainId: 1287, // 0x507 in hex, + }, +}; +// Note: ethers v6.6.2 not yet supported by Moonbase Alpha, use v5 +// https://docs.ethers.org/v5/api/providers/#WebSocketProvider +// so use `ethers.providers.JsonRpcProvider` instead of +// `ethers.JsonRpcProvider` +// const providerMoonbaseAlphaRPC = new ethers.providers.JsonRpcProvider( +// providerRPCMoonbaseAlphaConfig.moonbase.rpc, +// { +// chainId: providerRPCMoonbaseAlphaConfig.moonbase.chainId, +// name: providerRPCMoonbaseAlphaConfig.moonbase.name, +// } +// ); +// console.log('moonbase alpha provider RPC: ', providerMoonbaseAlphaRPC); + +const providerMoonbaseAlphaWS = new ethers.providers.WebSocketProvider( + // process.env.MOONBASE_BLASTAPI_ENDPOINT, // need auth for this endpoint + "wss://moonbeam-alpha.api.onfinality.io/public-ws", + { + name: "moonbase-alphanet", // or "moonbase-alpha" + chainId: 1287, // 0x507 in hex, + }, +); +console.log('moonbase alpha provider WS: ', providerMoonbaseAlphaWS); + +// Signer +const signer = new Wallet(process.env.MOONBASE_PRIVATE_KEY, providerMoonbaseAlphaWS); +console.log('signer', signer); + +const RandomNumberContractBuilt = require('../build/contracts/RandomNumber.json'); + +const main = async () => { + const contractAddressMoonbaseAlpha = '0x4027755C05514421fe00f4Fde0bD3F8475ce8A6b'; + const randomNumberInstance = new ethers.Contract( + contractAddressMoonbaseAlpha, RandomNumberContractBuilt.abi, signer); + console.log('randomNumberInstance: ', randomNumberInstance); + const fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); + console.log('fulfillmentFee: ', fulfillmentFee.toString()); + console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); + + console.log('x: ', ethers.utils.formatEther(fulfillmentFee)); + // console.log('accounts', accounts); + + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + refundAddress = await randomNumberInstance.requestRandomness( + roller, + { + from: signer.address, + gasLimit: 600000, + value: fulfillmentFee + } + ); + console.log('refundAddress: ', refundAddress); + + const requestId = await randomNumberInstance.requestId.call(); + console.log('requestId: ', requestId.toString()); + // Check status of request id from the randomness precompile + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + const requestStatus = await randomNumberInstance.getRequestStatus.call(); + console.log('requestStatus: ', requestStatus.toString()); + + // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.VRF_BLOCKS_DELAY.call(); + console.log('MIN_VRF_BLOCKS_DELAY: ', MIN_VRF_BLOCKS_DELAY); + + let currentBlockNumber = await providerMoonbaseAlphaWS.getBlockNumber(); + console.log('currentBlockNumber: ', currentBlockNumber.toString()); + + + // assert.equal(requestStatus, 1, 'should still be pending'); // where 1 in enum is 'PENDING' + // evm_mine not defined, since can only do on Ganache not live testnet + // for (i=0; i { // Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Dice not rolled" await getRolledValueForPlayer(); }, 60000); - }; - - main(); diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json index c6a0a41..a01cac2 100644 --- a/dapps/evm2/flipper/scripts/package.json +++ b/dapps/evm2/flipper/scripts/package.json @@ -10,8 +10,9 @@ "license": "MIT", "dependencies": { "alchemy-sdk": "^2.9.1", + "bn.js": "^5.2.1", "dotenv": "^16.3.1", - "ethers": "^6.6.1", + "ethers": "^5.6.1", "web3": "^4.0.2" } } From 4da18cffc251db75fd8d37f92684dc02f2740ae4 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 3 Jul 2023 11:52:58 +1000 Subject: [PATCH 51/58] insufficient funds for gas * price + value --- .../flipper/scripts/demo-moonbase-ethers.js | 78 +++++++++---------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js index c38d2e4..bac8c9b 100644 --- a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js +++ b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js @@ -4,17 +4,17 @@ const { Wallet } = require('ethers'); const BN = require('bn.js'); // https://docs.moonbeam.network/builders/build/eth-api/libraries/ethersjs/ -const providerRPCMoonbaseAlphaConfig = { - moonbase: { - name: 'moonbase-alpha', - rpc: 'https://rpc.api.moonbase.moonbeam.network', - chainId: 1287, // 0x507 in hex, - }, -}; // Note: ethers v6.6.2 not yet supported by Moonbase Alpha, use v5 // https://docs.ethers.org/v5/api/providers/#WebSocketProvider // so use `ethers.providers.JsonRpcProvider` instead of // `ethers.JsonRpcProvider` +// const providerRPCMoonbaseAlphaConfig = { +// moonbase: { +// name: 'moonbase-alpha', +// rpc: 'https://rpc.api.moonbase.moonbeam.network', +// chainId: 1287, // 0x507 in hex, +// }, +// }; // const providerMoonbaseAlphaRPC = new ethers.providers.JsonRpcProvider( // providerRPCMoonbaseAlphaConfig.moonbase.rpc, // { @@ -40,6 +40,13 @@ console.log('signer', signer); const RandomNumberContractBuilt = require('../build/contracts/RandomNumber.json'); +const setAsyncTimeout = (cb, timeout = 0) => new Promise(resolve => { + setTimeout(() => { + cb(); + resolve(); + }, timeout); +}); + const main = async () => { const contractAddressMoonbaseAlpha = '0x4027755C05514421fe00f4Fde0bD3F8475ce8A6b'; const randomNumberInstance = new ethers.Contract( @@ -67,7 +74,7 @@ const main = async () => { console.log('requestId: ', requestId.toString()); // Check status of request id from the randomness precompile // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - const requestStatus = await randomNumberInstance.getRequestStatus.call(); + let requestStatus = await randomNumberInstance.getRequestStatus.call(); console.log('requestStatus: ', requestStatus.toString()); // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY @@ -79,41 +86,28 @@ const main = async () => { let currentBlockNumber = await providerMoonbaseAlphaWS.getBlockNumber(); console.log('currentBlockNumber: ', currentBlockNumber.toString()); - // assert.equal(requestStatus, 1, 'should still be pending'); // where 1 in enum is 'PENDING' - // evm_mine not defined, since can only do on Ganache not live testnet - // for (i=0; i { + console.log('fulfillRequest'); + + // Error: insufficient funds for gas * price + value + await randomNumberInstance.fulfillRequest( + { + from: signer.address, + gasLimit: 600000, + gasPrice: 600000, + } + ); + }, 10000); + + // requestStatus = await randomNumberInstance.getRequestStatus.call(); + // console.log('requestStatus: ', requestStatus.toString()); + + // const random = await randomNumberInstance.random.call(); + // console.log('random number: ', random[0]); } main(); From 78c4c525c43bb7a08d64ffa7e82fd26ec661b74d Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 3 Jul 2023 13:28:36 +1000 Subject: [PATCH 52/58] crashes on requestRandomness. fixes error insufficient funds for intrinsic transaction cost --- .../flipper/scripts/demo-moonbase-ethers.js | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js index bac8c9b..f29e5ff 100644 --- a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js +++ b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js @@ -57,18 +57,20 @@ const main = async () => { console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); console.log('x: ', ethers.utils.formatEther(fulfillmentFee)); - // console.log('accounts', accounts); let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; - refundAddress = await randomNumberInstance.requestRandomness( + let res = await randomNumberInstance.requestRandomness( roller, { from: signer.address, gasLimit: 600000, + maxPriorityFeePerGas: 2, value: fulfillmentFee } ); - console.log('refundAddress: ', refundAddress); + console.log('res: ', await res); + // debugging receipt + console.log('res: ', await res.wait()); const requestId = await randomNumberInstance.requestId.call(); console.log('requestId: ', requestId.toString()); @@ -93,14 +95,19 @@ const main = async () => { await setAsyncTimeout(async () => { console.log('fulfillRequest'); - // Error: insufficient funds for gas * price + value - await randomNumberInstance.fulfillRequest( - { - from: signer.address, - gasLimit: 600000, - gasPrice: 600000, - } - ); + try { + // Error: insufficient funds for gas * price + value + await randomNumberInstance.fulfillRequest( + { + from: signer.address, + gasLimit: 600000, + // gasPrice: 600000, + maxPriorityFeePerGas: 2, + } + ); + } catch (e) { + console.log('fulfillRequest error: ', e); + } }, 10000); // requestStatus = await randomNumberInstance.getRequestStatus.call(); From 74eca77c2f55ce8cb668f5e63a39d3b0efc9f795 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Mon, 3 Jul 2023 16:47:13 +1000 Subject: [PATCH 53/58] wip --- dapps/evm2/flipper/README.md | 11 ++++++++-- .../flipper/migrations/2_deploy_contracts.js | 4 ++++ .../flipper/scripts/demo-moonbase-ethers.js | 22 ++++++++----------- dapps/evm2/flipper/scripts/demo.js | 5 +++-- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 875f295..03843c4 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -136,6 +136,7 @@ Verifying contracts on sourcify * Verify Contract - Chainlink VRF ``` +# cd flipper # truffle run verify VRFD20 --network sepolia Verifying contracts on etherscan @@ -149,8 +150,14 @@ Verifying contracts on sourcify * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription - * Prepay Subscription https://vrf.chain.link/ - + * Go to https://vrf.chain.link/sepolia/new. + * **Important** Must be in a private browser tab to clear cache + * https://vrf.chain.link/sepolia/3350 + * After clicking "Add Consume" and adding a consumer address in this [tx](https://sepolia.etherscan.io/tx/0x4bfc7fe73fd20f524daf07875502f2d1e7d65032c71a0fe736d3a8ddc6cb388f) it said `Important: Your consumer contract must use the Subscription ID 3350 in the VRF request to make use of these funds.` + * Go to https://vrf.chain.link/sepolia/3350, click "Actions" > "Fund Subscription" to prepay subscription. [tx](https://sepolia.etherscan.io/tx/0xf2a34026f513c29f6e8a12f5b6ac7d7bae2adc619e09dcc6b011c1a6c4f89350) + + * NOTE: + * I had already created a subscription id https://vrf.chain.link/sepolia/3217 to deploy through migrations file but had not added the consumer contract of it deployed, which i later did at https://sepolia.etherscan.io/tx/0xc689e64aca1c531fab582bbbbd86e835bb465c227d6068e001f1692f30eab3f6, and funded it in this tx https://sepolia.etherscan.io/tx/0x23e4464e74fbfb30dfd3a65042e86f37d915e143b63105f5391bcd23d45d93f6, so this is the one to use since that's the subscription id passed to the constructor when deployed * Run * node ./scripts/demo.js diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 8672f3a..dc1ce3c 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -29,6 +29,10 @@ module.exports = async function (deployer) { console.log('providerInstance: ', providerInstance); web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); + // **Important** It is necessary to add the deployed address as the + // consumer address and fund the subscription id otherwise it will not + // be possible to roll the dice and you will get error + // `CALL_EXCEPTION Dice not rolled` or similar const subscriptionId = 3217; // https://vrf.chain.link/ // wants 128620983229604640 wei const value = web3.utils.toWei('0.000001', 'ether'); diff --git a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js index f29e5ff..334498e 100644 --- a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js +++ b/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js @@ -95,19 +95,15 @@ const main = async () => { await setAsyncTimeout(async () => { console.log('fulfillRequest'); - try { - // Error: insufficient funds for gas * price + value - await randomNumberInstance.fulfillRequest( - { - from: signer.address, - gasLimit: 600000, - // gasPrice: 600000, - maxPriorityFeePerGas: 2, - } - ); - } catch (e) { - console.log('fulfillRequest error: ', e); - } + // Error: insufficient funds for gas * price + value + await randomNumberInstance.fulfillRequest( + { + from: signer.address, + gasLimit: 600000, + // gasPrice: 600000, + maxPriorityFeePerGas: 2, + } + ); }, 10000); // requestStatus = await randomNumberInstance.getRequestStatus.call(); diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 4e17ae3..36797d6 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -68,9 +68,11 @@ const main = async () => { // let gasLimit = await VRFD20ContractRW.estimateGas.rollDice(signer.address); const overrides = { + from: signer.address, // gasLimit: gasLimit, gasLimit: 600000, - gasPrice: 100000, + // gasPrice: 100000, + maxPriorityFeePerGas: 2, }; // Important: Must have added the latest VRFD20 contract as an approved consumer // contract so it can use the subscription balance when requesting randomness @@ -87,7 +89,6 @@ const main = async () => { await setAsyncTimeout(async () => { console.log('getRolledValueForPlayer'); - // Error: call revert exception; VM Exception while processing transaction: reverted with reason string "Dice not rolled" await getRolledValueForPlayer(); }, 60000); }; From 4e136dc9f6d314437cd7a97983533f3dcfc3860d Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 6 Jul 2023 09:46:53 +1000 Subject: [PATCH 54/58] fix vrf --- dapps/evm2/flipper/README.md | 10 ++++++++-- dapps/evm2/flipper/migrations/2_deploy_contracts.js | 2 +- dapps/evm2/flipper/scripts/demo.js | 11 ++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 03843c4..260eeda 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -154,10 +154,13 @@ Verifying contracts on sourcify * **Important** Must be in a private browser tab to clear cache * https://vrf.chain.link/sepolia/3350 * After clicking "Add Consume" and adding a consumer address in this [tx](https://sepolia.etherscan.io/tx/0x4bfc7fe73fd20f524daf07875502f2d1e7d65032c71a0fe736d3a8ddc6cb388f) it said `Important: Your consumer contract must use the Subscription ID 3350 in the VRF request to make use of these funds.` - * Go to https://vrf.chain.link/sepolia/3350, click "Actions" > "Fund Subscription" to prepay subscription. [tx](https://sepolia.etherscan.io/tx/0xf2a34026f513c29f6e8a12f5b6ac7d7bae2adc619e09dcc6b011c1a6c4f89350) + * Go to https://vrf.chain.link/sepolia/3350, click "Actions" > "Fund Subscription" to prepay subscription. [tx](https://sepolia.etherscan.io/tx/0xf2a34026f513c29f6e8a12f5b6ac7d7bae2adc619e09dcc6b011c1a6c4f89350), relates to contract deployed to 0x9912FEa426655B1d723ADFFa5dbD915C78198c49 with that subscription id 3350 * NOTE: * I had already created a subscription id https://vrf.chain.link/sepolia/3217 to deploy through migrations file but had not added the consumer contract of it deployed, which i later did at https://sepolia.etherscan.io/tx/0xc689e64aca1c531fab582bbbbd86e835bb465c227d6068e001f1692f30eab3f6, and funded it in this tx https://sepolia.etherscan.io/tx/0x23e4464e74fbfb30dfd3a65042e86f37d915e143b63105f5391bcd23d45d93f6, so this is the one to use since that's the subscription id passed to the constructor when deployed + * Fix + * After being unsuccessful in trying to generate a random number with subscription id 3217 and 3350, I got help in #vrf room of Chainlink on Discord from Lucas Archangelo who suggested to use the existing subscription id and redeploy and add the new contract address as the consumer. So I deployed VRFD20 to 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e that has tx hash https://dashboard.tenderly.co/tx/sepolia/0x0122f8b4efb1f66dea8482edf7d4e9089946cd13a60559504a4dc63fdd0a727b?trace=0.0, so then i went to https://vrf.chain.link/sepolia/3350, and added new consumer address 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e in this tx 0x397c8aedab55e475d27b87de8d63cc1f866b007698f94cea49ab2ae75f016104, then i imported all the contracts into Remix to access that contract and verified that i was interacting with that new contract. then made transaction rollDice passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter in this tx https://sepolia.etherscan.io/tx/0x558a0567c5c71ec378e6919d75d8cd02b60e97c6c87205f77f5146233a58affa, then finally in Remix i called getRolledValueForPlayer passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter, and that output the following in Remix 0: uint256: 8, so it successfully generated the random number 8. I also modified ./scripts/demo.js to load that new address and to not run rollDice since we'd already done that, and it also returned `8`. + * Run * node ./scripts/demo.js @@ -168,6 +171,8 @@ Verifying contracts on sourcify * Receipt https://sepolia.etherscan.io/tx/0xcc2cd9edf90e0f3351f3398b7013a7259c0acc7cfbfc38454192324fcfdb7d6a * Reference v2 contract (not implemented): https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2Consumer.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js +* Debugging + * Details of each tx https://dashboard.tenderly.co/tx/sepolia/0x???? * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me @@ -196,7 +201,8 @@ Verifying contracts on sourcify * https://docs.alchemy.com/docs/ethers-js-provider * https://docs.alchemy.com/docs/interacting-with-a-smart-contract * Ethers - * https://docs.ethers.org/v6/api/providers/#WebSocketProvider + * v5 https://docs.ethers.org/v5/api/utils/hdnode/ + * v6 https://docs.ethers.org/v6/api/providers/#WebSocketProvider * XCM * https://docs.moonbeam.network/builders/interoperability/xcm/overview/ * https://github.com/AstarNetwork/ink-xvm-sdk/tree/main diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index dc1ce3c..4182b16 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -33,7 +33,7 @@ module.exports = async function (deployer) { // consumer address and fund the subscription id otherwise it will not // be possible to roll the dice and you will get error // `CALL_EXCEPTION Dice not rolled` or similar - const subscriptionId = 3217; // https://vrf.chain.link/ + const subscriptionId = 3350; // https://vrf.chain.link/ // wants 128620983229604640 wei const value = web3.utils.toWei('0.000001', 'ether'); const amount = new BN(value, 10); diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js index 36797d6..b7489ee 100644 --- a/dapps/evm2/flipper/scripts/demo.js +++ b/dapps/evm2/flipper/scripts/demo.js @@ -1,4 +1,8 @@ -require('dotenv').config({ path: '../.env'}) +const dotenv = require('dotenv'); +// note: change the below to '../.env' if run from in the ./scripts directory +// otherwise get error `TypeError: Cannot read properties of undefined (reading 'toHexString')` +// since unable to load variabels from .env file +dotenv.config({path : './.env'}); // https://docs.alchemy.com/reference/alchemy-sdk-api-surface-overview#api-surface const { Network, Alchemy, Contract, Utils, Wallet } = require('alchemy-sdk'); const VRFD20ContractBuilt = require("../build/contracts/VRFD20.json"); @@ -29,7 +33,8 @@ const signer = new Wallet(process.env.MOONBASE_PRIVATE_KEY, alchemyProvider); console.log('signer', signer); // Contract -const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; +// const VRFD20DeployedAtAddress = '0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6'; +const VRFD20DeployedAtAddress = '0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e'; // https://docs.ethers.org/v5/api/contract/example/#example-erc-20-contract--connecting-to-a-contract const VRFD20ContractRW = new Contract(VRFD20DeployedAtAddress, VRFD20ContractBuilt.abi, signer); // console.log('VRFD20ContractRW', VRFD20ContractRW); @@ -54,7 +59,7 @@ const getRolledValueForPlayer = async () => { const valueRolled = await VRFD20ContractRW .getRolledValueForPlayer(signer.address); - console.log(`The valueRolled by ${signer.address} is: `, valueRolled); + console.log(`The valueRolled by ${signer.address} is: `, valueRolled.toString()); } // Example of using the call method From 5dde11bcd6d8b6b4d2d94d5d5b790a041655e68d Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 6 Jul 2023 10:12:20 +1000 Subject: [PATCH 55/58] wip --- README.md | 7 ++++++- docker/quickstart-randomness-vrfd20.sh | 27 ++++++++++++++++++++++++++ docker/quickstart-randomness.sh | 16 --------------- package-lock.json | 17 ---------------- package.json | 5 ----- 5 files changed, 33 insertions(+), 39 deletions(-) create mode 100755 docker/quickstart-randomness-vrfd20.sh delete mode 100755 docker/quickstart-randomness.sh delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/README.md b/README.md index a27d4f0..bd187c1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### Smart Contract in ink! +### Smart Contracts using XCM ## Table of Contents @@ -10,6 +10,7 @@ * [**Quickstart** Build & Upload ink! Rust "Basic Contract Caller" Smart Contract to Local Testnet (using Cargo Contract)](#quick-basic-contract-caller) * [**Quickstart** Build & Upload ink! Rust "IPSP22" Smart Contract to Local Testnet (using Cargo Contract)](#quick-ipsp22) * [**Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract)](#quick-unnamed) + * [Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia (using Truffle)](#vrfd20) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#build-upload) * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Swanky CLI)](#build-upload-swanky) * Interact @@ -192,6 +193,10 @@ docker exec -it ink /app/docker/quickstart.sh ./docker/quickstart-unnamed.sh ``` +### Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia Testnet (using Truffle) + +* Follow the instructions in the [VRF20 example README](./dapps/evm2/flipper/README.md) + ### Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract) * Create Rust project with template diff --git a/docker/quickstart-randomness-vrfd20.sh b/docker/quickstart-randomness-vrfd20.sh new file mode 100755 index 0000000..760ab96 --- /dev/null +++ b/docker/quickstart-randomness-vrfd20.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +trap "echo; exit" INT +trap "echo; exit" HUP + +# if they call this script from project root or from within docker/ folder then +# in both cases the PARENT_DIR will refer to the project root where the .env file is. +PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) + +# TODO - install all necessary dependencies as mentioned in the dapps/evm2/flipper/README.md + +# echo "Compiling contracts..." +# cd $PARENT_DIR/dapps/evm2/flipper +# PROJECT_ROOT=$PARENT_DIR/dapps/evm2/flipper +# truffle compile --compile-all + +# echo "Migrating contracts..." +# truffle migrate --reset --compile-all --network moonbase + +# TODO - get the deployed contract address from the output +# and pass that as a variable to the demo.js script +# (which gets the contract at that address and then call `rollDice` +# and waits some blocks before getting the random number) + +# echo "Rolling the dice and obtaining the random number" +# cd dapps/evm2/flipper +# node ./scripts/demo.js diff --git a/docker/quickstart-randomness.sh b/docker/quickstart-randomness.sh deleted file mode 100755 index 67429ff..0000000 --- a/docker/quickstart-randomness.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -trap "echo; exit" INT -trap "echo; exit" HUP - -# if they call this script from project root or from within docker/ folder then -# in both cases the PARENT_DIR will refer to the project root where the .env file is. -PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) - -echo "Compiling contracts..." -cd $PARENT_DIR/dapps/evm2/flipper -PROJECT_ROOT=$PARENT_DIR/dapps/evm2/flipper -truffle compile --compile-all - -echo "Migrating contracts..." -truffle migrate --reset --compile-all --network moonbase diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index a59c8c1..0000000 --- a/package-lock.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "InkTest", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "bn.js": "^5.2.1" - } - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 2b8c823..0000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "bn.js": "^5.2.1" - } -} From 0d6b01a92a4fdc1fccef0fb6726d5944376b2243 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 6 Jul 2023 10:43:38 +1000 Subject: [PATCH 56/58] split flipper from moonbase vrf example --- README.md | 19 +- dapps/evm2/flipper/README.md | 9 +- ...demo-chainlink-vrf-on-ethereum-sepolia.js} | 0 ...=> demo-moonbeam-vrf-on-moonbase-alpha.js} | 0 dapps/evm2/flipper/scripts/package.json | 2 +- dapps/evm2/flipper/test/test_Flipper.js | 150 +--------------- dapps/evm2/flipper/test/test_MoonbaseVRF.js | 165 ++++++++++++++++++ ...fd20.sh => quickstart-chainlink-vrfd20.sh} | 4 +- docker/quickstart-moonbeam-vrf-precompile.sh | 27 +++ 9 files changed, 212 insertions(+), 164 deletions(-) rename dapps/evm2/flipper/scripts/{demo.js => demo-chainlink-vrf-on-ethereum-sepolia.js} (100%) rename dapps/evm2/flipper/scripts/{demo-moonbase-ethers.js => demo-moonbeam-vrf-on-moonbase-alpha.js} (100%) create mode 100644 dapps/evm2/flipper/test/test_MoonbaseVRF.js rename docker/{quickstart-randomness-vrfd20.sh => quickstart-chainlink-vrfd20.sh} (85%) create mode 100755 docker/quickstart-moonbeam-vrf-precompile.sh diff --git a/README.md b/README.md index bd187c1..27f29dc 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,14 @@ * [Setup Docker Container](#setup-container) * [Run Cargo Contracts Node in Docker Container](#run-cargo-contracts-node) * Build & Upload - * [**Quickstart** Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#quick-build-upload) - * [**Quickstart** Build & Upload ink! Rust "Basic Contract Caller" Smart Contract to Local Testnet (using Cargo Contract)](#quick-basic-contract-caller) - * [**Quickstart** Build & Upload ink! Rust "IPSP22" Smart Contract to Local Testnet (using Cargo Contract)](#quick-ipsp22) - * [**Quickstart** Build & Upload ink! Rust "Unnamed" Smart Contract to Local Testnet (using Cargo Contract)](#quick-unnamed) - * [Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia (using Truffle)](#vrfd20) - * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract)](#build-upload) - * [Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Swanky CLI)](#build-upload-swanky) + * [**Quickstart** Build & Upload "Flipper" ink! Rust Smart Contract to Local Testnet (using Cargo Contract)](#quick-build-upload) + * [**Quickstart** Build & Upload "Basic Contract Caller" ink! Rust Smart Contract to Local Testnet (using Cargo Contract)](#quick-basic-contract-caller) + * [**Quickstart** Build & Upload "IPSP22" ink! Rust Smart Contract to Local Testnet (using Cargo Contract)](#quick-ipsp22) + * [**Quickstart** Build & Upload "Unnamed" ink! Rust Smart Contract to Local Testnet (using Cargo Contract)](#quick-unnamed) + * [Build & Upload Moonbeam VRF Randomness Precompile Solidity Smart Contract to Moonbase Alpha Testnet (using Truffle)](#moonbase-vrf) + * [Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia Testnet (using Truffle)](#vrfd20) + * [Build & Upload "Flipper" ink! Rust Smart Contract to Local Testnet (using Cargo Contract)](#build-upload) + * [Build & Upload "Flipper" ink! Rust Smart Contract to Local Testnet (using Swanky CLI)](#build-upload-swanky) * Interact * [Interact with ink! Python Smart Contract](#interact-python) * [Interact with ink! Rust Flipper Smart Contract using Polkadot.js API](#interact-polkadot-js-flipper) @@ -193,6 +194,10 @@ docker exec -it ink /app/docker/quickstart.sh ./docker/quickstart-unnamed.sh ``` +### Build & Upload Moonbeam VRF Randomness Precompile Solidity Smart Contract to Moonbase Alpha Testnet (using Truffle) + +* Follow the instructions in the [VRF example README](./dapps/evm2/flipper/README.md) + ### Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia Testnet (using Truffle) * Follow the instructions in the [VRF20 example README](./dapps/evm2/flipper/README.md) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 260eeda..2e67d67 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -112,8 +112,7 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Migrate full `truffle migrate --reset --compile-all --network sepolia` * Test - * **Important:** It is necessary to first comment-out the code that is **not being compiled** in 2_deploy_contracts.j - * `truffle test ./test/test_Flipper.js --verbose-rpc --network moonbase` + * `truffle test ./test/test_MoonbaseVRF.js --verbose-rpc --network moonbase` * `truffle test ./test/test_ChainlinkVRF.js --network sepolia` * Verify Contract - Moonbase Precompile @@ -159,10 +158,10 @@ Verifying contracts on sourcify * NOTE: * I had already created a subscription id https://vrf.chain.link/sepolia/3217 to deploy through migrations file but had not added the consumer contract of it deployed, which i later did at https://sepolia.etherscan.io/tx/0xc689e64aca1c531fab582bbbbd86e835bb465c227d6068e001f1692f30eab3f6, and funded it in this tx https://sepolia.etherscan.io/tx/0x23e4464e74fbfb30dfd3a65042e86f37d915e143b63105f5391bcd23d45d93f6, so this is the one to use since that's the subscription id passed to the constructor when deployed * Fix - * After being unsuccessful in trying to generate a random number with subscription id 3217 and 3350, I got help in #vrf room of Chainlink on Discord from Lucas Archangelo who suggested to use the existing subscription id and redeploy and add the new contract address as the consumer. So I deployed VRFD20 to 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e that has tx hash https://dashboard.tenderly.co/tx/sepolia/0x0122f8b4efb1f66dea8482edf7d4e9089946cd13a60559504a4dc63fdd0a727b?trace=0.0, so then i went to https://vrf.chain.link/sepolia/3350, and added new consumer address 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e in this tx 0x397c8aedab55e475d27b87de8d63cc1f866b007698f94cea49ab2ae75f016104, then i imported all the contracts into Remix to access that contract and verified that i was interacting with that new contract. then made transaction rollDice passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter in this tx https://sepolia.etherscan.io/tx/0x558a0567c5c71ec378e6919d75d8cd02b60e97c6c87205f77f5146233a58affa, then finally in Remix i called getRolledValueForPlayer passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter, and that output the following in Remix 0: uint256: 8, so it successfully generated the random number 8. I also modified ./scripts/demo.js to load that new address and to not run rollDice since we'd already done that, and it also returned `8`. + * After being unsuccessful in trying to generate a random number with subscription id 3217 and 3350, I got help in #vrf room of Chainlink on Discord from Lucas Archangelo who suggested to use the existing subscription id and redeploy and add the new contract address as the consumer. So I deployed VRFD20 to 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e that has tx hash https://dashboard.tenderly.co/tx/sepolia/0x0122f8b4efb1f66dea8482edf7d4e9089946cd13a60559504a4dc63fdd0a727b?trace=0.0, so then i went to https://vrf.chain.link/sepolia/3350, and added new consumer address 0xE265f9a30c72A78C4b89Fc2e2C60e9327704Fa5e in this tx 0x397c8aedab55e475d27b87de8d63cc1f866b007698f94cea49ab2ae75f016104, then i imported all the contracts into Remix to access that contract and verified that i was interacting with that new contract. then made transaction rollDice passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter in this tx https://sepolia.etherscan.io/tx/0x558a0567c5c71ec378e6919d75d8cd02b60e97c6c87205f77f5146233a58affa, then finally in Remix i called getRolledValueForPlayer passing my account address 0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 as a parameter, and that output the following in Remix 0: uint256: 8, so it successfully generated the random number 8. I also modified ./scripts/demo-chainlink-vrf-on-ethereum-sepolia.js to load that new address and to not run rollDice since we'd already done that, and it also returned `8`. * Run - * node ./scripts/demo.js + * node ./scripts/demo-chainlink-vrf-on-ethereum-sepolia.js * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 @@ -211,4 +210,4 @@ Verifying contracts on sourcify * Other * https://github.com/HCastano/urban-planning-in-the-paraverse-with-ink - * https://www.rob.tech/blog/hybrid-chains/ \ No newline at end of file + * https://www.rob.tech/blog/hybrid-chains/ diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js similarity index 100% rename from dapps/evm2/flipper/scripts/demo.js rename to dapps/evm2/flipper/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js diff --git a/dapps/evm2/flipper/scripts/demo-moonbase-ethers.js b/dapps/evm2/flipper/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js similarity index 100% rename from dapps/evm2/flipper/scripts/demo-moonbase-ethers.js rename to dapps/evm2/flipper/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json index a01cac2..11efcf1 100644 --- a/dapps/evm2/flipper/scripts/package.json +++ b/dapps/evm2/flipper/scripts/package.json @@ -2,7 +2,7 @@ "name": "flipper", "version": "1.0.0", "description": "", - "main": "demo.js", + "main": "demo-chainlink-vrf-on-ethereum-sepolia.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index 8102e21..cd262e5 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -3,86 +3,21 @@ const { Web3 } = require('web3'); const BN = require('bn.js'); // Uses Mocha and Ganache -const Randomness = artifacts.require("../build/contracts/Randomness"); -const RandomnessConsumer = artifacts.require("../build/contracts/RandomnessConsumer"); -const RandomNumber = artifacts.require("../contracts/lib/RandomNumber"); const Flipper = artifacts.require("../contracts/lib/Flipper"); console.log('test_Flipper'); let providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); console.log('providerInstance: ', providerInstance); -let web3 = new Web3(providerInstance); -// when using BlastAPI WSS endpoint I get error `TypeError: Cannot create property 'gasLimit' on string"` -// https://github.com/web3/web3.js/issues/3573 -console.log('web3.currentProvider: ', web3.currentProvider); -// Randomness.setProvider(providerInstance); -// RandomnessConsumer.setProvider(providerInstance); -// RandomNumber.setProvider(providerInstance); -// Flipper.setProvider(providerInstance); - -// advanceBlock = () => { -// return new Promise((resolve, reject) => { -// web3.currentProvider.send({ -// jsonrpc: '2.0', -// method: 'evm_mine', -// id: new Date().getTime() -// }, (err, result) => { -// console.log('result: ', result); -// console.log('err: ', err); -// if (err) { return reject(err) } -// const newBlockHash = web3.eth.getBlock('latest').hash; -// console.log('newBlockHash: ', newBlockHash); - -// return resolve(newBlockHash); -// }) -// }) -// } contract('Flipper', accounts => { console.log('accounts: ', accounts); - let randomnessInstance; - let randomNumberInstance; + let flipperInstance; - let fulfillmentFee; - let refundAddress; - let gas; - let gasLimit; - let gasPrice; - let currentBlockNumber; - let nextBlockNumber; - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 // https://docs.web3js.org/api/web3-utils/function/toWei - const requiredDeposit = Web3.utils.toWei('1', 'ether'); - const blockTimeout = 1000000; const initValue = false; beforeEach(async () => { console.log('beforeEach'); - randomnessInstance = await Randomness.at("0x0000000000000000000000000000000000000809"); - // console.log('randomnessInstance.address:', randomnessInstance.address); - - // RandomnessConsumer.link(randomnessInstance); - // RandomNumber.link(randomnessInstance); - - // gas = Web3.utils.toWei('1000000', 'wei'); - // gasLimit = Web3.utils.toWei('600000', 'wei'); - // gasPrice = Web3.utils.toWei('2000000', 'wei'); - // gas = Web3.utils.toHex(70000); - // gasLimit = Web3.utils.toHex(600000); // gwei - // gasPrice = Web3.utils.toHex(21000); - - // Create contract with 1 Ether (contract must be payable) - randomNumberInstance = await RandomNumber.deployed(); //.new({ from: accounts[0], value: requiredDeposit }); - // randomNumberInstance = await RandomNumber.new( - // { from: accounts[0], value: requiredDeposit, - // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, syncWithContext: true } - // ); - console.log('randomNumberInstance.address:', randomNumberInstance.address); - - // Flipper.link(randomnessInstance); - // Flipper.link(randomNumberInstance); - - // Deploy token contract flipperInstance = await Flipper.deployed(); //.new(initValue, { from: accounts[0] }); // console.log('flipperInstance.address:', flipperInstance.address); @@ -112,87 +47,4 @@ contract('Flipper', accounts => { console.log('error in flip: ', e); } }); - - it("requests randomness", async () => { - try { - fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); - console.log('fulfillmentFee: ', fulfillmentFee.toString()); - console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); - console.log('accounts', accounts); - - // console.log('web3.currentProvider: ', web3.currentProvider); - // do not use `.call` when doing state changes to blockchain - // gas = Web3.utils.toWei('1000000', 'wei'); - // gasLimit = Web3.utils.toWei('600000', 'wei'); - // gasPrice = Web3.utils.toWei('2000000', 'wei'); - gas = Web3.utils.toHex(150000); - gasLimit = Web3.utils.toHex(600000); - gasPrice = Web3.utils.toHex(21000); - let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; - refundAddress = await randomNumberInstance.requestRandomness(roller, { from: accounts[0], value: fulfillmentFee }); - // refundAddress = await randomNumberInstance.requestRandomness( - // { - // from: accounts[0], - // value: fulfillmentFee, - // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, - // syncWithContext: true - // } - // ); - // console.log('refundAddress: ', refundAddress); - - const requestId = await randomNumberInstance.requestId.call(); - console.log('requestId: ', requestId); - // Check status of request id from the randomness precompile - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 - const requestStatus = await randomNumberInstance.getRequestStatus.call(); - console.log('requestStatus: ', requestStatus.toString()); - - // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 - // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 - const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.VRF_BLOCKS_DELAY.call(); - console.log('MIN_VRF_BLOCKS_DELAY: ', MIN_VRF_BLOCKS_DELAY); - // let currentBlock = await web3.eth.getBlock("latest"); - currentBlockNumber = await web3.eth.getBlockNumber(); - console.log('currentBlockNumber: ', currentBlockNumber.toString()); - // remove 'n' character from end of blocknumber - currentBlockNumber = currentBlockNumber.toString().replace(/[^0-9.]/g, ''); - let firstBlockNumber = currentBlockNumber; - console.log('firstBlockNumber: ', firstBlockNumber); - assert.equal(requestStatus, 1, 'should still be pending'); // where 1 in enum is 'PENDING' - // evm_mine not defined, since can only do on Ganache not live testnet - // for (i=0; i { +// return new Promise((resolve, reject) => { +// web3.currentProvider.send({ +// jsonrpc: '2.0', +// method: 'evm_mine', +// id: new Date().getTime() +// }, (err, result) => { +// console.log('result: ', result); +// console.log('err: ', err); +// if (err) { return reject(err) } +// const newBlockHash = web3.eth.getBlock('latest').hash; +// console.log('newBlockHash: ', newBlockHash); + +// return resolve(newBlockHash); +// }) +// }) +// } + +contract('RandomNumber', accounts => { + console.log('accounts: ', accounts); + let randomnessInstance; + let randomNumberInstance; + let fulfillmentFee; + let refundAddress; + let gas; + let gasLimit; + let gasPrice; + let currentBlockNumber; + let nextBlockNumber; + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L17C43-L17C62 + // https://docs.web3js.org/api/web3-utils/function/toWei + const requiredDeposit = Web3.utils.toWei('1', 'ether'); + const blockTimeout = 1000000; + const initValue = false; + beforeEach(async () => { + console.log('beforeEach'); + randomnessInstance = await Randomness.at("0x0000000000000000000000000000000000000809"); + // console.log('randomnessInstance.address:', randomnessInstance.address); + + // RandomnessConsumer.link(randomnessInstance); + // RandomNumber.link(randomnessInstance); + + // gas = Web3.utils.toWei('1000000', 'wei'); + // gasLimit = Web3.utils.toWei('600000', 'wei'); + // gasPrice = Web3.utils.toWei('2000000', 'wei'); + // gas = Web3.utils.toHex(70000); + // gasLimit = Web3.utils.toHex(600000); // gwei + // gasPrice = Web3.utils.toHex(21000); + + // Create contract with 1 Ether (contract must be payable) + randomNumberInstance = await RandomNumber.deployed(); //.new({ from: accounts[0], value: requiredDeposit }); + // randomNumberInstance = await RandomNumber.new( + // { from: accounts[0], value: requiredDeposit, + // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, syncWithContext: true } + // ); + console.log('randomNumberInstance.address:', randomNumberInstance.address); + + // delay each test to simulate throttle that isn't available in truffle + // setTimeout(function(){ done(); }, 5000); + }); + + it("requests randomness", async () => { + try { + fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); + console.log('fulfillmentFee: ', fulfillmentFee.toString()); + console.log('fulfillmentFee is bn', BN.isBN(fulfillmentFee)); + console.log('accounts', accounts); + + // console.log('web3.currentProvider: ', web3.currentProvider); + // do not use `.call` when doing state changes to blockchain + // gas = Web3.utils.toWei('1000000', 'wei'); + // gasLimit = Web3.utils.toWei('600000', 'wei'); + // gasPrice = Web3.utils.toWei('2000000', 'wei'); + gas = Web3.utils.toHex(150000); + gasLimit = Web3.utils.toHex(600000); + gasPrice = Web3.utils.toHex(21000); + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + refundAddress = await randomNumberInstance.requestRandomness(roller, { from: accounts[0], value: fulfillmentFee }); + // refundAddress = await randomNumberInstance.requestRandomness( + // { + // from: accounts[0], + // value: fulfillmentFee, + // gas: gas, gasLimit: gasLimit, gasPrice: gasPrice, + // syncWithContext: true + // } + // ); + // console.log('refundAddress: ', refundAddress); + + const requestId = await randomNumberInstance.requestId.call(); + console.log('requestId: ', requestId); + // Check status of request id from the randomness precompile + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L96 + const requestStatus = await randomNumberInstance.getRequestStatus.call(); + console.log('requestStatus: ', requestStatus.toString()); + + // Wait for at least MIN_VRF_BLOCKS_DELAY but less than MAX_VRF_BLOCKS_DELAY + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L13 + // https://github.com/PureStake/moonbeam/blob/master/precompiles/randomness/Randomness.sol#L15 + const MIN_VRF_BLOCKS_DELAY = await randomNumberInstance.VRF_BLOCKS_DELAY.call(); + console.log('MIN_VRF_BLOCKS_DELAY: ', MIN_VRF_BLOCKS_DELAY); + // let currentBlock = await web3.eth.getBlock("latest"); + currentBlockNumber = await web3.eth.getBlockNumber(); + console.log('currentBlockNumber: ', currentBlockNumber.toString()); + // remove 'n' character from end of blocknumber + currentBlockNumber = currentBlockNumber.toString().replace(/[^0-9.]/g, ''); + let firstBlockNumber = currentBlockNumber; + console.log('firstBlockNumber: ', firstBlockNumber); + assert.equal(requestStatus, 1, 'should still be pending'); // where 1 in enum is 'PENDING' + // evm_mine not defined, since can only do on Ganache not live testnet + // for (i=0; i Date: Thu, 6 Jul 2023 10:56:26 +1000 Subject: [PATCH 57/58] update readme --- dapps/evm2/flipper/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 2e67d67..6defabc 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -170,6 +170,10 @@ Verifying contracts on sourcify * Receipt https://sepolia.etherscan.io/tx/0xcc2cd9edf90e0f3351f3398b7013a7259c0acc7cfbfc38454192324fcfdb7d6a * Reference v2 contract (not implemented): https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2Consumer.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js +* TODO + * allowing the owner of the VRFD20 contract to specify what block number the roll the dice relates to, since the block number will represent the start of each game + * allowing a random number to be rolled by a roller account calling rollDice multiple times each time there is a new game set by the owner of the VRFD20 + * Debugging * Details of each tx https://dashboard.tenderly.co/tx/sepolia/0x???? * Troubleshooting From b724f571c5baf2883e8e1ae93c6abdf6624388f0 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Thu, 6 Jul 2023 11:01:13 +1000 Subject: [PATCH 58/58] rename flipper folder to randomness --- README.md | 4 ++-- dapps/evm2/{flipper => randomness}/.env.example | 0 dapps/evm2/{flipper => randomness}/.gitignore | 0 dapps/evm2/{flipper => randomness}/LICENSE | 0 dapps/evm2/{flipper => randomness}/README.md | 8 ++++---- dapps/evm2/{flipper => randomness}/contracts/Flipper.sol | 0 .../evm2/{flipper => randomness}/contracts/Migrations.sol | 0 .../contracts/lib/RandomNumber.sol | 0 .../evm2/{flipper => randomness}/contracts/lib/VRFD20.sol | 0 .../contracts/precompiles/randomness/Randomness.sol | 0 .../precompiles/randomness/RandomnessConsumer.sol | 0 .../contracts/vrf/VRFConsumerBaseV2.sol | 0 .../vrf/interfaces/VRFCoordinatorV2Interface.sol | 0 .../migrations/1_initial_migration.js | 0 .../migrations/2_deploy_contracts.js | 0 dapps/evm2/{flipper => randomness}/package.json | 0 .../scripts/demo-chainlink-vrf-on-ethereum-sepolia.js | 0 .../scripts/demo-moonbeam-vrf-on-moonbase-alpha.js | 0 dapps/evm2/{flipper => randomness}/scripts/package.json | 0 .../{flipper => randomness}/test/test_ChainlinkVRF.js | 0 dapps/evm2/{flipper => randomness}/test/test_Flipper.js | 0 .../evm2/{flipper => randomness}/test/test_MoonbaseVRF.js | 0 dapps/evm2/{flipper => randomness}/truffle-box.json | 0 dapps/evm2/{flipper => randomness}/truffle-config.js | 0 dapps/evm2/{flipper => randomness}/tx.log | 4 ++-- docker/quickstart-chainlink-vrfd20.sh | 8 ++++---- docker/quickstart-moonbeam-vrf-precompile.sh | 8 ++++---- 27 files changed, 16 insertions(+), 16 deletions(-) rename dapps/evm2/{flipper => randomness}/.env.example (100%) rename dapps/evm2/{flipper => randomness}/.gitignore (100%) rename dapps/evm2/{flipper => randomness}/LICENSE (100%) rename dapps/evm2/{flipper => randomness}/README.md (98%) rename dapps/evm2/{flipper => randomness}/contracts/Flipper.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/Migrations.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/lib/RandomNumber.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/lib/VRFD20.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/precompiles/randomness/Randomness.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/precompiles/randomness/RandomnessConsumer.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/vrf/VRFConsumerBaseV2.sol (100%) rename dapps/evm2/{flipper => randomness}/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol (100%) rename dapps/evm2/{flipper => randomness}/migrations/1_initial_migration.js (100%) rename dapps/evm2/{flipper => randomness}/migrations/2_deploy_contracts.js (100%) rename dapps/evm2/{flipper => randomness}/package.json (100%) rename dapps/evm2/{flipper => randomness}/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js (100%) rename dapps/evm2/{flipper => randomness}/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js (100%) rename dapps/evm2/{flipper => randomness}/scripts/package.json (100%) rename dapps/evm2/{flipper => randomness}/test/test_ChainlinkVRF.js (100%) rename dapps/evm2/{flipper => randomness}/test/test_Flipper.js (100%) rename dapps/evm2/{flipper => randomness}/test/test_MoonbaseVRF.js (100%) rename dapps/evm2/{flipper => randomness}/truffle-box.json (100%) rename dapps/evm2/{flipper => randomness}/truffle-config.js (100%) rename dapps/evm2/{flipper => randomness}/tx.log (97%) diff --git a/README.md b/README.md index 27f29dc..ae3cf9f 100644 --- a/README.md +++ b/README.md @@ -196,11 +196,11 @@ docker exec -it ink /app/docker/quickstart.sh ### Build & Upload Moonbeam VRF Randomness Precompile Solidity Smart Contract to Moonbase Alpha Testnet (using Truffle) -* Follow the instructions in the [VRF example README](./dapps/evm2/flipper/README.md) +* Follow the instructions in the [VRF example README](./dapps/evm2/randomness/README.md) ### Build & Upload Chainlink VRFD20 Randomness Solidity Smart Contract to Ethereum Sepolia Testnet (using Truffle) -* Follow the instructions in the [VRF20 example README](./dapps/evm2/flipper/README.md) +* Follow the instructions in the [VRF20 example README](./dapps/evm2/randomness/README.md) ### Build & Upload ink! Rust Flipper Smart Contract to Local Testnet (using Cargo Contract) diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/randomness/.env.example similarity index 100% rename from dapps/evm2/flipper/.env.example rename to dapps/evm2/randomness/.env.example diff --git a/dapps/evm2/flipper/.gitignore b/dapps/evm2/randomness/.gitignore similarity index 100% rename from dapps/evm2/flipper/.gitignore rename to dapps/evm2/randomness/.gitignore diff --git a/dapps/evm2/flipper/LICENSE b/dapps/evm2/randomness/LICENSE similarity index 100% rename from dapps/evm2/flipper/LICENSE rename to dapps/evm2/randomness/LICENSE diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/randomness/README.md similarity index 98% rename from dapps/evm2/flipper/README.md rename to dapps/evm2/randomness/README.md index 6defabc..0c64d75 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/randomness/README.md @@ -1,4 +1,4 @@ -# Flipper +# Randomness Note: The following was based upon Moonbeam Truffle Box https://docs.moonbeam.network/builders/build/eth-api/dev-env/truffle/ @@ -32,8 +32,8 @@ chmod 755 /usr/lib/node_modules/truffle/build/cli.bundled.js ``` * Setup Moonbeam Truffle Box template that this has been based upon ```bash -mkdir -p /app/dapps/evm/flipper -DAPP_PATH=/app/dapps/evm/flipper +mkdir -p /app/dapps/evm2/randomness +DAPP_PATH=/app/dapps/evm2/randomness git clone https://github.com/PureStake/moonbeam-truffle-box $DAPP_PATH cd $DAPP_PATH ```bash @@ -124,7 +124,7 @@ Verifying contracts on moonscan Successfully verified 1 contract(s). Verifying contracts on sourcify Failed to connect to Sourcify API at url https://sourcify.dev/server/chains -root@ink:/app/dapps/evm2/flipper# truffle run verify RandomNumber --network moonbase +root@ink:/app/dapps/evm2/randomness# truffle run verify RandomNumber --network moonbase Verifying contracts on moonscan Verifying RandomNumber Pass - Verified: https://moonbase.moonscan.io/address/0x4027755C05514421fe00f4Fde0bD3F8475ce8A6b#code diff --git a/dapps/evm2/flipper/contracts/Flipper.sol b/dapps/evm2/randomness/contracts/Flipper.sol similarity index 100% rename from dapps/evm2/flipper/contracts/Flipper.sol rename to dapps/evm2/randomness/contracts/Flipper.sol diff --git a/dapps/evm2/flipper/contracts/Migrations.sol b/dapps/evm2/randomness/contracts/Migrations.sol similarity index 100% rename from dapps/evm2/flipper/contracts/Migrations.sol rename to dapps/evm2/randomness/contracts/Migrations.sol diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/randomness/contracts/lib/RandomNumber.sol similarity index 100% rename from dapps/evm2/flipper/contracts/lib/RandomNumber.sol rename to dapps/evm2/randomness/contracts/lib/RandomNumber.sol diff --git a/dapps/evm2/flipper/contracts/lib/VRFD20.sol b/dapps/evm2/randomness/contracts/lib/VRFD20.sol similarity index 100% rename from dapps/evm2/flipper/contracts/lib/VRFD20.sol rename to dapps/evm2/randomness/contracts/lib/VRFD20.sol diff --git a/dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol b/dapps/evm2/randomness/contracts/precompiles/randomness/Randomness.sol similarity index 100% rename from dapps/evm2/flipper/contracts/precompiles/randomness/Randomness.sol rename to dapps/evm2/randomness/contracts/precompiles/randomness/Randomness.sol diff --git a/dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol b/dapps/evm2/randomness/contracts/precompiles/randomness/RandomnessConsumer.sol similarity index 100% rename from dapps/evm2/flipper/contracts/precompiles/randomness/RandomnessConsumer.sol rename to dapps/evm2/randomness/contracts/precompiles/randomness/RandomnessConsumer.sol diff --git a/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol b/dapps/evm2/randomness/contracts/vrf/VRFConsumerBaseV2.sol similarity index 100% rename from dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol rename to dapps/evm2/randomness/contracts/vrf/VRFConsumerBaseV2.sol diff --git a/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol b/dapps/evm2/randomness/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol similarity index 100% rename from dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol rename to dapps/evm2/randomness/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol diff --git a/dapps/evm2/flipper/migrations/1_initial_migration.js b/dapps/evm2/randomness/migrations/1_initial_migration.js similarity index 100% rename from dapps/evm2/flipper/migrations/1_initial_migration.js rename to dapps/evm2/randomness/migrations/1_initial_migration.js diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/randomness/migrations/2_deploy_contracts.js similarity index 100% rename from dapps/evm2/flipper/migrations/2_deploy_contracts.js rename to dapps/evm2/randomness/migrations/2_deploy_contracts.js diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/randomness/package.json similarity index 100% rename from dapps/evm2/flipper/package.json rename to dapps/evm2/randomness/package.json diff --git a/dapps/evm2/flipper/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js b/dapps/evm2/randomness/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js similarity index 100% rename from dapps/evm2/flipper/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js rename to dapps/evm2/randomness/scripts/demo-chainlink-vrf-on-ethereum-sepolia.js diff --git a/dapps/evm2/flipper/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js b/dapps/evm2/randomness/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js similarity index 100% rename from dapps/evm2/flipper/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js rename to dapps/evm2/randomness/scripts/demo-moonbeam-vrf-on-moonbase-alpha.js diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/randomness/scripts/package.json similarity index 100% rename from dapps/evm2/flipper/scripts/package.json rename to dapps/evm2/randomness/scripts/package.json diff --git a/dapps/evm2/flipper/test/test_ChainlinkVRF.js b/dapps/evm2/randomness/test/test_ChainlinkVRF.js similarity index 100% rename from dapps/evm2/flipper/test/test_ChainlinkVRF.js rename to dapps/evm2/randomness/test/test_ChainlinkVRF.js diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/randomness/test/test_Flipper.js similarity index 100% rename from dapps/evm2/flipper/test/test_Flipper.js rename to dapps/evm2/randomness/test/test_Flipper.js diff --git a/dapps/evm2/flipper/test/test_MoonbaseVRF.js b/dapps/evm2/randomness/test/test_MoonbaseVRF.js similarity index 100% rename from dapps/evm2/flipper/test/test_MoonbaseVRF.js rename to dapps/evm2/randomness/test/test_MoonbaseVRF.js diff --git a/dapps/evm2/flipper/truffle-box.json b/dapps/evm2/randomness/truffle-box.json similarity index 100% rename from dapps/evm2/flipper/truffle-box.json rename to dapps/evm2/randomness/truffle-box.json diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/randomness/truffle-config.js similarity index 100% rename from dapps/evm2/flipper/truffle-config.js rename to dapps/evm2/randomness/truffle-config.js diff --git a/dapps/evm2/flipper/tx.log b/dapps/evm2/randomness/tx.log similarity index 97% rename from dapps/evm2/flipper/tx.log rename to dapps/evm2/randomness/tx.log index 8ba97fc..23b3dcf 100644 --- a/dapps/evm2/flipper/tx.log +++ b/dapps/evm2/randomness/tx.log @@ -5,7 +5,7 @@ Compiling your contracts... ✓ Fetching solc version list from solc-bin. Attempt #1 > Compiling ./contracts/Flipper.sol > Compiling ./contracts/Migrations.sol -> Artifacts written to /app/dapps/evm/flipper/build/contracts +> Artifacts written to /app/dapps/evm2/randomness/build/contracts > Compiled successfully using: - solc: 0.8.20+commit.a1b79de6.Emscripten.clang @@ -77,7 +77,7 @@ Compiling your contracts... > Compiling ./contracts/lib/RandomNumber.sol > Compiling ./contracts/precompiles/randomness/Randomness.sol > Compiling ./contracts/precompiles/randomness/RandomnessConsumer.sol -> Artifacts written to /app/dapps/evm2/flipper/build/contracts +> Artifacts written to /app/dapps/evm2/randomness/build/contracts > Compiled successfully using: - solc: 0.8.20+commit.a1b79de6.Emscripten.clang diff --git a/docker/quickstart-chainlink-vrfd20.sh b/docker/quickstart-chainlink-vrfd20.sh index 15d802c..c0db783 100755 --- a/docker/quickstart-chainlink-vrfd20.sh +++ b/docker/quickstart-chainlink-vrfd20.sh @@ -7,11 +7,11 @@ trap "echo; exit" HUP # in both cases the PARENT_DIR will refer to the project root where the .env file is. PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) -# TODO - install all necessary dependencies as mentioned in the dapps/evm2/flipper/README.md +# TODO - install all necessary dependencies as mentioned in the dapps/evm2/randomness/README.md # echo "Compiling contracts..." -# cd $PARENT_DIR/dapps/evm2/flipper -# PROJECT_ROOT=$PARENT_DIR/dapps/evm2/flipper +# cd $PARENT_DIR/dapps/evm2/randomness +# PROJECT_ROOT=$PARENT_DIR/dapps/evm2/randomness # truffle compile --compile-all # echo "Migrating contracts..." @@ -23,5 +23,5 @@ PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) # and waits some blocks before getting the random number) # echo "Rolling the dice and obtaining the random number" -# cd dapps/evm2/flipper +# cd dapps/evm2/randomness # node ./scripts/demo-chainlink-vrf-on-ethereum-sepolia.js diff --git a/docker/quickstart-moonbeam-vrf-precompile.sh b/docker/quickstart-moonbeam-vrf-precompile.sh index 073c880..59ef2a0 100755 --- a/docker/quickstart-moonbeam-vrf-precompile.sh +++ b/docker/quickstart-moonbeam-vrf-precompile.sh @@ -7,11 +7,11 @@ trap "echo; exit" HUP # in both cases the PARENT_DIR will refer to the project root where the .env file is. PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) -# TODO - install all necessary dependencies as mentioned in the dapps/evm2/flipper/README.md +# TODO - install all necessary dependencies as mentioned in the dapps/evm2/randomness/README.md # echo "Compiling contracts..." -# cd $PARENT_DIR/dapps/evm2/flipper -# PROJECT_ROOT=$PARENT_DIR/dapps/evm2/flipper +# cd $PARENT_DIR/dapps/evm2/randomness +# PROJECT_ROOT=$PARENT_DIR/dapps/evm2/randomness # truffle compile --compile-all # echo "Migrating contracts..." @@ -23,5 +23,5 @@ PARENT_DIR=$( echo $(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")") ) # and waits some blocks before getting the random number) # echo "Request randomness then obtain a randomness status then a random number" -# cd dapps/evm2/flipper +# cd dapps/evm2/randomness # node ./scripts/demo-moonbeam-vrf-on-moonbase-alpha.js