From 1edc6b729070666abbee0e8daa96bca9d4c5e951 Mon Sep 17 00:00:00 2001 From: shekohex Date: Fri, 6 Dec 2024 19:29:33 +0200 Subject: [PATCH] feat: add support for paying with ERC20 or AssetId for services (#845) * chore: update flakes * feat: add payment assets * feat: ERC20 and AssetId support * chore: update onRequestHook * feat: add Mock ERC20 for testing * feat: test using other assets * feat: using ERC20 and Assets works on Both EVM and Substrate * feat: add custom error messages for the precompile --- .editorconfig | 15 ++ Cargo.lock | 1 + flake.lock | 24 +- flake.nix | 31 ++- pallets/services/Cargo.toml | 2 + pallets/services/src/functions.rs | 220 +++++++++++++----- pallets/services/src/lib.rs | 70 ++++-- pallets/services/src/mock.rs | 155 +++++++++++- .../src/test-artifacts/CGGMP21Blueprint.hex | 2 +- .../HookTestBlueprintServiceManager.hex | 2 +- .../MasterBlueprintServiceManager.hex | 2 +- .../services/src/test-artifacts/MockERC20.hex | 1 + pallets/services/src/tests.rs | 115 ++++++++- precompiles/services/Services.sol | 175 ++++++++------ precompiles/services/src/lib.rs | 97 +++++++- precompiles/services/src/mock.rs | 175 +++++++++++++- precompiles/services/src/tests.rs | 179 +++++++++++++- primitives/src/services/mod.rs | 59 ++++- runtime/mainnet/src/tangle_services.rs | 1 + runtime/testnet/src/tangle_services.rs | 1 + 20 files changed, 1126 insertions(+), 201 deletions(-) create mode 100644 .editorconfig create mode 100644 pallets/services/src/test-artifacts/MockERC20.hex diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..48694371 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = tab +indent_size = 4 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[.github/workflows/*.{yaml,yml}] +indent_size = 2 diff --git a/Cargo.lock b/Cargo.lock index 77583acb..f867b9ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8417,6 +8417,7 @@ dependencies = [ "libsecp256k1", "log", "num_enum", + "pallet-assets", "pallet-balances", "pallet-base-fee", "pallet-dynamic-fee", diff --git a/flake.lock b/flake.lock index 735dfea1..a33ffa87 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1730625090, - "narHash": "sha256-lWfkkj+GEUM0UqYLD2Rx3zzILTL3xdmGJKGR4fwONpA=", + "lastModified": 1733217107, + "narHash": "sha256-T5rE+F85pRWkG7efabISw7ZNLgCBhnAg6egu5uGT4Bg=", "owner": "shazow", "repo": "foundry.nix", - "rev": "1c6a742bcbfd55a80de0e1f967a60174716a1560", + "rev": "b0534fca03a058756b4a405aacd5f5059a879673", "type": "github" }, "original": { @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1731245184, - "narHash": "sha256-vmLS8+x+gHRv1yzj3n+GTAEObwmhxmkkukB2DwtJRdU=", + "lastModified": 1733097829, + "narHash": "sha256-9hbb1rqGelllb4kVUCZ307G2k3/UhmA8PPGBoyuWaSw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "aebe249544837ce42588aa4b2e7972222ba12e8f", + "rev": "2c15aa59df0017ca140d9ba302412298ab4bf22a", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1731464916, - "narHash": "sha256-WZ5rpjr/wCt7yBOUsvDE2i22hYz9g8W921jlwVktRQ4=", + "lastModified": 1733193245, + "narHash": "sha256-nwvKoPi3S6XyliqBRuC+01QFF0k94ZOvnoZtbGi/ObM=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "2c19bad6e881b5a154cafb7f9106879b5b356d1f", + "rev": "3458f7f946ba61d1a1069aedcc17d7b7616f23cd", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e289c0c8..ace67e27 100644 --- a/flake.nix +++ b/flake.nix @@ -6,9 +6,7 @@ # Rust rust-overlay = { url = "github:oxalica/rust-overlay"; - inputs = { - nixpkgs.follows = "nixpkgs"; - }; + inputs = { nixpkgs.follows = "nixpkgs"; }; }; # EVM dev tools foundry = { @@ -24,13 +22,10 @@ flake-utils.lib.eachDefaultSystem (system: let overlays = [ (import rust-overlay) foundry.overlay ]; - pkgs = import nixpkgs { - inherit system overlays; - }; + pkgs = import nixpkgs { inherit system overlays; }; lib = pkgs.lib; toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; - in - { + in { devShells.default = pkgs.mkShell { name = "tangle"; nativeBuildInputs = [ @@ -44,8 +39,10 @@ pkgs.rustPlatform.bindgenHook # Mold Linker for faster builds (only on Linux) (lib.optionals pkgs.stdenv.isLinux pkgs.mold) - (lib.optionals pkgs.stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.Security) - (lib.optionals pkgs.stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.SystemConfiguration) + (lib.optionals pkgs.stdenv.isDarwin + pkgs.darwin.apple_sdk.frameworks.Security) + (lib.optionals pkgs.stdenv.isDarwin + pkgs.darwin.apple_sdk.frameworks.SystemConfiguration) ]; buildInputs = [ # Nodejs for test suite @@ -56,15 +53,17 @@ toolchain pkgs.foundry-bin ]; - packages = [ - pkgs.taplo - pkgs.cargo-nextest - pkgs.cargo-tarpaulin - ]; + packages = + [ pkgs.taplo pkgs.harper pkgs.cargo-nextest pkgs.cargo-tarpaulin ]; # Environment variables RUST_SRC_PATH = "${toolchain}/lib/rustlib/src/rust/library"; # Needed for running DKG Node. - LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.gmp pkgs.openssl pkgs.libclang pkgs.stdenv.cc.cc ]; + LD_LIBRARY_PATH = lib.makeLibraryPath [ + pkgs.gmp + pkgs.openssl + pkgs.libclang + pkgs.stdenv.cc.cc + ]; }; }); } diff --git a/pallets/services/Cargo.toml b/pallets/services/Cargo.toml index 69d0849f..e93e95d1 100644 --- a/pallets/services/Cargo.toml +++ b/pallets/services/Cargo.toml @@ -32,6 +32,7 @@ hex = { workspace = true } num_enum = { workspace = true } hex-literal = { workspace = true } libsecp256k1 = { workspace = true } +pallet-assets = { workspace = true } pallet-balances = { workspace = true } pallet-timestamp = { workspace = true } serde = { workspace = true } @@ -103,6 +104,7 @@ std = [ "pallet-ethereum/std", "pallet-evm/std", "pallet-evm-chain-id/std", + "pallet-assets/std", "pallet-evm-precompile-modexp/std", "pallet-evm-precompile-sha3fips/std", diff --git a/pallets/services/src/functions.rs b/pallets/services/src/functions.rs index 2008db47..26d6944e 100644 --- a/pallets/services/src/functions.rs +++ b/pallets/services/src/functions.rs @@ -9,8 +9,8 @@ use frame_support::dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}; use sp_core::{H160, U256}; use sp_runtime::traits::{UniqueSaturatedInto, Zero}; use tangle_primitives::services::{ - BlueprintServiceManager, Field, MasterBlueprintServiceManagerRevision, OperatorPreferences, - Service, ServiceBlueprint, + Asset, BlueprintServiceManager, Field, MasterBlueprintServiceManagerRevision, + OperatorPreferences, Service, ServiceBlueprint, }; use super::*; @@ -449,7 +449,9 @@ impl Pallet { permitted_callers: &[T::AccountId], _assets: &[T::AssetId], ttl: BlockNumberFor, + paymet_asset: Asset, value: BalanceOf, + native_value: BalanceOf, ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { #[allow(deprecated)] Self::dispatch_hook( @@ -463,41 +465,28 @@ impl Pallet { internal_type: None, }, ethabi::Param { - name: String::from("requestId"), - kind: ethabi::ParamType::Uint(64), - internal_type: None, - }, - ethabi::Param { - name: String::from("requester"), - kind: ethabi::ParamType::Address, - internal_type: None, - }, - ethabi::Param { - name: String::from("operatorsWithPreferences"), - kind: ethabi::ParamType::Array(Box::new( - OperatorPreferences::to_ethabi_param_type(), - )), - internal_type: Some(String::from("OperatorPreferences[]")), - }, - ethabi::Param { - name: String::from("requestInputs"), - kind: ethabi::ParamType::Bytes, - internal_type: None, - }, - ethabi::Param { - name: String::from("permittedCallers"), - kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), - internal_type: Some(String::from("address[]")), - }, - // ethabi::Param { - // name: String::from("assets"), - // kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), - // internal_type: Some(String::from("address[]")), - // }, - ethabi::Param { - name: String::from("ttl"), - kind: ethabi::ParamType::Uint(64), - internal_type: None, + name: String::from("params"), + kind: ethabi::ParamType::Tuple(vec![ + // requestId + ethabi::ParamType::Uint(64), + // requester + ethabi::ParamType::Address, + // operatorsWithPreferences + ethabi::ParamType::Array(Box::new( + OperatorPreferences::to_ethabi_param_type(), + )), + // requestInputs + ethabi::ParamType::Bytes, + // permittedCallers + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + // ttl + ethabi::ParamType::Uint(64), + // payment asset + Asset::::to_ethabi_param_type(), + // value + ethabi::ParamType::Uint(256), + ]), + internal_type: Some(String::from("struct ServiceOperators.RequestParams")), }, ], outputs: Default::default(), @@ -506,23 +495,27 @@ impl Pallet { }, &[ Token::Uint(ethabi::Uint::from(blueprint_id)), - Token::Uint(ethabi::Uint::from(request_id)), - Token::Address(T::EvmAddressMapping::into_address(requester.clone())), - Token::Array(operators.iter().map(OperatorPreferences::to_ethabi).collect()), - Token::Bytes(Field::encode_to_ethabi(request_args)), - Token::Array( - permitted_callers - .iter() - .map(|caller| { - Token::Address(T::EvmAddressMapping::into_address(caller.clone())) - .clone() - }) - .collect(), - ), - // Token::Array(vec![]), - Token::Uint(ethabi::Uint::from(ttl.into())), + Token::Tuple(vec![ + Token::Uint(ethabi::Uint::from(request_id)), + Token::Address(T::EvmAddressMapping::into_address(requester.clone())), + Token::Array(operators.iter().map(OperatorPreferences::to_ethabi).collect()), + Token::Bytes(Field::encode_to_ethabi(request_args)), + Token::Array( + permitted_callers + .iter() + .map(|caller| { + Token::Address(T::EvmAddressMapping::into_address(caller.clone())) + .clone() + }) + .collect(), + ), + // Token::Array(vec![]), + Token::Uint(ethabi::Uint::from(ttl.into())), + paymet_asset.to_ethabi(), + Token::Uint(ethabi::Uint::from(value.using_encoded(U256::from_little_endian))), + ]), ], - value, + native_value, ) } @@ -863,8 +856,9 @@ impl Pallet { constant: None, state_mutability: StateMutability::NonPayable, }; + let mbsm = Self::mbsm_address_of(&blueprint)?; let (info, weight) = Self::dispatch_evm_call( - &blueprint, + mbsm, query.clone(), &[ Token::Uint(ethabi::Uint::from(service.blueprint)), @@ -928,8 +922,9 @@ impl Pallet { constant: None, state_mutability: StateMutability::NonPayable, }; + let mbsm = Self::mbsm_address_of(&blueprint)?; let (info, weight) = Self::dispatch_evm_call( - &blueprint, + mbsm, query.clone(), &[ Token::Uint(ethabi::Uint::from(service.blueprint)), @@ -955,6 +950,113 @@ impl Pallet { Ok((dispute_origin, weight)) } + /// Moves a `value` amount of tokens from the caller's account to `to`. + pub fn erc20_transfer( + erc20: H160, + caller: &T::AccountId, + to: H160, + value: BalanceOf, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + let from = T::EvmAddressMapping::into_address(caller.clone()); + #[allow(deprecated)] + let transfer_fn = Function { + name: String::from("transfer"), + inputs: vec![ + ethabi::Param { + name: String::from("to"), + kind: ethabi::ParamType::Address, + internal_type: None, + }, + ethabi::Param { + name: String::from("value"), + kind: ethabi::ParamType::Uint(256), + internal_type: None, + }, + ], + outputs: vec![ethabi::Param { + name: String::from("success"), + kind: ethabi::ParamType::Bool, + internal_type: None, + }], + constant: None, + state_mutability: StateMutability::NonPayable, + }; + + let args = [ + Token::Address(to), + Token::Uint(ethabi::Uint::from(value.using_encoded(U256::from_little_endian))), + ]; + + log::debug!(target: "evm", "Dispatching EVM call(0x{}): {}", hex::encode(transfer_fn.short_signature()), transfer_fn.signature()); + let data = transfer_fn.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + let info = Self::evm_call(from, erc20, U256::zero(), data, gas_limit)?; + let weight = Self::weight_from_call_info(&info); + + // decode the result and return it + let maybe_value = info.exit_reason.is_succeed().then_some(&info.value); + let success = if let Some(data) = maybe_value { + let result = transfer_fn.decode_output(data).map_err(|_| Error::::EVMAbiDecode)?; + let success = result.first().ok_or_else(|| Error::::EVMAbiDecode)?; + if let ethabi::Token::Bool(val) = success { + *val + } else { + false + } + } else { + false + }; + + Ok((success, weight)) + } + + /// Get the balance of an ERC20 token for an account. + pub fn query_erc20_balance_of( + erc20: H160, + who: H160, + ) -> Result<(U256, Weight), DispatchErrorWithPostInfo> { + #[allow(deprecated)] + let transfer_fn = Function { + name: String::from("balanceOf"), + inputs: vec![ethabi::Param { + name: String::from("who"), + kind: ethabi::ParamType::Address, + internal_type: None, + }], + outputs: vec![ethabi::Param { + name: String::from("balance"), + kind: ethabi::ParamType::Uint(256), + internal_type: None, + }], + constant: None, + state_mutability: StateMutability::NonPayable, + }; + + let args = [Token::Address(who)]; + + log::debug!(target: "evm", "Dispatching EVM call(0x{}): {}", hex::encode(transfer_fn.short_signature()), transfer_fn.signature()); + let data = transfer_fn.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + let info = Self::evm_call(Self::address(), erc20, U256::zero(), data, gas_limit)?; + let weight = Self::weight_from_call_info(&info); + + // decode the result and return it + let maybe_value = info.exit_reason.is_succeed().then_some(&info.value); + let balance = if let Some(data) = maybe_value { + let result = transfer_fn.decode_output(data).map_err(|_| Error::::EVMAbiDecode)?; + let success = result.first().ok_or_else(|| Error::::EVMAbiDecode)?; + if let ethabi::Token::Uint(val) = success { + *val + } else { + U256::zero() + } + } else { + U256::zero() + }; + + Ok((balance, weight)) + } + /// Dispatches a hook to the EVM and returns if the call was successful with the used weight. fn dispatch_hook( blueprint: &ServiceBlueprint, @@ -962,23 +1064,23 @@ impl Pallet { args: &[ethabi::Token], value: BalanceOf, ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { - Self::dispatch_evm_call(blueprint, f, args, value) + let mbsm = Self::mbsm_address_of(blueprint)?; + Self::dispatch_evm_call(mbsm, f, args, value) .map(|(info, weight)| (info.exit_reason.is_succeed(), weight)) } /// Dispatches a hook to the EVM and returns if the result with the used weight. fn dispatch_evm_call( - blueprint: &ServiceBlueprint, + contract: H160, f: Function, args: &[ethabi::Token], value: BalanceOf, ) -> Result<(fp_evm::CallInfo, Weight), DispatchErrorWithPostInfo> { log::debug!(target: "evm", "Dispatching EVM call(0x{}): {}", hex::encode(f.short_signature()), f.signature()); - let mbsm = Self::mbsm_address_of(blueprint)?; let data = f.encode_input(args).map_err(|_| Error::::EVMAbiEncode)?; let gas_limit = 300_000; let value = value.using_encoded(U256::from_little_endian); - let info = Self::evm_call(Self::address(), mbsm, value, data, gas_limit)?; + let info = Self::evm_call(Self::address(), contract, value, data, gas_limit)?; let weight = Self::weight_from_call_info(&info); Ok((info, weight)) } diff --git a/pallets/services/src/lib.rs b/pallets/services/src/lib.rs index 1e11b42c..e6fe8cf4 100644 --- a/pallets/services/src/lib.rs +++ b/pallets/services/src/lib.rs @@ -59,15 +59,14 @@ pub use impls::BenchmarkingOperatorDelegationManager; pub mod module { use super::*; use frame_support::dispatch::PostDispatchInfo; + use frame_support::traits::fungibles::{Inspect, Mutate}; + use frame_support::traits::tokens::Preservation; use sp_core::H160; - use sp_runtime::traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize}; + use sp_runtime::traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Zero}; use sp_runtime::Percent; use sp_std::vec::Vec; use tangle_primitives::services::MasterBlueprintServiceManagerRevision; - use tangle_primitives::{ - services::{PriceTargets, *}, - MultiAssetDelegationInfo, - }; + use tangle_primitives::{services::*, MultiAssetDelegationInfo}; use types::*; #[pallet::config] @@ -78,6 +77,10 @@ pub mod module { /// The currency mechanism. type Currency: ReservableCurrency; + /// The fungibles trait used for managing fungible assets. + type Fungibles: Inspect> + + Mutate; + /// `Pallet` EVM Address. #[pallet::constant] type PalletEVMAddress: Get; @@ -286,6 +289,8 @@ pub mod module { MasterBlueprintServiceManagerRevisionNotFound, /// Maximum number of Master Blueprint Service Manager revisions reached. MaxMasterBlueprintServiceManagerVersionsExceeded, + /// The ERC20 transfer failed. + ERC20TransferFailed, } #[pallet::event] @@ -836,7 +841,7 @@ pub mod module { } /// Request a new service to be initiated using the provided blueprint with a list of - /// operators that will run your service. Optionally, you can specifiy who is permitted + /// operators that will run your service. Optionally, you can customize who is permitted /// caller of this service, by default only the caller is allowed to call the service. #[pallet::weight(T::WeightInfo::request())] pub fn request( @@ -847,6 +852,7 @@ pub mod module { request_args: Vec>, assets: Vec, #[pallet::compact] ttl: BlockNumberFor, + payment_asset: Asset, #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; @@ -864,36 +870,59 @@ pub mod module { preferences.push(prefs); } - // Transfer the request value to the pallet - T::Currency::transfer( - &caller, - &Self::account_id(), - value, - ExistenceRequirement::KeepAlive, - )?; + let mut native_value = Zero::zero(); + + if value != Zero::zero() { + // Payment transfer + match payment_asset { + // Handle the case of native currency. + Asset::Custom(asset_id) if asset_id == Zero::zero() => { + T::Currency::transfer( + &caller, + &Self::account_id(), + value, + ExistenceRequirement::KeepAlive, + )?; + native_value = value; + }, + Asset::Custom(asset_id) => { + T::Fungibles::transfer( + asset_id, + &caller, + &Self::account_id(), + value, + Preservation::Preserve, + )?; + }, + Asset::Erc20(token) => { + let (success, _weight) = + Self::erc20_transfer(token, &caller, Self::address(), value)?; + ensure!(success, Error::::ERC20TransferFailed); + }, + }; + } - let service_id = Self::next_instance_id(); + let request_id = NextServiceRequestId::::get(); let (allowed, _weight) = Self::on_request_hook( &blueprint, blueprint_id, &caller, - service_id, + request_id, &preferences, &request_args, &permitted_callers, &assets, ttl, + payment_asset, value, + native_value, )?; - ensure!(allowed, Error::::InvalidRequestInput); - let permitted_callers = BoundedVec::<_, MaxPermittedCallersOf>::try_from(permitted_callers) .map_err(|_| Error::::MaxPermittedCallersExceeded)?; let assets = BoundedVec::<_, MaxAssetsPerServiceOf>::try_from(assets) .map_err(|_| Error::::MaxAssetsPerServiceExceeded)?; - let request_id = NextServiceRequestId::::get(); let operators = pending_approvals .iter() .cloned() @@ -916,6 +945,8 @@ pub mod module { permitted_callers, operators_with_approval_state, }; + + ensure!(allowed, Error::::InvalidRequestInput); ServiceRequests::::insert(request_id, service_request); NextServiceRequestId::::set(request_id.saturating_add(1)); @@ -1337,6 +1368,9 @@ pub mod module { Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } + /// Adds a new Master Blueprint Service Manager to the list of revisions. + /// + /// The caller needs to be an authorized Master Blueprint Service Manager Update Origin. pub fn update_master_blueprint_service_manager( origin: OriginFor, address: H160, diff --git a/pallets/services/src/mock.rs b/pallets/services/src/mock.rs index cac0f45d..44d97c26 100644 --- a/pallets/services/src/mock.rs +++ b/pallets/services/src/mock.rs @@ -16,19 +16,21 @@ #![allow(clippy::all)] use super::*; use crate::{self as pallet_services}; +use ethabi::Uint; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, onchain, SequentialPhragmen, }; -use frame_support::derive_impl; use frame_support::{ construct_runtime, parameter_types, traits::{ConstU128, ConstU32, OneSessionHandler}, }; +use frame_support::{derive_impl, traits::AsEnsureOriginWithArg}; use frame_system::EnsureRoot; use mock_evm::MockedEvmRunner; use pallet_evm::GasWeightMapping; use pallet_session::historical as pallet_session_historical; +use serde_json::json; use sp_core::{sr25519, H160}; use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; use sp_runtime::{ @@ -37,6 +39,7 @@ use sp_runtime::{ AccountId32, BuildStorage, Perbill, }; +use core::ops::Mul; use std::{collections::BTreeMap, sync::Arc}; pub type AccountId = AccountId32; @@ -237,6 +240,27 @@ impl EvmAddressMapping for PalletEVMAddressMapping { } } +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = u128; + type AssetId = AssetId; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; +} + pub type AssetId = u32; pub struct MockDelegationManager; @@ -384,6 +408,7 @@ impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = frame_system::EnsureRoot; type Currency = Balances; + type Fungibles = Assets; type PalletEVMAddress = ServicesEVMAddress; type AssetId = AssetId; type EvmRunner = MockedEvmRunner; @@ -425,6 +450,7 @@ construct_runtime!( System: frame_system, Timestamp: pallet_timestamp, Balances: pallet_balances, + Assets: pallet_assets, Services: pallet_services, EVM: pallet_evm, Ethereum: pallet_ethereum, @@ -446,6 +472,10 @@ pub fn mock_pub_key(id: u8) -> AccountId { sr25519::Public::from_raw([id; 32]).into() } +pub fn mock_address(id: u8) -> H160 { + H160([id; 20]) +} + pub fn mock_authorities(vec: Vec) -> Vec { vec.into_iter().map(|id| mock_pub_key(id)).collect() } @@ -457,6 +487,12 @@ pub fn new_test_ext(ids: Vec) -> sp_io::TestExternalities { pub const MBSM: H160 = H160([0x12; 20]); pub const CGGMP21_BLUEPRINT: H160 = H160([0x21; 20]); pub const HOOKS_TEST: H160 = H160([0x22; 20]); +pub const USDC_ERC20: H160 = H160([0x23; 20]); + +pub const TNT: AssetId = 0; +pub const USDC: AssetId = 1; +pub const WETH: AssetId = 2; +pub const WBTC: AssetId = 3; // This function basically just builds a genesis storage key/value store according to // our desired mockup. @@ -519,12 +555,53 @@ pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::TestE include_str!("./test-artifacts/HookTestBlueprintServiceManager.hex"), HOOKS_TEST, ); + create_contract(include_str!("./test-artifacts/MockERC20.hex"), USDC_ERC20); + + for i in 1..=authorities.len() { + evm_accounts.insert( + mock_address(i as u8), + fp_evm::GenesisAccount { + code: vec![], + storage: Default::default(), + nonce: Default::default(), + balance: Uint::from(1_000).mul(Uint::from(10).pow(Uint::from(18))), + }, + ); + } let evm_config = pallet_evm::GenesisConfig:: { accounts: evm_accounts, ..Default::default() }; evm_config.assimilate_storage(&mut t).unwrap(); + let assets_config = pallet_assets::GenesisConfig:: { + assets: vec![ + (USDC, authorities[0].clone(), true, 100_000), // 1 cent. + (WETH, authorities[1].clone(), true, 100), // 100 wei. + (WBTC, authorities[2].clone(), true, 100), // 100 satoshi. + ], + metadata: vec![ + (USDC, Vec::from(b"USD Coin"), Vec::from(b"USDC"), 6), + (WETH, Vec::from(b"Wrapped Ether"), Vec::from(b"WETH"), 18), + (WBTC, Vec::from(b"Wrapped Bitcoin"), Vec::from(b"WBTC"), 18), + ], + accounts: vec![ + (USDC, authorities[0].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[0].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[0].clone(), 50 * 10u128.pow(18)), + // + (USDC, authorities[1].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[1].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[1].clone(), 50 * 10u128.pow(18)), + // + (USDC, authorities[2].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[2].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[2].clone(), 50 * 10u128.pow(18)), + ], + next_asset_id: Some(4), + }; + + assets_config.assimilate_storage(&mut t).unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); ext.execute_with(|| System::set_block_number(1)); @@ -532,6 +609,82 @@ pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::TestE System::set_block_number(1); Session::on_initialize(1); >::on_initialize(1); + + let call = ::EvmRunner::call( + Services::address(), + USDC_ERC20, + serde_json::from_value::(json!({ + "name": "initialize", + "inputs": [ + { + "name": "name_", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol_", + "type": "string", + "internalType": "string" + }, + { + "name": "decimals_", + "type": "uint8", + "internalType": "uint8" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + })) + .unwrap() + .encode_input(&[ + ethabi::Token::String("USD Coin".to_string()), + ethabi::Token::String("USDC".to_string()), + ethabi::Token::Uint(6.into()), + ]) + .unwrap(), + Default::default(), + 300_000, + true, + false, + ); + + assert_eq!(call.map(|info| info.exit_reason.is_succeed()).ok(), Some(true)); + // Mint + for i in 1..=authorities.len() { + let call = ::EvmRunner::call( + Services::address(), + USDC_ERC20, + serde_json::from_value::(json!({ + "name": "mint", + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + })) + .unwrap() + .encode_input(&[ + ethabi::Token::Address(mock_address(i as u8).into()), + ethabi::Token::Uint(Uint::from(100_000).mul(Uint::from(10).pow(Uint::from(6)))), + ]) + .unwrap(), + Default::default(), + 300_000, + true, + false, + ); + + assert_eq!(call.map(|info| info.exit_reason.is_succeed()).ok(), Some(true)); + } }); ext diff --git a/pallets/services/src/test-artifacts/CGGMP21Blueprint.hex b/pallets/services/src/test-artifacts/CGGMP21Blueprint.hex index 41b839f8..84bb7d1e 100644 --- a/pallets/services/src/test-artifacts/CGGMP21Blueprint.hex +++ b/pallets/services/src/test-artifacts/CGGMP21Blueprint.hex @@ -1 +1 @@ -0x60806040526004361061012a5760003560e01c8063884673ac116100ab578063a4d91fe91161006f578063a4d91fe9146102e3578063bb43abd914610301578063d7deb4821461030f578063e926cbd11461012f578063f84076621461032f578063fe0dd3711461034f57600080fd5b8063884673ac146102585780639838caa314610280578063987ab9db1461028e5780639d0410ee146102b5578063a24e8a90146102c857600080fd5b8063434698bb116100f2578063434698bb146101e15780635d79ea291461020157806365ce59fa1461022557806374ceeb55146101ae578063821c7be21461023857600080fd5b80630af7d7431461012f5780630b6535d7146101515780630d0dd3991461017157806314b4df4c146101ae57806337c29662146101ce575b600080fd5b34801561013b57600080fd5b5061014f61014a366004610638565b61035d565b005b34801561015d57600080fd5b5061014f61016c3660046106bb565b6103a9565b34801561017d57600080fd5b50600054610191906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101ba57600080fd5b506101916101c93660046106fe565b503090565b61014f6101dc366004610738565b610432565b3480156101ed57600080fd5b5061014f6101fc3660046107fd565b610478565b34801561020d57600080fd5b5061021760015481565b6040519081526020016101a5565b61014f61023336600461087d565b6104b7565b34801561024457600080fd5b5061014f610253366004610947565b6104fe565b34801561026457600080fd5b5061019173111111111111111111111111111111111111111181565b61014f61014a366004610994565b34801561029a57600080fd5b50731111111111111111111111111111111111111111610191565b61014f6102c3366004610a09565b61053e565b3480156102d457600080fd5b5061014f610253366004610a71565b3480156102ef57600080fd5b506000546001600160a01b0316610191565b61014f6102c3366004610a9b565b34801561031b57600080fd5b5061014f61032a366004610aef565b61057f565b34801561033b57600080fd5b50600254610191906001600160a01b031681565b61014f6101fc3660046107fd565b6000546001600160a01b031633146103a257600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b60405180910390fd5b5050505050565b33731111111111111111111111111111111111111111146103f557337311111111111111111111111111111111111111116040516359afe8af60e11b8152600401610399929190610b73565b6001600160401b0392909216600155600280546001600160a01b039283166001600160a01b03199182161790915560008054929093169116179055565b6000546001600160a01b0316331461046e57600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b5050505050505050565b6000546001600160a01b031633146104b457600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b50565b6000546001600160a01b031633146104f357600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b505050505050505050565b6000546001600160a01b0316331461053a57600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b5050565b6000546001600160a01b0316331461057a57600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b505050565b6000546001600160a01b031633146105bb57600054604051630c423fcf60e01b81526103999133916001600160a01b0390911690600401610b73565b505050505050565b80356001600160401b03811681146105da57600080fd5b919050565b60008083601f8401126105f157600080fd5b5081356001600160401b0381111561060857600080fd5b60208301915083602082850101111561062057600080fd5b9250929050565b803560ff811681146105da57600080fd5b60008060008060006080868803121561065057600080fd5b610659866105c3565b945060208601356001600160401b0381111561067457600080fd5b610680888289016105df565b9095509350610693905060408701610627565b949793965091946060013592915050565b80356001600160a01b03811681146105da57600080fd5b6000806000606084860312156106d057600080fd5b6106d9846105c3565b92506106e7602085016106a4565b91506106f5604085016106a4565b90509250925092565b60006020828403121561071057600080fd5b610719826105c3565b9392505050565b600060c0828403121561073257600080fd5b50919050565b60008060008060008060008060c0898b03121561075457600080fd5b61075d896105c3565b975061076b60208a01610627565b965061077960408a016105c3565b955060608901356001600160401b038082111561079557600080fd5b6107a18c838d01610720565b965060808b01359150808211156107b757600080fd5b6107c38c838d016105df565b909650945060a08b01359150808211156107dc57600080fd5b506107e98b828c016105df565b999c989b5096995094979396929594505050565b60006020828403121561080f57600080fd5b81356001600160401b0381111561082557600080fd5b61083184828501610720565b949350505050565b60008083601f84011261084b57600080fd5b5081356001600160401b0381111561086257600080fd5b6020830191508360208260051b850101111561062057600080fd5b600080600080600080600080600060c08a8c03121561089b57600080fd5b6108a48a6105c3565b98506108b260208b016106a4565b975060408a01356001600160401b03808211156108ce57600080fd5b6108da8d838e01610839565b909950975060608c01359150808211156108f357600080fd5b6108ff8d838e016105df565b909750955060808c013591508082111561091857600080fd5b506109258c828d01610839565b9094509250610938905060a08b016105c3565b90509295985092959850929598565b6000806040838503121561095a57600080fd5b82356001600160401b0381111561097057600080fd5b61097c85828601610720565b92505061098b602084016105c3565b90509250929050565b6000806000806000608086880312156109ac57600080fd5b6109b5866105c3565b94506109c360208701610627565b93506109d1604087016105c3565b925060608601356001600160401b038111156109ec57600080fd5b6109f8888289016105df565b969995985093965092949392505050565b600080600060408486031215610a1e57600080fd5b83356001600160401b0380821115610a3557600080fd5b610a4187838801610720565b94506020860135915080821115610a5757600080fd5b50610a64868287016105df565b9497909650939450505050565b60008060408385031215610a8457600080fd5b610a8d836105c3565b915061098b602084016106a4565b600080600060608486031215610ab057600080fd5b83356001600160401b03811115610ac657600080fd5b610ad286828701610720565b935050610ae1602085016105c3565b91506106f560408501610627565b60008060008060008060a08789031215610b0857600080fd5b610b11876105c3565b9550610b1f602088016105c3565b9450610b2d604088016106a4565b935060608701356001600160401b03811115610b4857600080fd5b610b5489828a01610839565b9094509250610b679050608088016105c3565b90509295509295509295565b6001600160a01b039283168152911660208201526040019056fea164736f6c6343000814000a +0x6080604052600436106101355760003560e01c80638b248065116100ab578063a4d91fe91161006f578063a4d91fe914610314578063bb43abd914610332578063d7deb48214610340578063e926cbd114610182578063f840766214610360578063fe0dd3711461038057600080fd5b80638b248065146102a35780639838caa3146102b1578063987ab9db146102bf5780639d0410ee146102e6578063a24e8a90146102f957600080fd5b806337c29662116100fd57806337c2966214610204578063434698bb146102175780635d79ea291461023757806374ceeb55146101e4578063821c7be21461025b578063884673ac1461027b57600080fd5b806308179f351461013a5780630af7d743146101825780630b6535d7146101a45780630d0dd399146101c457806314b4df4c146101e4575b600080fd5b34801561014657600080fd5b506101656101553660046105e3565b506002546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561018e57600080fd5b506101a261019d36600461065f565b61038e565b005b3480156101b057600080fd5b506101a26101bf3660046106e3565b6103da565b3480156101d057600080fd5b50600054610165906001600160a01b031681565b3480156101f057600080fd5b506101656101ff3660046105e3565b503090565b6101a261021236600461073e565b610468565b34801561022357600080fd5b506101a2610232366004610804565b6104b2565b34801561024357600080fd5b5061024d60015481565b604051908152602001610179565b34801561026757600080fd5b506101a2610276366004610841565b6104f5565b34801561028757600080fd5b5061016573111111111111111111111111111111111111111181565b6101a261023236600461088f565b6101a261019d3660046108cb565b3480156102cb57600080fd5b50731111111111111111111111111111111111111111610165565b6101a26102f4366004610941565b610539565b34801561030557600080fd5b506101a26102763660046109aa565b34801561032057600080fd5b506000546001600160a01b0316610165565b6101a26102f43660046109d4565b34801561034c57600080fd5b506101a261035b366004610a29565b61057e565b34801561036c57600080fd5b50600254610165906001600160a01b031681565b6101a2610232366004610804565b6000546001600160a01b031633146103d357600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044015b60405180910390fd5b5050505050565b337311111111111111111111111111111111111111111461042a576040516359afe8af60e11b815233600482015273111111111111111111111111111111111111111160248201526044016103ca565b67ffffffffffffffff92909216600155600280546001600160a01b039283166001600160a01b03199182161790915560008054929093169116179055565b6000546001600160a01b031633146104a857600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044016103ca565b5050505050505050565b6000546001600160a01b031633146104f257600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044016103ca565b50565b6000546001600160a01b0316331461053557600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044016103ca565b5050565b6000546001600160a01b0316331461057957600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044016103ca565b505050565b6000546001600160a01b031633146105be57600054604051630c423fcf60e01b81523360048201526001600160a01b0390911660248201526044016103ca565b505050505050565b803567ffffffffffffffff811681146105de57600080fd5b919050565b6000602082840312156105f557600080fd5b6105fe826105c6565b9392505050565b60008083601f84011261061757600080fd5b50813567ffffffffffffffff81111561062f57600080fd5b60208301915083602082850101111561064757600080fd5b9250929050565b803560ff811681146105de57600080fd5b60008060008060006080868803121561067757600080fd5b610680866105c6565b9450602086013567ffffffffffffffff81111561069c57600080fd5b6106a888828901610605565b90955093506106bb90506040870161064e565b949793965091946060013592915050565b80356001600160a01b03811681146105de57600080fd5b6000806000606084860312156106f857600080fd5b610701846105c6565b925061070f602085016106cc565b915061071d604085016106cc565b90509250925092565b600060c0828403121561073857600080fd5b50919050565b60008060008060008060008060c0898b03121561075a57600080fd5b610763896105c6565b975061077160208a0161064e565b965061077f60408a016105c6565b9550606089013567ffffffffffffffff8082111561079c57600080fd5b6107a88c838d01610726565b965060808b01359150808211156107be57600080fd5b6107ca8c838d01610605565b909650945060a08b01359150808211156107e357600080fd5b506107f08b828c01610605565b999c989b5096995094979396929594505050565b60006020828403121561081657600080fd5b813567ffffffffffffffff81111561082d57600080fd5b61083984828501610726565b949350505050565b6000806040838503121561085457600080fd5b823567ffffffffffffffff81111561086b57600080fd5b61087785828601610726565b925050610886602084016105c6565b90509250929050565b6000602082840312156108a157600080fd5b813567ffffffffffffffff8111156108b857600080fd5b820161012081850312156105fe57600080fd5b6000806000806000608086880312156108e357600080fd5b6108ec866105c6565b94506108fa6020870161064e565b9350610908604087016105c6565b9250606086013567ffffffffffffffff81111561092457600080fd5b61093088828901610605565b969995985093965092949392505050565b60008060006040848603121561095657600080fd5b833567ffffffffffffffff8082111561096e57600080fd5b61097a87838801610726565b9450602086013591508082111561099057600080fd5b5061099d86828701610605565b9497909650939450505050565b600080604083850312156109bd57600080fd5b6109c6836105c6565b9150610886602084016106cc565b6000806000606084860312156109e957600080fd5b833567ffffffffffffffff811115610a0057600080fd5b610a0c86828701610726565b935050610a1b602085016105c6565b915061071d6040850161064e565b60008060008060008060a08789031215610a4257600080fd5b610a4b876105c6565b9550610a59602088016105c6565b9450610a67604088016106cc565b9350606087013567ffffffffffffffff80821115610a8457600080fd5b818901915089601f830112610a9857600080fd5b813581811115610aa757600080fd5b8a60208260051b8501011115610abc57600080fd5b602083019550809450505050610ad4608088016105c6565b9050929550929550929556fea164736f6c6343000814000a diff --git a/pallets/services/src/test-artifacts/HookTestBlueprintServiceManager.hex b/pallets/services/src/test-artifacts/HookTestBlueprintServiceManager.hex index 057611db..f405bb35 100644 --- a/pallets/services/src/test-artifacts/HookTestBlueprintServiceManager.hex +++ b/pallets/services/src/test-artifacts/HookTestBlueprintServiceManager.hex @@ -1 +1 @@ -0x60806040526004361061012a5760003560e01c8063884673ac116100ab578063a4d91fe91161006f578063a4d91fe9146102ed578063bb43abd91461030b578063d7deb4821461031e578063e926cbd11461033e578063f84076621461035e578063fe0dd3711461037e57600080fd5b8063884673ac146102585780639838caa314610280578063987ab9db146102935780639d0410ee146102ba578063a24e8a90146102cd57600080fd5b8063434698bb116100f2578063434698bb146101e15780635d79ea291461020157806365ce59fa1461022557806374ceeb55146101ae578063821c7be21461023857600080fd5b80630af7d7431461012f5780630b6535d7146101515780630d0dd3991461017157806314b4df4c146101ae57806337c29662146101ce575b600080fd5b34801561013b57600080fd5b5061014f61014a36600461098e565b610391565b005b34801561015d57600080fd5b5061014f61016c366004610a11565b6103c1565b34801561017d57600080fd5b50600054610191906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156101ba57600080fd5b506101916101c9366004610a54565b503090565b61014f6101dc366004610a8e565b61047f565b3480156101ed57600080fd5b5061014f6101fc366004610b53565b6104ee565b34801561020d57600080fd5b5061021760015481565b6040519081526020016101a5565b61014f610233366004610bd3565b610556565b34801561024457600080fd5b5061014f610253366004610c9d565b6105c6565b34801561026457600080fd5b5061019173111111111111111111111111111111111111111181565b61014f61028e366004610cea565b61062f565b34801561029f57600080fd5b50731111111111111111111111111111111111111111610191565b61014f6102c8366004610d5f565b61069b565b3480156102d957600080fd5b5061014f6102e8366004610dc7565b610705565b3480156102f957600080fd5b506000546001600160a01b0316610191565b61014f610319366004610df1565b61076e565b34801561032a57600080fd5b5061014f610339366004610e45565b6107d8565b34801561034a57600080fd5b5061014f61035936600461098e565b610845565b34801561036a57600080fd5b50600254610191906001600160a01b031681565b61014f61038c366004610b53565b6108b1565b6040517fd38931c95654e0c6958f3e427ad7c53f3a131634d634c86732f8655a28c119eb90600090a15050505050565b337311111111111111111111111111111111111111111461041657337311111111111111111111111111111111111111116040516359afe8af60e11b815260040161040d929190610ec9565b60405180910390fd5b6001600160401b038316600155600280546001600160a01b038085166001600160a01b03199283161790925560008054928416929091169190911781556040517fcf7e69bd1c708d6d282a3b1525cd1c89aa8bf25ec133174b4a7299223ceb3c4f9190a1505050565b6000546001600160a01b031633146104bb57600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f025cf7c6b8939ff50c796fa1df561a4a8d4e0de035caa3d184d5929e47e33d3590600090a15050505050505050565b6000546001600160a01b0316331461052a57600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f82b9cd36e76e3328de8315cb87dd42c248cdb31558184543b45ffd52ba422f2b90600090a150565b6000546001600160a01b0316331461059257600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f3582472ca72fc6a04530f08cfa31f71919e91e34971f4743873db0dbdf02b76090600090a1505050505050505050565b6000546001600160a01b0316331461060257600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f537b387222a90168d719f1d554df67d479e37cb59651378e6d4e4939030352a790600090a15050565b6000546001600160a01b0316331461066b57600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f9de6d7077ebf9fc111bfdc873d12a9d37d80b3657797fa91476f82695c942a3490600090a15050505050565b6000546001600160a01b031633146106d757600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f9add4e5824603d31f2170069522539a6971d31dc77d08e24588e3b68ce077ee690600090a1505050565b6000546001600160a01b0316331461074157600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517fbdd650f74e0fff138cdfa7cac980a24bf480423cba6de8d8daf53042b6240a0890600090a15050565b6000546001600160a01b031633146107aa57600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517fd4162ed8e9bc92ece7ef39b8f199293e403fbea78e95ce1fcbfce0153eb86bb590600090a1505050565b6000546001600160a01b0316331461081457600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517fdd03b583a4b2c88c19891a8aee92431d65f349d08a744f72297b4f25b28095a890600090a1505050505050565b6000546001600160a01b0316331461088157600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f95bfc812251a7cb44ca7b529c8854d13c0ae581729a7d2142231a3258ecd774390600090a15050505050565b6000546001600160a01b031633146108ed57600054604051630c423fcf60e01b815261040d9133916001600160a01b0390911690600401610ec9565b6040517f7e8e44afe7f3a9205df3a9e5ffc0c6e96006905bc7ca73b2a55eeb177ec63ff590600090a150565b80356001600160401b038116811461093057600080fd5b919050565b60008083601f84011261094757600080fd5b5081356001600160401b0381111561095e57600080fd5b60208301915083602082850101111561097657600080fd5b9250929050565b803560ff8116811461093057600080fd5b6000806000806000608086880312156109a657600080fd5b6109af86610919565b945060208601356001600160401b038111156109ca57600080fd5b6109d688828901610935565b90955093506109e990506040870161097d565b949793965091946060013592915050565b80356001600160a01b038116811461093057600080fd5b600080600060608486031215610a2657600080fd5b610a2f84610919565b9250610a3d602085016109fa565b9150610a4b604085016109fa565b90509250925092565b600060208284031215610a6657600080fd5b610a6f82610919565b9392505050565b600060c08284031215610a8857600080fd5b50919050565b60008060008060008060008060c0898b031215610aaa57600080fd5b610ab389610919565b9750610ac160208a0161097d565b9650610acf60408a01610919565b955060608901356001600160401b0380821115610aeb57600080fd5b610af78c838d01610a76565b965060808b0135915080821115610b0d57600080fd5b610b198c838d01610935565b909650945060a08b0135915080821115610b3257600080fd5b50610b3f8b828c01610935565b999c989b5096995094979396929594505050565b600060208284031215610b6557600080fd5b81356001600160401b03811115610b7b57600080fd5b610b8784828501610a76565b949350505050565b60008083601f840112610ba157600080fd5b5081356001600160401b03811115610bb857600080fd5b6020830191508360208260051b850101111561097657600080fd5b600080600080600080600080600060c08a8c031215610bf157600080fd5b610bfa8a610919565b9850610c0860208b016109fa565b975060408a01356001600160401b0380821115610c2457600080fd5b610c308d838e01610b8f565b909950975060608c0135915080821115610c4957600080fd5b610c558d838e01610935565b909750955060808c0135915080821115610c6e57600080fd5b50610c7b8c828d01610b8f565b9094509250610c8e905060a08b01610919565b90509295985092959850929598565b60008060408385031215610cb057600080fd5b82356001600160401b03811115610cc657600080fd5b610cd285828601610a76565b925050610ce160208401610919565b90509250929050565b600080600080600060808688031215610d0257600080fd5b610d0b86610919565b9450610d196020870161097d565b9350610d2760408701610919565b925060608601356001600160401b03811115610d4257600080fd5b610d4e88828901610935565b969995985093965092949392505050565b600080600060408486031215610d7457600080fd5b83356001600160401b0380821115610d8b57600080fd5b610d9787838801610a76565b94506020860135915080821115610dad57600080fd5b50610dba86828701610935565b9497909650939450505050565b60008060408385031215610dda57600080fd5b610de383610919565b9150610ce1602084016109fa565b600080600060608486031215610e0657600080fd5b83356001600160401b03811115610e1c57600080fd5b610e2886828701610a76565b935050610e3760208501610919565b9150610a4b6040850161097d565b60008060008060008060a08789031215610e5e57600080fd5b610e6787610919565b9550610e7560208801610919565b9450610e83604088016109fa565b935060608701356001600160401b03811115610e9e57600080fd5b610eaa89828a01610b8f565b9094509250610ebd905060808801610919565b90509295509295509295565b6001600160a01b039283168152911660208201526040019056fea164736f6c6343000814000a +0x6080604052600436106101355760003560e01c80638b248065116100ab578063a4d91fe91161006f578063a4d91fe914610323578063bb43abd914610341578063d7deb48214610354578063e926cbd114610374578063f840766214610394578063fe0dd371146103b457600080fd5b80638b248065146102a35780639838caa3146102b6578063987ab9db146102c95780639d0410ee146102f0578063a24e8a901461030357600080fd5b806337c29662116100fd57806337c2966214610204578063434698bb146102175780635d79ea291461023757806374ceeb55146101e4578063821c7be21461025b578063884673ac1461027b57600080fd5b806308179f351461013a5780630af7d743146101825780630b6535d7146101a45780630d0dd399146101c457806314b4df4c146101e4575b600080fd5b34801561014657600080fd5b50610165610155366004610965565b506002546001600160a01b031690565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561018e57600080fd5b506101a261019d3660046109e1565b6103c7565b005b3480156101b057600080fd5b506101a26101bf366004610a65565b6103f7565b3480156101d057600080fd5b50600054610165906001600160a01b031681565b3480156101f057600080fd5b506101656101ff366004610965565b503090565b6101a2610212366004610ac0565b6104b6565b34801561022357600080fd5b506101a2610232366004610b86565b610525565b34801561024357600080fd5b5061024d60015481565b604051908152602001610179565b34801561026757600080fd5b506101a2610276366004610bc3565b61058d565b34801561028757600080fd5b5061016573111111111111111111111111111111111111111181565b6101a26102b1366004610c11565b6105f6565b6101a26102c4366004610c4d565b61065e565b3480156102d557600080fd5b50731111111111111111111111111111111111111111610165565b6101a26102fe366004610cc3565b6106ca565b34801561030f57600080fd5b506101a261031e366004610d2c565b610734565b34801561032f57600080fd5b506000546001600160a01b0316610165565b6101a261034f366004610d56565b61079d565b34801561036057600080fd5b506101a261036f366004610dab565b610807565b34801561038057600080fd5b506101a261038f3660046109e1565b610874565b3480156103a057600080fd5b50600254610165906001600160a01b031681565b6101a26103c2366004610b86565b6108e0565b6040517fd38931c95654e0c6958f3e427ad7c53f3a131634d634c86732f8655a28c119eb90600090a15050505050565b337311111111111111111111111111111111111111111461044c57337311111111111111111111111111111111111111116040516359afe8af60e11b8152600401610443929190610e62565b60405180910390fd5b67ffffffffffffffff8316600155600280546001600160a01b038085166001600160a01b03199283161790925560008054928416929091169190911781556040517fcf7e69bd1c708d6d282a3b1525cd1c89aa8bf25ec133174b4a7299223ceb3c4f9190a1505050565b6000546001600160a01b031633146104f257600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f025cf7c6b8939ff50c796fa1df561a4a8d4e0de035caa3d184d5929e47e33d3590600090a15050505050505050565b6000546001600160a01b0316331461056157600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f82b9cd36e76e3328de8315cb87dd42c248cdb31558184543b45ffd52ba422f2b90600090a150565b6000546001600160a01b031633146105c957600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f537b387222a90168d719f1d554df67d479e37cb59651378e6d4e4939030352a790600090a15050565b6000546001600160a01b0316331461063257600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f3582472ca72fc6a04530f08cfa31f71919e91e34971f4743873db0dbdf02b76090600090a150565b6000546001600160a01b0316331461069a57600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f9de6d7077ebf9fc111bfdc873d12a9d37d80b3657797fa91476f82695c942a3490600090a15050505050565b6000546001600160a01b0316331461070657600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f9add4e5824603d31f2170069522539a6971d31dc77d08e24588e3b68ce077ee690600090a1505050565b6000546001600160a01b0316331461077057600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517fbdd650f74e0fff138cdfa7cac980a24bf480423cba6de8d8daf53042b6240a0890600090a15050565b6000546001600160a01b031633146107d957600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517fd4162ed8e9bc92ece7ef39b8f199293e403fbea78e95ce1fcbfce0153eb86bb590600090a1505050565b6000546001600160a01b0316331461084357600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517fdd03b583a4b2c88c19891a8aee92431d65f349d08a744f72297b4f25b28095a890600090a1505050505050565b6000546001600160a01b031633146108b057600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f95bfc812251a7cb44ca7b529c8854d13c0ae581729a7d2142231a3258ecd774390600090a15050505050565b6000546001600160a01b0316331461091c57600054604051630c423fcf60e01b81526104439133916001600160a01b0390911690600401610e62565b6040517f7e8e44afe7f3a9205df3a9e5ffc0c6e96006905bc7ca73b2a55eeb177ec63ff590600090a150565b803567ffffffffffffffff8116811461096057600080fd5b919050565b60006020828403121561097757600080fd5b61098082610948565b9392505050565b60008083601f84011261099957600080fd5b50813567ffffffffffffffff8111156109b157600080fd5b6020830191508360208285010111156109c957600080fd5b9250929050565b803560ff8116811461096057600080fd5b6000806000806000608086880312156109f957600080fd5b610a0286610948565b9450602086013567ffffffffffffffff811115610a1e57600080fd5b610a2a88828901610987565b9095509350610a3d9050604087016109d0565b949793965091946060013592915050565b80356001600160a01b038116811461096057600080fd5b600080600060608486031215610a7a57600080fd5b610a8384610948565b9250610a9160208501610a4e565b9150610a9f60408501610a4e565b90509250925092565b600060c08284031215610aba57600080fd5b50919050565b60008060008060008060008060c0898b031215610adc57600080fd5b610ae589610948565b9750610af360208a016109d0565b9650610b0160408a01610948565b9550606089013567ffffffffffffffff80821115610b1e57600080fd5b610b2a8c838d01610aa8565b965060808b0135915080821115610b4057600080fd5b610b4c8c838d01610987565b909650945060a08b0135915080821115610b6557600080fd5b50610b728b828c01610987565b999c989b5096995094979396929594505050565b600060208284031215610b9857600080fd5b813567ffffffffffffffff811115610baf57600080fd5b610bbb84828501610aa8565b949350505050565b60008060408385031215610bd657600080fd5b823567ffffffffffffffff811115610bed57600080fd5b610bf985828601610aa8565b925050610c0860208401610948565b90509250929050565b600060208284031215610c2357600080fd5b813567ffffffffffffffff811115610c3a57600080fd5b8201610120818503121561098057600080fd5b600080600080600060808688031215610c6557600080fd5b610c6e86610948565b9450610c7c602087016109d0565b9350610c8a60408701610948565b9250606086013567ffffffffffffffff811115610ca657600080fd5b610cb288828901610987565b969995985093965092949392505050565b600080600060408486031215610cd857600080fd5b833567ffffffffffffffff80821115610cf057600080fd5b610cfc87838801610aa8565b94506020860135915080821115610d1257600080fd5b50610d1f86828701610987565b9497909650939450505050565b60008060408385031215610d3f57600080fd5b610d4883610948565b9150610c0860208401610a4e565b600080600060608486031215610d6b57600080fd5b833567ffffffffffffffff811115610d8257600080fd5b610d8e86828701610aa8565b935050610d9d60208501610948565b9150610a9f604085016109d0565b60008060008060008060a08789031215610dc457600080fd5b610dcd87610948565b9550610ddb60208801610948565b9450610de960408801610a4e565b9350606087013567ffffffffffffffff80821115610e0657600080fd5b818901915089601f830112610e1a57600080fd5b813581811115610e2957600080fd5b8a60208260051b8501011115610e3e57600080fd5b602083019550809450505050610e5660808801610948565b90509295509295509295565b6001600160a01b039283168152911660208201526040019056fea164736f6c6343000814000a diff --git a/pallets/services/src/test-artifacts/MasterBlueprintServiceManager.hex b/pallets/services/src/test-artifacts/MasterBlueprintServiceManager.hex index 745cb77c..a6bc701e 100644 --- a/pallets/services/src/test-artifacts/MasterBlueprintServiceManager.hex +++ b/pallets/services/src/test-artifacts/MasterBlueprintServiceManager.hex @@ -1 +1 @@ -0x60806040526004361061019c5760003560e01c8063727391f2116100ec578063a4d91fe91161008a578063b89af90411610064578063b89af9041461047c578063b9315d3a1461048f578063c97008e0146104a2578063d547741f146104c257600080fd5b8063a4d91fe914610438578063a6a7853814610456578063a8f7c5ed1461046957600080fd5b80638e6f8c60116100c65780638e6f8c60146103c257806391d14854146103e2578063987ab9db14610402578063a217fddf1461042357600080fd5b8063727391f21461036d57806382a1ece414610380578063884673ac146103a057600080fd5b80632f2ff15d11610159578063410fdec811610133578063410fdec81461030f5780634984ee6b1461032f5780634efb4b8b146103425780635c975abb1461035557600080fd5b80632f2ff15d146102af57806333db3920146102cf57806336568abe146102ef57600080fd5b806301ffc9a7146101a15780630633da77146101d65780630d0dd399146101f85780631fb27b3414610230578063248a9ca314610250578063274ef0151461028f575b600080fd5b3480156101ad57600080fd5b506101c16101bc3660046116e7565b6104e2565b60405190151581526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f136600461174d565b610519565b005b34801561020457600080fd5b50600054610218906001600160a01b031681565b6040516001600160a01b0390911681526020016101cd565b34801561023c57600080fd5b506101f661024b3660046117ac565b610640565b34801561025c57600080fd5b5061028161026b3660046117f9565b6000908152600160208190526040909120015490565b6040519081526020016101cd565b34801561029b57600080fd5b506102186102aa366004611812565b610745565b3480156102bb57600080fd5b506101f66102ca366004611845565b6107d9565b3480156102db57600080fd5b506101f66102ea3660046118ce565b610805565b3480156102fb57600080fd5b506101f661030a366004611845565b610926565b34801561031b57600080fd5b506101f661032a36600461194b565b61095e565b6101f661033d3660046119a8565b610a62565b6101f6610350366004611a71565b610b72565b34801561036157600080fd5b5060025460ff166101c1565b6101f661037b366004611b4e565b610c9d565b34801561038c57600080fd5b506101f661039b366004611bc4565b610da8565b3480156103ac57600080fd5b5061021860008051602061248583398151915281565b3480156103ce57600080fd5b506102186103dd366004611812565b610ed1565b3480156103ee57600080fd5b506101c16103fd366004611845565b610f20565b34801561040e57600080fd5b50600080516020612485833981519152610218565b34801561042f57600080fd5b50610281600081565b34801561044457600080fd5b506000546001600160a01b0316610218565b6101f66104643660046117ac565b610f4b565b6101f6610477366004611c5c565b611043565b6101f661048a366004611d34565b61116b565b6101f661049d366004611d8f565b611240565b3480156104ae57600080fd5b506101f66104bd3660046118ce565b611357565b3480156104ce57600080fd5b506101f66104dd366004611845565b611467565b60006001600160e01b03198216637965db0b60e01b148061051357506301ffc9a760e01b6001600160e01b03198316145b92915050565b336000805160206124858339815191521461056257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b60405180910390fd5b61056a61148d565b600061058060036001600160401b0386166114b3565b604051630a24e8a960e41b81526001600160401b03851660048201526001600160a01b0384811660248301529192509082169063a24e8a9090604401600060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b50506040516001600160a01b03851681526001600160401b038087169350871691507f5267932e6c1b678e74efba1e4d6c8b3fd7504cf0fa8eea462efac2c590a21d56906020015b60405180910390a350505050565b336000805160206124858339815191521461068057336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61068861148d565b600061069e60036001600160401b0385166114b3565b60405163434698bb60e01b81529091506001600160a01b0382169063434698bb906106cd908590600401611f18565b600060405180830381600087803b1580156106e757600080fd5b505af11580156106fb573d6000803e3d6000fd5b50505050826001600160401b03167fde25c2b146db36cbc91715fdf29cb0eb556eed7678e0bf13563bf7050e8f0bbd836040516107389190611f18565b60405180910390a2505050565b60008061075c60036001600160401b0386166114b3565b6040516374ceeb5560e01b81526001600160401b03851660048201529091506001600160a01b038216906374ceeb55906024015b602060405180830381865afa1580156107ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d19190611f2b565b949350505050565b600082815260016020819052604090912001546107f5816114c6565b6107ff83836114d3565b50505050565b336000805160206124858339815191521461084557336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61084d61148d565b600061086360036001600160401b0389166114b3565b604051630af7d74360e01b81529091506001600160a01b03821690630af7d7439061089a9089908990899089908990600401611f48565b600060405180830381600087803b1580156108b457600080fd5b505af11580156108c8573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f7d2ac4c1544e07516def74ce3ada12ff791868ed07d6da82694ae2c0342c8371878787876040516109159493929190611f82565b60405180910390a350505050505050565b6001600160a01b038116331461094f5760405163334bd91960e11b815260040160405180910390fd5b610959828261154c565b505050565b336000805160206124858339815191521461099e57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b6109a661148d565b60006109bc60036001600160401b0386166114b3565b60405163410e3df160e11b81529091506001600160a01b0382169063821c7be2906109ed9086908690600401611fac565b600060405180830381600087803b158015610a0757600080fd5b505af1158015610a1b573d6000803e3d6000fd5b50505050816001600160401b0316846001600160401b03167f4ca48d7cb411035a931da7a686ea77bc413069de12d844c47daf9242b765cba4856040516106329190611f18565b3360008051602061248583398151915214610aa257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610aaa61148d565b6000610ac060036001600160401b0389166114b3565b604051639838caa360e01b81529091506001600160a01b03821690639838caa390610af79089908990899089908990600401611fd7565b600060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b50506040805160ff891681526001600160401b038881166020830152808b1694508b1692507fa9aaaef624d196d961d053fc29d4331e5cb45d62195d99814d29a94f46fa9d4b9101610915565b3360008051602061248583398151915214610bb257336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610bba61148d565b6000610bd060036001600160401b038d166114b3565b6040516332e72cfd60e11b81529091506001600160a01b038216906365ce59fa90610c0f908d908d908d908d908d908d908d908d908d90600401612061565b600060405180830381600087803b158015610c2957600080fd5b505af1158015610c3d573d6000803e3d6000fd5b50506040516001600160401b0385811682526001600160a01b038d169350808e1692508e16907f43200f1363ce7ac3780a4c2c5835bf74800937ca5cbc69c4f4d666cf92b0c54c9060200160405180910390a45050505050505050505050565b3360008051602061248583398151915214610cdd57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610ce561148d565b6000610cfb60036001600160401b0387166114b3565b604051634e82087760e11b81529091506001600160a01b03821690639d0410ee90610d2e90879087908790600401612136565b600060405180830381600087803b158015610d4857600080fd5b505af1158015610d5c573d6000803e3d6000fd5b50505050846001600160401b03167f7814301100cb38a35027dd63a29aa14c3f73188f15cf9f027655257c45016e8785604051610d999190611f18565b60405180910390a25050505050565b3360008051602061248583398151915214610de857336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610df061148d565b6000610e0660036001600160401b038a166114b3565b604051636bef5a4160e11b81529091506001600160a01b0382169063d7deb48290610e3f908a908a908a908a908a908a90600401612166565b600060405180830381600087803b158015610e5957600080fd5b505af1158015610e6d573d6000803e3d6000fd5b5050604080516001600160a01b03891681526001600160401b038681166020830152808b1694508b811693508c16917f93927390d124732c66289c6e22370514ddd612a9cc6bff5671cbf2cbc15ddfe3910160405180910390a45050505050505050565b600080610ee860036001600160401b0386166114b3565b60405163052d37d360e21b81526001600160401b03851660048201529091506001600160a01b038216906314b4df4c90602401610790565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3360008051602061248583398151915214610f8b57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b610f9361148d565b6000610fa960036001600160401b0385166114b3565b60405163fe0dd37160e01b81529091506001600160a01b0382169063fe0dd37190610fd8908590600401611f18565b600060405180830381600087803b158015610ff257600080fd5b505af1158015611006573d6000803e3d6000fd5b50505050826001600160401b03167febc442018e78570634a88dbac83d4677ae1a5cf8491fb0fc166a7306ba1ff051836040516107389190611f18565b336000805160206124858339815191521461108357336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61108b61148d565b60006110a160036001600160401b038c166114b3565b604051631be14b3160e11b81529091506001600160a01b038216906337c29662906110de908c908c908c908c908c908c908c908c906004016121b6565b600060405180830381600087803b1580156110f857600080fd5b505af115801561110c573d6000803e3d6000fd5b50505050886001600160401b03168a6001600160401b03167f08e18861659838cad8b04f4687aca1dfb93336e750acf5c3699637ed8ca4c27a8a8a8a60405161115793929190612222565b60405180910390a350505050505050505050565b33600080516020612485833981519152146111ab57336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b6111b361148d565b6111d96001600160401b0384166111d06040840160208501612256565b600391906115b9565b506111ef60066001600160401b038516846115b9565b50826001600160401b0316826001600160a01b03167f278018182b7c51e2da72c1f465c26c12d9606099af0f08db420378344b352223836040516112339190612287565b60405180910390a3505050565b336000805160206124858339815191521461128057336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61128861148d565b600061129e60036001600160401b0387166114b3565b60405163bb43abd960e01b81529091506001600160a01b0382169063bb43abd9906112d19087908790879060040161242a565b600060405180830381600087803b1580156112eb57600080fd5b505af11580156112ff573d6000803e3d6000fd5b50505050826001600160401b0316856001600160401b03167f219c2fdfbe4f111dda584eefbcb4eb2370cec850e2a79e4fed3a8f708006e7a9868560405161134892919061245f565b60405180910390a35050505050565b336000805160206124858339815191521461139757336000805160206124858339815191526040516359afe8af60e11b8152600401610559929190611dfd565b61139f61148d565b60006113b560036001600160401b0389166114b3565b60405163e926cbd160e01b81529091506001600160a01b0382169063e926cbd1906113ec9089908990899089908990600401611f48565b600060405180830381600087803b15801561140657600080fd5b505af115801561141a573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f0145a8acdb5e19e431ea924e2c8997b01f0869cad2a2c6927c8645a5938cf0c3878787876040516109159493929190611f82565b60008281526001602081905260409091200154611483816114c6565b6107ff838361154c565b60025460ff16156114b15760405163d93c066560e01b815260040160405180910390fd5b565b60006114bf83836115cf565b9392505050565b6114d08133611616565b50565b60006114df8383610f20565b6115445760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610513565b506000610513565b60006115588383610f20565b156115445760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610513565b60006107d184846001600160a01b038516611653565b6000818152600283016020526040812054801580156115f557506115f38484611670565b155b156114bf5760405163015ab34360e11b815260048101849052602401610559565b6116208282610f20565b61164f5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610559565b5050565b600082815260028401602052604081208290556107d1848461167c565b60006114bf8383611688565b60006114bf83836116a0565b600081815260018301602052604081205415156114bf565b600081815260018301602052604081205461154457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610513565b6000602082840312156116f957600080fd5b81356001600160e01b0319811681146114bf57600080fd5b80356001600160401b038116811461172857600080fd5b919050565b6001600160a01b03811681146114d057600080fd5b80356117288161172d565b60008060006060848603121561176257600080fd5b61176b84611711565b925061177960208501611711565b915060408401356117898161172d565b809150509250925092565b600060c082840312156117a657600080fd5b50919050565b600080604083850312156117bf57600080fd5b6117c883611711565b915060208301356001600160401b038111156117e357600080fd5b6117ef85828601611794565b9150509250929050565b60006020828403121561180b57600080fd5b5035919050565b6000806040838503121561182557600080fd5b61182e83611711565b915061183c60208401611711565b90509250929050565b6000806040838503121561185857600080fd5b82359150602083013561186a8161172d565b809150509250929050565b60008083601f84011261188757600080fd5b5081356001600160401b0381111561189e57600080fd5b6020830191508360208285010111156118b657600080fd5b9250929050565b803560ff8116811461172857600080fd5b60008060008060008060a087890312156118e757600080fd5b6118f087611711565b95506118fe60208801611711565b945060408701356001600160401b0381111561191957600080fd5b61192589828a01611875565b90955093506119389050606088016118bd565b9150608087013590509295509295509295565b60008060006060848603121561196057600080fd5b61196984611711565b925060208401356001600160401b0381111561198457600080fd5b61199086828701611794565b92505061199f60408501611711565b90509250925092565b60008060008060008060a087890312156119c157600080fd5b6119ca87611711565b95506119d860208801611711565b94506119e6604088016118bd565b93506119f460608801611711565b925060808701356001600160401b03811115611a0f57600080fd5b611a1b89828a01611875565b979a9699509497509295939492505050565b60008083601f840112611a3f57600080fd5b5081356001600160401b03811115611a5657600080fd5b6020830191508360208260051b85010111156118b657600080fd5b60008060008060008060008060008060e08b8d031215611a9057600080fd5b611a998b611711565b9950611aa760208c01611711565b985060408b0135611ab78161172d565b975060608b01356001600160401b0380821115611ad357600080fd5b611adf8e838f01611a2d565b909950975060808d0135915080821115611af857600080fd5b611b048e838f01611875565b909750955060a08d0135915080821115611b1d57600080fd5b50611b2a8d828e01611a2d565b9094509250611b3d905060c08c01611711565b90509295989b9194979a5092959850565b60008060008060608587031215611b6457600080fd5b611b6d85611711565b935060208501356001600160401b0380821115611b8957600080fd5b611b9588838901611794565b94506040870135915080821115611bab57600080fd5b50611bb887828801611875565b95989497509550505050565b600080600080600080600060c0888a031215611bdf57600080fd5b611be888611711565b9650611bf660208901611711565b9550611c0460408901611711565b94506060880135611c148161172d565b935060808801356001600160401b03811115611c2f57600080fd5b611c3b8a828b01611a2d565b9094509250611c4e905060a08901611711565b905092959891949750929550565b600080600080600080600080600060e08a8c031215611c7a57600080fd5b611c838a611711565b9850611c9160208b01611711565b9750611c9f60408b016118bd565b9650611cad60608b01611711565b955060808a01356001600160401b0380821115611cc957600080fd5b611cd58d838e01611794565b965060a08c0135915080821115611ceb57600080fd5b611cf78d838e01611875565b909650945060c08c0135915080821115611d1057600080fd5b50611d1d8c828d01611875565b915080935050809150509295985092959850929598565b600080600060608486031215611d4957600080fd5b611d5284611711565b92506020840135611d628161172d565b915060408401356001600160401b03811115611d7d57600080fd5b84016060818703121561178957600080fd5b60008060008060808587031215611da557600080fd5b611dae85611711565b935060208501356001600160401b03811115611dc957600080fd5b611dd587828801611794565b935050611de460408601611711565b9150611df2606086016118bd565b905092959194509250565b6001600160a01b0392831681529116602082015260400190565b6000808335601e19843603018112611e2e57600080fd5b83016020810192503590506001600160401b03811115611e4d57600080fd5b8036038213156118b657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000611e918283611e17565b60c08552611ea360c086018284611e5c565b9150506001600160401b0380611ebb60208601611711565b16602086015280611ece60408601611711565b16604086015280611ee160608601611711565b16606086015280611ef460808601611711565b16608086015280611f0760a08601611711565b1660a0860152508091505092915050565b6020815260006114bf6020830184611e85565b600060208284031215611f3d57600080fd5b81516114bf8161172d565b6001600160401b0386168152608060208201526000611f6b608083018688611e5c565b60ff94909416604083015250606001529392505050565b606081526000611f96606083018688611e5c565b60ff949094166020830152506040015292915050565b604081526000611fbf6040830185611e85565b90506001600160401b03831660208301529392505050565b60006001600160401b03808816835260ff871660208401528086166040840152506080606083015261200d608083018486611e5c565b979650505050505050565b8183526000602080850194508260005b8581101561205657813561203b8161172d565b6001600160a01b031687529582019590820190600101612028565b509495945050505050565b6001600160401b038a1681526001600160a01b038916602082015260c0604082018190528101879052600060e0600589901b830181019083018a835b8b8110156120e55785840360df190183528135368e900360be190181126120c357600080fd5b6120cf858f8301611e85565b945050602092830192919091019060010161209d565b50505082810360608401526120fb81888a611e5c565b90508281036080840152612110818688612018565b91505061212860a08301846001600160401b03169052565b9a9950505050505050505050565b6040815260006121496040830186611e85565b828103602084015261215c818587611e5c565b9695505050505050565b60006001600160401b038089168352808816602084015260018060a01b038716604084015260a060608401526121a060a084018688612018565b9150808416608084015250979650505050505050565b60006001600160401b03808b16835260ff8a16602084015280891660408401525060c060608301526121eb60c0830188611e85565b82810360808401526121fe818789611e5c565b905082810360a0840152612213818587611e5c565b9b9a5050505050505050505050565b60ff841681526001600160401b038316602082015260606040820152600061224d6060830184611e85565b95945050505050565b60006020828403121561226857600080fd5b81356114bf8161172d565b803563ffffffff8116811461172857600080fd5b602081526000823560fe198436030181126122a157600080fd5b6060602084015283016122b48180611e17565b6101008060808701526122cc61018087018385611e5c565b92506122db6020850185611e17565b9250607f19808886030160a08901526122f5858584611e5c565b94506123046040870187611e17565b94509150808886030160c089015261231d858584611e5c565b945061232c6060870187611e17565b94509150808886030160e0890152612345858584611e5c565b94506123546080870187611e17565b9450915080888603018389015261236c858584611e5c565b945061237b60a0870187611e17565b945092508088860301610120890152612395858585611e5c565b94506123a460c0870187611e17565b9450925080888603016101408901526123be858585611e5c565b94506123cd60e0870187611e17565b9650935080888603016101608901525050506123ea828483611e5c565b925050506123fa60208501611742565b6001600160a01b03811660408501525061241660408501612273565b63ffffffff81166060850152509392505050565b60608152600061243d6060830186611e85565b90506001600160401b038416602083015260ff83166040830152949350505050565b6040815260006124726040830185611e85565b905060ff83166020830152939250505056fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000814000a +0x60806040526004361061019c5760003560e01c806382a1ece4116100ec578063a6a785381161008a578063b9315d3a11610064578063b9315d3a1461047c578063c97008e01461048f578063d547741f146104af578063f9e13845146104cf57600080fd5b8063a6a7853814610443578063a8f7c5ed14610456578063b89af9041461046957600080fd5b806391d14854116100c657806391d14854146103cf578063987ab9db146103ef578063a217fddf14610410578063a4d91fe91461042557600080fd5b806382a1ece41461036d578063884673ac1461038d5780638e6f8c60146103af57600080fd5b80632f2ff15d11610159578063410fdec811610133578063410fdec81461030f5780634984ee6b1461032f5780635c975abb14610342578063727391f21461035a57600080fd5b80632f2ff15d146102af57806333db3920146102cf57806336568abe146102ef57600080fd5b806301ffc9a7146101a15780630633da77146101d65780630d0dd399146101f85780631fb27b3414610230578063248a9ca314610250578063274ef0151461028f575b600080fd5b3480156101ad57600080fd5b506101c16101bc366004611707565b6104e2565b60405190151581526020015b60405180910390f35b3480156101e257600080fd5b506101f66101f136600461176d565b610519565b005b34801561020457600080fd5b50600054610218906001600160a01b031681565b6040516001600160a01b0390911681526020016101cd565b34801561023c57600080fd5b506101f661024b3660046117cc565b610640565b34801561025c57600080fd5b5061028161026b366004611819565b6000908152600160208190526040909120015490565b6040519081526020016101cd565b34801561029b57600080fd5b506102186102aa366004611832565b610745565b3480156102bb57600080fd5b506101f66102ca366004611865565b6107d9565b3480156102db57600080fd5b506101f66102ea3660046118ee565b610805565b3480156102fb57600080fd5b506101f661030a366004611865565b610926565b34801561031b57600080fd5b506101f661032a36600461196b565b61095e565b6101f661033d3660046119c8565b610a62565b34801561034e57600080fd5b5060025460ff166101c1565b6101f6610368366004611a4d565b610b72565b34801561037957600080fd5b506101f6610388366004611ac3565b610c7d565b34801561039957600080fd5b5061021860008051602061256a83398151915281565b3480156103bb57600080fd5b506102186103ca366004611832565b610da6565b3480156103db57600080fd5b506101c16103ea366004611865565b610df5565b3480156103fb57600080fd5b5060008051602061256a833981519152610218565b34801561041c57600080fd5b50610281600081565b34801561043157600080fd5b506000546001600160a01b0316610218565b6101f66104513660046117cc565b610e20565b6101f6610464366004611b8d565b610f18565b6101f6610477366004611c65565b611040565b6101f661048a366004611cc0565b611115565b34801561049b57600080fd5b506101f66104aa3660046118ee565b61122c565b3480156104bb57600080fd5b506101f66104ca366004611865565b61133c565b6101f66104dd366004611d2e565b611362565b60006001600160e01b03198216637965db0b60e01b148061051357506301ffc9a760e01b6001600160e01b03198316145b92915050565b3360008051602061256a83398151915214610562573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b60405180910390fd5b61056a6114ad565b600061058060036001600160401b0386166114d3565b604051630a24e8a960e41b81526001600160401b03851660048201526001600160a01b0384811660248301529192509082169063a24e8a9090604401600060405180830381600087803b1580156105d657600080fd5b505af11580156105ea573d6000803e3d6000fd5b50506040516001600160a01b03851681526001600160401b038087169350871691507f5267932e6c1b678e74efba1e4d6c8b3fd7504cf0fa8eea462efac2c590a21d56906020015b60405180910390a350505050565b3360008051602061256a83398151915214610680573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6106886114ad565b600061069e60036001600160401b0385166114d3565b60405163434698bb60e01b81529091506001600160a01b0382169063434698bb906106cd908590600401611e93565b600060405180830381600087803b1580156106e757600080fd5b505af11580156106fb573d6000803e3d6000fd5b50505050826001600160401b03167fde25c2b146db36cbc91715fdf29cb0eb556eed7678e0bf13563bf7050e8f0bbd836040516107389190611e93565b60405180910390a2505050565b60008061075c60036001600160401b0386166114d3565b6040516374ceeb5560e01b81526001600160401b03851660048201529091506001600160a01b038216906374ceeb55906024015b602060405180830381865afa1580156107ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d19190611ea6565b949350505050565b600082815260016020819052604090912001546107f5816114e6565b6107ff83836114f3565b50505050565b3360008051602061256a83398151915214610845573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b61084d6114ad565b600061086360036001600160401b0389166114d3565b604051630af7d74360e01b81529091506001600160a01b03821690630af7d7439061089a9089908990899089908990600401611ec3565b600060405180830381600087803b1580156108b457600080fd5b505af11580156108c8573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f7d2ac4c1544e07516def74ce3ada12ff791868ed07d6da82694ae2c0342c8371878787876040516109159493929190611efd565b60405180910390a350505050505050565b6001600160a01b038116331461094f5760405163334bd91960e11b815260040160405180910390fd5b610959828261156c565b505050565b3360008051602061256a8339815191521461099e573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6109a66114ad565b60006109bc60036001600160401b0386166114d3565b60405163410e3df160e11b81529091506001600160a01b0382169063821c7be2906109ed9086908690600401611f27565b600060405180830381600087803b158015610a0757600080fd5b505af1158015610a1b573d6000803e3d6000fd5b50505050816001600160401b0316846001600160401b03167f4ca48d7cb411035a931da7a686ea77bc413069de12d844c47daf9242b765cba4856040516106329190611e93565b3360008051602061256a83398151915214610aa2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610aaa6114ad565b6000610ac060036001600160401b0389166114d3565b604051639838caa360e01b81529091506001600160a01b03821690639838caa390610af79089908990899089908990600401611f52565b600060405180830381600087803b158015610b1157600080fd5b505af1158015610b25573d6000803e3d6000fd5b50506040805160ff891681526001600160401b038881166020830152808b1694508b1692507fa9aaaef624d196d961d053fc29d4331e5cb45d62195d99814d29a94f46fa9d4b9101610915565b3360008051602061256a83398151915214610bb2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610bba6114ad565b6000610bd060036001600160401b0387166114d3565b604051634e82087760e11b81529091506001600160a01b03821690639d0410ee90610c0390879087908790600401611f93565b600060405180830381600087803b158015610c1d57600080fd5b505af1158015610c31573d6000803e3d6000fd5b50505050846001600160401b03167f7814301100cb38a35027dd63a29aa14c3f73188f15cf9f027655257c45016e8785604051610c6e9190611e93565b60405180910390a25050505050565b3360008051602061256a83398151915214610cbd573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610cc56114ad565b6000610cdb60036001600160401b038a166114d3565b604051636bef5a4160e11b81529091506001600160a01b0382169063d7deb48290610d14908a908a908a908a908a908a90600401611fc3565b600060405180830381600087803b158015610d2e57600080fd5b505af1158015610d42573d6000803e3d6000fd5b5050604080516001600160a01b03891681526001600160401b038681166020830152808b1694508b811693508c16917f93927390d124732c66289c6e22370514ddd612a9cc6bff5671cbf2cbc15ddfe3910160405180910390a45050505050505050565b600080610dbd60036001600160401b0386166114d3565b60405163052d37d360e21b81526001600160401b03851660048201529091506001600160a01b038216906314b4df4c90602401610790565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b3360008051602061256a83398151915214610e60573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610e686114ad565b6000610e7e60036001600160401b0385166114d3565b60405163fe0dd37160e01b81529091506001600160a01b0382169063fe0dd37190610ead908590600401611e93565b600060405180830381600087803b158015610ec757600080fd5b505af1158015610edb573d6000803e3d6000fd5b50505050826001600160401b03167febc442018e78570634a88dbac83d4677ae1a5cf8491fb0fc166a7306ba1ff051836040516107389190611e93565b3360008051602061256a83398151915214610f58573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b610f606114ad565b6000610f7660036001600160401b038c166114d3565b604051631be14b3160e11b81529091506001600160a01b038216906337c2966290610fb3908c908c908c908c908c908c908c908c9060040161204a565b600060405180830381600087803b158015610fcd57600080fd5b505af1158015610fe1573d6000803e3d6000fd5b50505050886001600160401b03168a6001600160401b03167f08e18861659838cad8b04f4687aca1dfb93336e750acf5c3699637ed8ca4c27a8a8a8a60405161102c939291906120b6565b60405180910390a350505050505050505050565b3360008051602061256a83398151915214611080573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6110886114ad565b6110ae6001600160401b0384166110a560408401602085016120ea565b600391906115d9565b506110c460066001600160401b038516846115d9565b50826001600160401b0316826001600160a01b03167f278018182b7c51e2da72c1f465c26c12d9606099af0f08db420378344b35222383604051611108919061211b565b60405180910390a3505050565b3360008051602061256a83398151915214611155573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b61115d6114ad565b600061117360036001600160401b0387166114d3565b60405163bb43abd960e01b81529091506001600160a01b0382169063bb43abd9906111a6908790879087906004016122be565b600060405180830381600087803b1580156111c057600080fd5b505af11580156111d4573d6000803e3d6000fd5b50505050826001600160401b0316856001600160401b03167f219c2fdfbe4f111dda584eefbcb4eb2370cec850e2a79e4fed3a8f708006e7a9868560405161121d9291906122f3565b60405180910390a35050505050565b3360008051602061256a8339815191521461126c573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6112746114ad565b600061128a60036001600160401b0389166114d3565b60405163e926cbd160e01b81529091506001600160a01b0382169063e926cbd1906112c19089908990899089908990600401611ec3565b600060405180830381600087803b1580156112db57600080fd5b505af11580156112ef573d6000803e3d6000fd5b50505050856001600160401b0316876001600160401b03167f0145a8acdb5e19e431ea924e2c8997b01f0869cad2a2c6927c8645a5938cf0c3878787876040516109159493929190611efd565b60008281526001602081905260409091200154611358816114e6565b6107ff838361156c565b3360008051602061256a833981519152146113a2573360008051602061256a8339815191526040516359afe8af60e11b8152600401610559929190611d78565b6113aa6114ad565b60006113c060036001600160401b0385166114d3565b604051638b24806560e01b81529091506001600160a01b03821690638b248065906113ef90859060040161242d565b600060405180830381600087803b15801561140957600080fd5b505af115801561141d573d6000803e3d6000fd5b506114329250505060408301602084016120ea565b6001600160a01b03166114486020840184612523565b6001600160401b039081169085167f4def5362750954077cbc9dad1ab88058dd6d0ed894ba05f8f147a7a2fe204b2261148760c0870160a08801612523565b8660c0018761010001356040516114a09392919061253e565b60405180910390a4505050565b60025460ff16156114d15760405163d93c066560e01b815260040160405180910390fd5b565b60006114df83836115ef565b9392505050565b6114f08133611636565b50565b60006114ff8383610df5565b6115645760008381526001602081815260408084206001600160a01b0387168086529252808420805460ff19169093179092559051339286917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a4506001610513565b506000610513565b60006115788383610df5565b156115645760008381526001602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610513565b60006107d184846001600160a01b038516611673565b60008181526002830160205260408120548015801561161557506116138484611690565b155b156114df5760405163015ab34360e11b815260048101849052602401610559565b6116408282610df5565b61166f5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610559565b5050565b600082815260028401602052604081208290556107d1848461169c565b60006114df83836116a8565b60006114df83836116c0565b600081815260018301602052604081205415156114df565b600081815260018301602052604081205461156457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610513565b60006020828403121561171957600080fd5b81356001600160e01b0319811681146114df57600080fd5b80356001600160401b038116811461174857600080fd5b919050565b6001600160a01b03811681146114f057600080fd5b80356117488161174d565b60008060006060848603121561178257600080fd5b61178b84611731565b925061179960208501611731565b915060408401356117a98161174d565b809150509250925092565b600060c082840312156117c657600080fd5b50919050565b600080604083850312156117df57600080fd5b6117e883611731565b915060208301356001600160401b0381111561180357600080fd5b61180f858286016117b4565b9150509250929050565b60006020828403121561182b57600080fd5b5035919050565b6000806040838503121561184557600080fd5b61184e83611731565b915061185c60208401611731565b90509250929050565b6000806040838503121561187857600080fd5b82359150602083013561188a8161174d565b809150509250929050565b60008083601f8401126118a757600080fd5b5081356001600160401b038111156118be57600080fd5b6020830191508360208285010111156118d657600080fd5b9250929050565b803560ff8116811461174857600080fd5b60008060008060008060a0878903121561190757600080fd5b61191087611731565b955061191e60208801611731565b945060408701356001600160401b0381111561193957600080fd5b61194589828a01611895565b90955093506119589050606088016118dd565b9150608087013590509295509295509295565b60008060006060848603121561198057600080fd5b61198984611731565b925060208401356001600160401b038111156119a457600080fd5b6119b0868287016117b4565b9250506119bf60408501611731565b90509250925092565b60008060008060008060a087890312156119e157600080fd5b6119ea87611731565b95506119f860208801611731565b9450611a06604088016118dd565b9350611a1460608801611731565b925060808701356001600160401b03811115611a2f57600080fd5b611a3b89828a01611895565b979a9699509497509295939492505050565b60008060008060608587031215611a6357600080fd5b611a6c85611731565b935060208501356001600160401b0380821115611a8857600080fd5b611a94888389016117b4565b94506040870135915080821115611aaa57600080fd5b50611ab787828801611895565b95989497509550505050565b600080600080600080600060c0888a031215611ade57600080fd5b611ae788611731565b9650611af560208901611731565b9550611b0360408901611731565b94506060880135611b138161174d565b935060808801356001600160401b0380821115611b2f57600080fd5b818a0191508a601f830112611b4357600080fd5b813581811115611b5257600080fd5b8b60208260051b8501011115611b6757600080fd5b602083019550809450505050611b7f60a08901611731565b905092959891949750929550565b600080600080600080600080600060e08a8c031215611bab57600080fd5b611bb48a611731565b9850611bc260208b01611731565b9750611bd060408b016118dd565b9650611bde60608b01611731565b955060808a01356001600160401b0380821115611bfa57600080fd5b611c068d838e016117b4565b965060a08c0135915080821115611c1c57600080fd5b611c288d838e01611895565b909650945060c08c0135915080821115611c4157600080fd5b50611c4e8c828d01611895565b915080935050809150509295985092959850929598565b600080600060608486031215611c7a57600080fd5b611c8384611731565b92506020840135611c938161174d565b915060408401356001600160401b03811115611cae57600080fd5b8401606081870312156117a957600080fd5b60008060008060808587031215611cd657600080fd5b611cdf85611731565b935060208501356001600160401b03811115611cfa57600080fd5b611d06878288016117b4565b935050611d1560408601611731565b9150611d23606086016118dd565b905092959194509250565b60008060408385031215611d4157600080fd5b611d4a83611731565b915060208301356001600160401b03811115611d6557600080fd5b8301610120818603121561188a57600080fd5b6001600160a01b0392831681529116602082015260400190565b6000808335601e19843603018112611da957600080fd5b83016020810192503590506001600160401b03811115611dc857600080fd5b8036038213156118d657600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000611e0c8283611d92565b60c08552611e1e60c086018284611dd7565b9150506001600160401b0380611e3660208601611731565b16602086015280611e4960408601611731565b16604086015280611e5c60608601611731565b16606086015280611e6f60808601611731565b16608086015280611e8260a08601611731565b1660a0860152508091505092915050565b6020815260006114df6020830184611e00565b600060208284031215611eb857600080fd5b81516114df8161174d565b6001600160401b0386168152608060208201526000611ee6608083018688611dd7565b60ff94909416604083015250606001529392505050565b606081526000611f11606083018688611dd7565b60ff949094166020830152506040015292915050565b604081526000611f3a6040830185611e00565b90506001600160401b03831660208301529392505050565b60006001600160401b03808816835260ff8716602084015280861660408401525060806060830152611f88608083018486611dd7565b979650505050505050565b604081526000611fa66040830186611e00565b8281036020840152611fb9818587611dd7565b9695505050505050565b6001600160401b0387811682528681166020808401919091526001600160a01b03878116604085015260a06060850181905284018690526000928792909160c08601855b8981101561202e57853561201a8161174d565b831682529483019490830190600101612007565b5080955050505080851660808501525050979650505050505050565b60006001600160401b03808b16835260ff8a16602084015280891660408401525060c0606083015261207f60c0830188611e00565b8281036080840152612092818789611dd7565b905082810360a08401526120a7818587611dd7565b9b9a5050505050505050505050565b60ff841681526001600160401b03831660208201526060604082015260006120e16060830184611e00565b95945050505050565b6000602082840312156120fc57600080fd5b81356114df8161174d565b803563ffffffff8116811461174857600080fd5b602081526000823560fe1984360301811261213557600080fd5b6060602084015283016121488180611d92565b61010080608087015261216061018087018385611dd7565b925061216f6020850185611d92565b9250607f19808886030160a0890152612189858584611dd7565b94506121986040870187611d92565b94509150808886030160c08901526121b1858584611dd7565b94506121c06060870187611d92565b94509150808886030160e08901526121d9858584611dd7565b94506121e86080870187611d92565b94509150808886030183890152612200858584611dd7565b945061220f60a0870187611d92565b945092508088860301610120890152612229858585611dd7565b945061223860c0870187611d92565b945092508088860301610140890152612252858585611dd7565b945061226160e0870187611d92565b96509350808886030161016089015250505061227e828483611dd7565b9250505061228e60208501611762565b6001600160a01b0381166040850152506122aa60408501612107565b63ffffffff81166060850152509392505050565b6060815260006122d16060830186611e00565b90506001600160401b038416602083015260ff83166040830152949350505050565b6040815260006123066040830185611e00565b905060ff831660208301529392505050565b6000808335601e1984360301811261232f57600080fd5b83016020810192503590506001600160401b0381111561234e57600080fd5b8060051b36038213156118d657600080fd5b81835260006020808501808196508560051b81019150846000805b888110156123ba578385038a52823560be1989360301811261239b578283fd5b6123a7868a8301611e00565b9a87019a9550509185019160010161237b565b509298975050505050505050565b8183526000602080850194508260005b858110156124065781356123eb8161174d565b6001600160a01b0316875295820195908201906001016123d8565b509495945050505050565b80356002811061242057600080fd5b8252602090810135910152565b602081526001600160401b0361244283611731565b166020820152600061245660208401611762565b6001600160a01b0381166040840152506124736040840184612318565b61012080606086015261248b61014086018385612360565b925061249a6060870187611d92565b9250601f19808786030160808801526124b4858584611dd7565b94506124c36080890189612318565b94509150808786030160a0880152506124dd8484836123c8565b9350506124ec60a08701611731565b6001600160401b03811660c0870152915061250d60e0860160c08801612411565b6101008601358186015250508091505092915050565b60006020828403121561253557600080fd5b6114df82611731565b6001600160401b03841681526080810161255b6020830185612411565b82606083015294935050505056fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000814000a diff --git a/pallets/services/src/test-artifacts/MockERC20.hex b/pallets/services/src/test-artifacts/MockERC20.hex new file mode 100644 index 00000000..99a9f49e --- /dev/null +++ b/pallets/services/src/test-artifacts/MockERC20.hex @@ -0,0 +1 @@ +0x608060405234801561001057600080fd5b50600436106100f55760003560e01c806340c10f19116100975780639dc29fac116100665780639dc29fac146101f6578063a9059cbb14610209578063d505accf1461021c578063dd62ed3e1461022f57600080fd5b806340c10f191461019257806370a08231146101a55780637ecebe00146101ce57806395d89b41146101ee57600080fd5b806318160ddd116100d357806318160ddd1461015057806323b872dd14610162578063313ce567146101755780633644e5151461018a57600080fd5b806306fdde03146100fa578063095ea7b3146101185780631624f6c61461013b575b600080fd5b610102610268565b60405161010f9190610ab0565b60405180910390f35b61012b610126366004610b1a565b6102fa565b604051901515815260200161010f565b61014e610149366004610bf8565b610367565b005b6003545b60405190815260200161010f565b61012b610170366004610c6c565b610406565b60025460405160ff909116815260200161010f565b610154610509565b61014e6101a0366004610b1a565b61052f565b6101546101b3366004610ca8565b6001600160a01b031660009081526004602052604090205490565b6101546101dc366004610ca8565b60086020526000908152604090205481565b61010261053d565b61014e610204366004610b1a565b61054c565b61012b610217366004610b1a565b610556565b61014e61022a366004610cc3565b6105db565b61015461023d366004610d2d565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205490565b60606000805461027790610d60565b80601f01602080910402602001604051908101604052809291908181526020018280546102a390610d60565b80156102f05780601f106102c5576101008083540402835291602001916102f0565b820191906000526020600020905b8154815290600101906020018083116102d357829003601f168201915b5050505050905090565b3360008181526005602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103559086815260200190565b60405180910390a35060015b92915050565b60095460ff16156103b55760405162461bcd60e51b81526020600482015260136024820152721053149150511657d253925512505312569151606a1b60448201526064015b60405180910390fd5b60006103c18482610de9565b5060016103ce8382610de9565b506002805460ff191660ff83161790556103e6610839565b6006556103f1610852565b60075550506009805460ff1916600117905550565b6001600160a01b038316600090815260056020908152604080832033845290915281205460001981146104625761043d81846108f5565b6001600160a01b03861660009081526005602090815260408083203384529091529020555b6001600160a01b03851660009081526004602052604090205461048590846108f5565b6001600160a01b0380871660009081526004602052604080822093909355908616815220546104b49084610958565b6001600160a01b038086166000818152600460205260409081902093909355915190871690600080516020610f75833981519152906104f69087815260200190565b60405180910390a3506001949350505050565b6000600654610516610839565b1461052857610523610852565b905090565b5060075490565b61053982826109b7565b5050565b60606001805461027790610d60565b6105398282610a34565b3360009081526004602052604081205461057090836108f5565b33600090815260046020526040808220929092556001600160a01b0385168152205461059c9083610958565b6001600160a01b038416600081815260046020526040908190209290925590513390600080516020610f75833981519152906103559086815260200190565b4284101561062b5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064016103ac565b60006001610637610509565b6001600160a01b038a16600090815260086020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d9290919061068583610ebf565b909155506040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810188905260e001604051602081830303815290604052805190602001206040516020016106fe92919061190160f01b81526002810192909252602282015260420190565b60408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa15801561075c573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906107925750876001600160a01b0316816001600160a01b0316145b6107cf5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b60448201526064016103ac565b6001600160a01b0381811660009081526005602090815260408083208b8516808552908352928190208a90555189815291928b16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35050505050505050565b6000610aac8061084b63ffffffff8216565b9250505090565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516108849190610ed8565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66108b5610839565b604080516020810195909552840192909252606083015260808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6000818310156109475760405162461bcd60e51b815260206004820152601c60248201527f45524332303a207375627472616374696f6e20756e646572666c6f770000000060448201526064016103ac565b6109518284610f4e565b9392505050565b6000806109658385610f61565b9050838110156109515760405162461bcd60e51b815260206004820152601860248201527f45524332303a206164646974696f6e206f766572666c6f77000000000000000060448201526064016103ac565b6109c360035482610958565b6003556001600160a01b0382166000908152600460205260409020546109e99082610958565b6001600160a01b038316600081815260046020526040808220939093559151909190600080516020610f7583398151915290610a289085815260200190565b60405180910390a35050565b6001600160a01b038216600090815260046020526040902054610a5790826108f5565b6001600160a01b038316600090815260046020526040902055600354610a7d90826108f5565b6003556040518181526000906001600160a01b03841690600080516020610f7583398151915290602001610a28565b4690565b600060208083528351808285015260005b81811015610add57858101830151858201604001528201610ac1565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610b1557600080fd5b919050565b60008060408385031215610b2d57600080fd5b610b3683610afe565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610b6b57600080fd5b813567ffffffffffffffff80821115610b8657610b86610b44565b604051601f8301601f19908116603f01168101908282118183101715610bae57610bae610b44565b81604052838152866020858801011115610bc757600080fd5b836020870160208301376000602085830101528094505050505092915050565b803560ff81168114610b1557600080fd5b600080600060608486031215610c0d57600080fd5b833567ffffffffffffffff80821115610c2557600080fd5b610c3187838801610b5a565b94506020860135915080821115610c4757600080fd5b50610c5486828701610b5a565b925050610c6360408501610be7565b90509250925092565b600080600060608486031215610c8157600080fd5b610c8a84610afe565b9250610c9860208501610afe565b9150604084013590509250925092565b600060208284031215610cba57600080fd5b61095182610afe565b600080600080600080600060e0888a031215610cde57600080fd5b610ce788610afe565b9650610cf560208901610afe565b95506040880135945060608801359350610d1160808901610be7565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215610d4057600080fd5b610d4983610afe565b9150610d5760208401610afe565b90509250929050565b600181811c90821680610d7457607f821691505b602082108103610d9457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610de457600081815260208120601f850160051c81016020861015610dc15750805b601f850160051c820191505b81811015610de057828155600101610dcd565b5050505b505050565b815167ffffffffffffffff811115610e0357610e03610b44565b610e1781610e118454610d60565b84610d9a565b602080601f831160018114610e4c5760008415610e345750858301515b600019600386901b1c1916600185901b178555610de0565b600085815260208120601f198616915b82811015610e7b57888601518255948401946001909101908401610e5c565b5085821015610e995787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b600060018201610ed157610ed1610ea9565b5060010190565b6000808354610ee681610d60565b60018281168015610efe5760018114610f1357610f42565b60ff1984168752821515830287019450610f42565b8760005260208060002060005b85811015610f395781548a820152908401908201610f20565b50505082870194505b50929695505050505050565b8181038181111561036157610361610ea9565b8082018082111561036157610361610ea956feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c6343000814000a diff --git a/pallets/services/src/tests.rs b/pallets/services/src/tests.rs index b7657a81..d46ad41f 100644 --- a/pallets/services/src/tests.rs +++ b/pallets/services/src/tests.rs @@ -18,6 +18,7 @@ use crate::types::ConstraintsOf; use super::*; use frame_support::{assert_err, assert_ok}; use mock::*; +use sp_core::U256; use sp_core::{bounded_vec, ecdsa, ByteArray}; use sp_runtime::{KeyTypeId, Percent}; use tangle_primitives::services::*; @@ -29,9 +30,6 @@ const CHARLIE: u8 = 3; const DAVE: u8 = 4; const EVE: u8 = 5; -const USDC: AssetId = 1; -const WETH: AssetId = 2; - const KEYGEN_JOB_ID: u8 = 0; const SIGN_JOB_ID: u8 = 1; @@ -408,6 +406,7 @@ fn request_service() { Default::default(), vec![USDC, WETH], 100, + Asset::Custom(USDC), 0, )); @@ -508,6 +507,7 @@ fn request_service_with_no_assets() { Default::default(), vec![], // no assets 100, + Asset::Custom(USDC), 0, ), Error::::NoAssetsProvided @@ -515,6 +515,111 @@ fn request_service_with_no_assets() { }); } +#[test] +fn request_service_with_payment_asset() { + new_test_ext(vec![ALICE, BOB, CHARLIE, DAVE, EVE]).execute_with(|| { + System::set_block_number(1); + assert_ok!(Services::update_master_blueprint_service_manager(RuntimeOrigin::root(), MBSM)); + let alice = mock_pub_key(ALICE); + let blueprint = cggmp21_blueprint(); + + assert_ok!(Services::create_blueprint(RuntimeOrigin::signed(alice.clone()), blueprint)); + let bob = mock_pub_key(BOB); + assert_ok!(Services::register( + RuntimeOrigin::signed(bob.clone()), + 0, + OperatorPreferences { key: zero_key(), price_targets: Default::default() }, + Default::default(), + 0, + )); + + let charlie = mock_pub_key(CHARLIE); + assert_ok!(Services::request( + RuntimeOrigin::signed(charlie.clone()), + 0, + vec![], + vec![bob.clone()], + Default::default(), + vec![TNT, USDC, WETH], + 100, + Asset::Custom(USDC), + 5 * 10u128.pow(6), // 5 USDC + )); + + assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); + + // The Pallet account now has 5 USDC + assert_eq!(Assets::balance(USDC, Services::account_id()), 5 * 10u128.pow(6)); + + // Bob approves the request + assert_ok!(Services::approve( + RuntimeOrigin::signed(bob.clone()), + 0, + Percent::from_percent(10) + )); + + // The request is now fully approved + assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 0); + + // Now the service should be initiated + assert!(Instances::::contains_key(0)); + }); +} + +#[test] +fn request_service_with_payment_token() { + new_test_ext(vec![ALICE, BOB, CHARLIE, DAVE, EVE]).execute_with(|| { + System::set_block_number(1); + assert_ok!(Services::update_master_blueprint_service_manager(RuntimeOrigin::root(), MBSM)); + let alice = mock_pub_key(ALICE); + let blueprint = cggmp21_blueprint(); + + assert_ok!(Services::create_blueprint(RuntimeOrigin::signed(alice.clone()), blueprint)); + let bob = mock_pub_key(BOB); + assert_ok!(Services::register( + RuntimeOrigin::signed(bob.clone()), + 0, + OperatorPreferences { key: zero_key(), price_targets: Default::default() }, + Default::default(), + 0, + )); + + let charlie = mock_pub_key(CHARLIE); + assert_ok!(Services::request( + RuntimeOrigin::signed(charlie.clone()), + 0, + vec![], + vec![bob.clone()], + Default::default(), + vec![TNT, USDC, WETH], + 100, + Asset::Erc20(USDC_ERC20), + 5 * 10u128.pow(6), // 5 USDC + )); + + assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); + + // The Pallet address now has 5 USDC + assert_ok!( + Services::query_erc20_balance_of(USDC_ERC20, Services::address()).map(|(b, _)| b), + U256::from(5 * 10u128.pow(6)) + ); + + // Bob approves the request + assert_ok!(Services::approve( + RuntimeOrigin::signed(bob.clone()), + 0, + Percent::from_percent(10) + )); + + // The request is now fully approved + assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 0); + + // Now the service should be initiated + assert!(Instances::::contains_key(0)); + }); +} + #[test] fn job_calls() { new_test_ext(vec![ALICE, BOB, CHARLIE, DAVE, EVE]).execute_with(|| { @@ -557,6 +662,7 @@ fn job_calls() { Default::default(), vec![WETH], 100, + Asset::Custom(USDC), 0, )); @@ -649,6 +755,7 @@ fn job_result() { Default::default(), vec![WETH], 100, + Asset::Custom(USDC), 0, )); @@ -766,6 +873,7 @@ fn deploy() -> Deployment { Default::default(), vec![WETH], 100, + Asset::Custom(USDC), 0, )); @@ -1071,6 +1179,7 @@ fn hooks() { Default::default(), vec![USDC, WETH], 100, + Asset::Custom(USDC), 0, )); assert_evm_logs(&[evm_log!(HOOKS_TEST, b"OnRequest()")]); diff --git a/precompiles/services/Services.sol b/precompiles/services/Services.sol index 7d2a468a..cc571436 100644 --- a/precompiles/services/Services.sol +++ b/precompiles/services/Services.sol @@ -4,89 +4,114 @@ pragma solidity ^0.8.0; /// @title ServicesPrecompile Interface /// @dev This interface is meant to interact with the ServicesPrecompile in the Tangle network. interface ServicesPrecompile { - /// @notice Create a new service blueprint - /// @param blueprint_data The blueprint data encoded as bytes - function createBlueprint(bytes calldata blueprint_data) external; + /// @dev Invalid Permitted Callers provided + error InvalidPermittedCallers(); + /// @dev Invalid Service Providers provided + error InvalidOperatorsList(); + /// @dev Invalid Request Arguments provided + error InvalidRequestArguments(); + /// @dev Invalid TTL Value provided + error InvalidTTL(); + /// @dev Invalid Payment Amount provided + error InvalidAmount(); + /// @dev `msg.value` must be zero when using ERC20 token for payment + error ValueMustBeZeroForERC20(); + /// @dev `msg.value` must be zero when using custom asset for payment + error ValueMustBeZeroForCustomAsset(); + /// @dev Payment asset should be either custom or ERC20 + error PaymentAssetShouldBeCustomOrERC20(); - /// @notice Register an operator for a specific blueprint - /// @param blueprint_id The ID of the blueprint to register for - /// @param preferences The operator's preferences encoded as bytes - /// @param registration_args The registration arguments encoded as bytes - function registerOperator( - uint256 blueprint_id, - bytes calldata preferences, - bytes calldata registration_args - ) external payable; + /// @notice Create a new service blueprint + /// @param blueprint_data The blueprint data encoded as bytes + function createBlueprint(bytes calldata blueprint_data) external; - /// @notice Unregister an operator from a specific blueprint - /// @param blueprint_id The ID of the blueprint to unregister from - function unregisterOperator(uint256 blueprint_id) external; + /// @notice Register an operator for a specific blueprint + /// @param blueprint_id The ID of the blueprint to register for + /// @param preferences The operator's preferences encoded as bytes + /// @param registration_args The registration arguments encoded as bytes + function registerOperator( + uint256 blueprint_id, + bytes calldata preferences, + bytes calldata registration_args + ) external payable; - /// @notice Request a service from a specific blueprint - /// @param blueprint_id The ID of the blueprint - /// @param assets The list of assets to use for the service - /// @param permitted_callers_data The permitted callers for the service encoded as bytes - /// @param service_providers_data The service providers encoded as bytes - /// @param request_args_data The request arguments encoded as bytes - function requestService( - uint256 blueprint_id, - uint256[] calldata assets, - bytes calldata permitted_callers_data, - bytes calldata service_providers_data, - bytes calldata request_args_data - ) external; + /// @notice Unregister an operator from a specific blueprint + /// @param blueprint_id The ID of the blueprint to unregister from + function unregisterOperator(uint256 blueprint_id) external; - /// @notice Terminate a service - /// @param service_id The ID of the service to terminate - function terminateService(uint256 service_id) external; + /// @notice Request a service from a specific blueprint + /// @param blueprint_id The ID of the blueprint + /// @param assets The list of assets to use for the service + /// @param permitted_callers_data The permitted callers for the service encoded as bytes + /// @param service_providers_data The service providers encoded as bytes + /// @param request_args_data The request arguments encoded as bytes + /// @param ttl The time-to-live of the service. + /// @param payment_asset_id The ID of the asset to use for payment (0 for native asset) + /// @param payment_token_address The address of the token to use for payment (0x0 for using the value of payment_asset_id) + /// @param payment_amount The amount to pay for the service (use msg.value if payment_asset_id is 0) + function requestService( + uint256 blueprint_id, + uint256[] calldata assets, + bytes calldata permitted_callers_data, + bytes calldata service_providers_data, + bytes calldata request_args_data, + uint256 ttl, + uint256 payment_asset_id, + address payment_token_address, + uint256 payment_amount + ) external payable; - /// @notice Approve a service request - /// @param request_id The ID of the service request to approve - /// @param restaking_percent The amount of your restake to be exposed to the service in percentage [0, 100] - function approve(uint256 request_id, uint8 restaking_percent) external; + /// @notice Terminate a service + /// @param service_id The ID of the service to terminate + function terminateService(uint256 service_id) external; - /// @notice Reject a service request - /// @param request_id The ID of the service request to reject - function reject(uint256 request_id) external; + /// @notice Approve a service request + /// @param request_id The ID of the service request to approve + /// @param restaking_percent The amount of your restake to be exposed to the service in percentage [0, 100] + function approve(uint256 request_id, uint8 restaking_percent) external; - /// @notice Call a job in the service - /// @param service_id The ID of the service - /// @param job The job index (as uint8) - /// @param args_data The arguments of the job encoded as bytes - function callJob( - uint256 service_id, - uint8 job, - bytes calldata args_data - ) external; + /// @notice Reject a service request + /// @param request_id The ID of the service request to reject + function reject(uint256 request_id) external; - /// @notice Submit the result of a job call - /// @param service_id The ID of the service - /// @param call_id The ID of the call - /// @param result_data The result data encoded as bytes - function submitResult( - uint256 service_id, - uint256 call_id, - bytes calldata result_data - ) external; + /// @notice Call a job in the service + /// @param service_id The ID of the service + /// @param job The job index (as uint8) + /// @param args_data The arguments of the job encoded as bytes + function callJob( + uint256 service_id, + uint8 job, + bytes calldata args_data + ) external; - /// @notice Slash an operator (offender) for a service id with a given percent of their exposed stake for that service. - /// - /// The caller needs to be an authorized Slash Origin for this service. - /// Note that this does not apply the slash directly, but instead schedules a deferred call to apply the slash - /// by another entity. - /// @param offender The operator to be slashed encoded as bytes - /// @param service_id The ID of the service to slash for - /// @param percent The percent of the offender's exposed stake to slash - function slash( - bytes calldata offender, - uint256 service_id, - uint8 percent - ) external; + /// @notice Submit the result of a job call + /// @param service_id The ID of the service + /// @param call_id The ID of the call + /// @param result_data The result data encoded as bytes + function submitResult( + uint256 service_id, + uint256 call_id, + bytes calldata result_data + ) external; - /// @notice Dispute an Unapplied Slash for a service id. - /// - /// The caller needs to be an authorized Dispute Origin for this service. - /// @param era The era of the unapplied slash. - /// @param slash_index The index of the unapplied slash in the era. - function dispute(uint32 era, uint32 slash_index) external; + /// @notice Slash an operator (offender) for a service id with a given percent of their exposed stake for that service. + /// + /// The caller needs to be an authorized Slash Origin for this service. + /// Note that this does not apply the slash directly, but instead schedules a deferred call to apply the slash + /// by another entity. + /// @param offender The operator to be slashed encoded as bytes + /// @param service_id The ID of the service to slash for + /// @param percent The percent of the offender's exposed stake to slash + function slash( + bytes calldata offender, + uint256 service_id, + uint8 percent + ) external; + + /// @notice Dispute an Unapplied Slash for a service id. + /// + /// The caller needs to be an authorized Dispute Origin for this service. + /// @param era The era of the unapplied slash. + /// @param slash_index The index of the unapplied slash in the era. + function dispute(uint32 era, uint32 slash_index) external; } diff --git a/precompiles/services/src/lib.rs b/precompiles/services/src/lib.rs index 324e783a..50946f49 100644 --- a/precompiles/services/src/lib.rs +++ b/precompiles/services/src/lib.rs @@ -1,7 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::too_many_arguments)] -use fp_evm::PrecompileHandle; +use fp_evm::{PrecompileFailure, PrecompileHandle}; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; +use frame_system::pallet_prelude::BlockNumberFor; use pallet_evm::AddressMapping; use pallet_services::types::BalanceOf; use parity_scale_codec::Decode; @@ -10,7 +12,7 @@ use sp_core::U256; use sp_runtime::traits::Dispatchable; use sp_runtime::Percent; use sp_std::{marker::PhantomData, vec::Vec}; -use tangle_primitives::services::{Field, OperatorPreferences, ServiceBlueprint}; +use tangle_primitives::services::{Asset, Field, OperatorPreferences, ServiceBlueprint}; #[cfg(test)] mod mock; @@ -30,6 +32,26 @@ where ::RuntimeOrigin: From>, Runtime::RuntimeCall: From>, { + // Errors for the `Services` precompile. + + /// Found an invalid permitted callers list. + const INVALID_PERMITTED_CALLERS: [u8; 32] = keccak256!("InvalidPermittedCallers()"); + /// Found an invalid service providers list. + const INVALID_OPERATORS_LIST: [u8; 32] = keccak256!("InvalidOperatorsList()"); + /// Found an invalid request arguments. + const INVALID_REQUEST_ARGUMENTS: [u8; 32] = keccak256!("InvalidRequestArguments()"); + /// Invalid TTL. + const INVALID_TTL: [u8; 32] = keccak256!("InvalidTTL()"); + /// Found an invalid amount / value. + const INVALID_AMOUNT: [u8; 32] = keccak256!("InvalidAmount()"); + /// Value must be zero for ERC20 payment asset. + const VALUE_NOT_ZERO_FOR_ERC20: [u8; 32] = keccak256!("ValueMustBeZeroForERC20()"); + /// Value must be zero for custom payment asset. + const VALUE_NOT_ZERO_FOR_CUSTOM_ASSET: [u8; 32] = keccak256!("ValueMustBeZeroForCustomAsset()"); + /// Payment asset should be either custom or ERC20. + const PAYMENT_ASSET_SHOULD_BE_CUSTOM_OR_ERC20: [u8; 32] = + keccak256!("PaymentAssetShouldBeCustomOrERC20()"); + /// Create a new blueprint. #[precompile::public("createBlueprint(bytes)")] fn create_blueprint( @@ -53,6 +75,7 @@ where /// Register as an operator for a specific blueprint. #[precompile::public("registerOperator(uint256,bytes,bytes)")] + #[precompile::payable] fn register_operator( handle: &mut impl PrecompileHandle, blueprint_id: U256, @@ -112,7 +135,10 @@ where } /// Request a new service. - #[precompile::public("requestService(uint256,uint256[],bytes,bytes,bytes)")] + #[precompile::public( + "requestService(uint256,uint256[],bytes,bytes,bytes,uint256,uint256,address,uint256)" + )] + #[precompile::payable] fn request_service( handle: &mut impl PrecompileHandle, blueprint_id: U256, @@ -120,6 +146,10 @@ where permitted_callers_data: UnboundedBytes, service_providers_data: UnboundedBytes, request_args_data: UnboundedBytes, + ttl: U256, + payment_asset_id: U256, + payment_token_address: Address, + amount: U256, ) -> EvmResult { handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); @@ -131,15 +161,16 @@ where let permitted_callers: Vec = Decode::decode(&mut &permitted_callers_data[..]) - .map_err(|_| revert("Invalid permitted callers data"))?; + .map_err(|_| revert_custom_error(Self::INVALID_PERMITTED_CALLERS))?; let operators: Vec = Decode::decode(&mut &service_providers_data[..]) - .map_err(|_| revert("Invalid service providers data"))?; + .map_err(|_| revert_custom_error(Self::INVALID_OPERATORS_LIST))?; let request_args: Vec> = Decode::decode(&mut &request_args_data[..]) - .map_err(|_| revert("Invalid request arguments data"))?; + .map_err(|_| revert_custom_error(Self::INVALID_REQUEST_ARGUMENTS))?; + let assets: Vec = assets.into_iter().map(|asset| asset.as_u32().into()).collect(); @@ -150,15 +181,55 @@ where value_bytes }; let value = BalanceOf::::decode(&mut &value_bytes[..]) - .map_err(|_| revert("Value is not a valid balance"))?; + .map_err(|_| revert_custom_error(Self::INVALID_AMOUNT))?; + + let ttl_bytes = { + let mut ttl_bytes = [0u8; core::mem::size_of::()]; + ttl.to_little_endian(&mut ttl_bytes); + ttl_bytes + }; + + let ttl = BlockNumberFor::::decode(&mut &ttl_bytes[..]) + .map_err(|_| revert_custom_error(Self::INVALID_TTL))?; + + let amount = { + let mut amount_bytes = [0u8; core::mem::size_of::()]; + amount.to_little_endian(&mut amount_bytes); + BalanceOf::::decode(&mut &amount_bytes[..]) + .map_err(|_| revert_custom_error(Self::INVALID_AMOUNT))? + }; + + const ZERO_ADDRESS: [u8; 20] = [0; 20]; + + let (payment_asset, amount) = match (payment_asset_id.as_u32(), payment_token_address.0 .0) + { + (0, ZERO_ADDRESS) => (Asset::Custom(0u32.into()), value), + (0, erc20_token) => { + if value != Default::default() { + return Err(revert_custom_error(Self::VALUE_NOT_ZERO_FOR_ERC20)); + } + (Asset::Erc20(erc20_token.into()), amount) + }, + (other_asset_id, ZERO_ADDRESS) => { + if value != Default::default() { + return Err(revert_custom_error(Self::VALUE_NOT_ZERO_FOR_CUSTOM_ASSET)); + } + (Asset::Custom(other_asset_id.into()), amount) + }, + (_other_asset_id, _erc20_token) => { + return Err(revert_custom_error(Self::PAYMENT_ASSET_SHOULD_BE_CUSTOM_OR_ERC20)) + }, + }; + let call = pallet_services::Call::::request { blueprint_id, permitted_callers, operators, - ttl: 10000_u32.into(), + ttl, assets, request_args, - value, + payment_asset, + value: amount, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -324,3 +395,11 @@ where Ok(()) } } + +/// Revert with Custom Error Selector +fn revert_custom_error(err: [u8; 32]) -> PrecompileFailure { + let selector = &err[0..4]; + let mut output = sp_std::vec![0u8; 32]; + output[0..4].copy_from_slice(selector); + PrecompileFailure::Revert { exit_status: fp_evm::ExitRevert::Reverted, output } +} diff --git a/precompiles/services/src/mock.rs b/precompiles/services/src/mock.rs index aab53659..4a0bf273 100644 --- a/precompiles/services/src/mock.rs +++ b/precompiles/services/src/mock.rs @@ -15,26 +15,30 @@ // along with Tangle. If not, see . #![allow(clippy::all)] use super::*; +use core::ops::Mul; +use ethabi::Uint; use frame_election_provider_support::{ bounds::{ElectionBounds, ElectionBoundsBuilder}, onchain, SequentialPhragmen, }; -use frame_support::derive_impl; use frame_support::pallet_prelude::Hooks; use frame_support::pallet_prelude::Weight; use frame_support::{ construct_runtime, parameter_types, traits::{ConstU128, OneSessionHandler}, }; +use frame_support::{derive_impl, traits::AsEnsureOriginWithArg}; use frame_system::EnsureRoot; use mock_evm::MockedEvmRunner; use pallet_evm::GasWeightMapping; +use pallet_services::traits::EvmRunner; use pallet_services::{EvmAddressMapping, EvmGasWeightMapping}; use pallet_session::historical as pallet_session_historical; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use serde::Deserialize; use serde::Serialize; +use serde_json::json; use sp_core::{self, sr25519, sr25519::Public as sr25519Public, ConstU32, RuntimeDebug, H160}; use sp_keystore::{testing::MemoryKeystore, KeystoreExt, KeystorePtr}; use sp_runtime::{ @@ -245,6 +249,27 @@ impl EvmAddressMapping for PalletEVMAddressMapping { } } +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = u128; + type AssetId = AssetId; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type WeightInfo = (); + type CallbackHandle = (); + type Extra = (); + type RemoveItemsLimit = ConstU32<5>; +} + const PRECOMPILE_ADDRESS_BYTES: [u8; 32] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ]; @@ -337,6 +362,21 @@ impl From for AccountId32 { } } +impl From for TestAccount { + fn from(x: AccountId32) -> Self { + let bytes: [u8; 32] = x.into(); + match bytes { + a if a == [1u8; 32] => TestAccount::Alex, + a if a == [2u8; 32] => TestAccount::Bob, + a if a == [3u8; 32] => TestAccount::Charlie, + a if a == [4u8; 32] => TestAccount::Dave, + a if a == [5u8; 32] => TestAccount::Eve, + a if a == PRECOMPILE_ADDRESS_BYTES => TestAccount::PrecompileAddress, + _ => TestAccount::Empty, + } + } +} + impl From for sp_core::sr25519::Public { fn from(x: TestAccount) -> Self { match x { @@ -494,6 +534,7 @@ impl pallet_services::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = frame_system::EnsureRoot; type Currency = Balances; + type Fungibles = Assets; type AssetId = AssetId; type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = MockedEvmRunner; @@ -535,6 +576,7 @@ construct_runtime!( System: frame_system, Timestamp: pallet_timestamp, Balances: pallet_balances, + Assets: pallet_assets, Services: pallet_services, EVM: pallet_evm, Ethereum: pallet_ethereum, @@ -554,6 +596,12 @@ pub fn mock_authorities(vec: Vec) -> Vec { pub const MBSM: H160 = H160([0x12; 20]); pub const CGGMP21_BLUEPRINT: H160 = H160([0x21; 20]); +pub const USDC_ERC20: H160 = H160([0x23; 20]); + +pub const TNT: AssetId = 0; +pub const USDC: AssetId = 1; +pub const WETH: AssetId = 2; +pub const WBTC: AssetId = 3; /// Build test externalities, prepopulated with data for testing democracy precompiles #[derive(Default)] @@ -572,7 +620,7 @@ impl ExtBuilder { pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); // We use default for brevity, but you can configure as desired if needed. - let balances: Vec<_> = authorities.iter().map(|i| (i.clone(), 20_000_u128)).collect(); + let balances: Vec<_> = authorities.iter().map(|i| (i.clone(), 20_000_000_u128)).collect(); pallet_balances::GenesisConfig:: { balances } .assimilate_storage(&mut t) .unwrap(); @@ -633,11 +681,58 @@ pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::TestE MBSM, ); + create_contract( + include_str!("../../../pallets/services/src/test-artifacts/MockERC20.hex"), + USDC_ERC20, + ); + + // Add some initial balance to the authorities in the EVM pallet + for a in authorities.iter().cloned() { + evm_accounts.insert( + TestAccount::from(a).into(), + fp_evm::GenesisAccount { + code: vec![], + storage: Default::default(), + nonce: Default::default(), + balance: Uint::from(1_000).mul(Uint::from(10).pow(Uint::from(18))), + }, + ); + } + let evm_config = pallet_evm::GenesisConfig:: { accounts: evm_accounts, ..Default::default() }; evm_config.assimilate_storage(&mut t).unwrap(); + let assets_config = pallet_assets::GenesisConfig:: { + assets: vec![ + (USDC, authorities[0].clone(), true, 100_000), // 1 cent. + (WETH, authorities[1].clone(), true, 100), // 100 wei. + (WBTC, authorities[2].clone(), true, 100), // 100 satoshi. + ], + metadata: vec![ + (USDC, Vec::from(b"USD Coin"), Vec::from(b"USDC"), 6), + (WETH, Vec::from(b"Wrapped Ether"), Vec::from(b"WETH"), 18), + (WBTC, Vec::from(b"Wrapped Bitcoin"), Vec::from(b"WBTC"), 18), + ], + accounts: vec![ + (USDC, authorities[0].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[0].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[0].clone(), 50 * 10u128.pow(18)), + // + (USDC, authorities[1].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[1].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[1].clone(), 50 * 10u128.pow(18)), + // + (USDC, authorities[2].clone(), 1_000_000 * 10u128.pow(6)), + (WETH, authorities[2].clone(), 100 * 10u128.pow(18)), + (WBTC, authorities[2].clone(), 50 * 10u128.pow(18)), + ], + next_asset_id: Some(4), + }; + + assets_config.assimilate_storage(&mut t).unwrap(); + let mut ext = sp_io::TestExternalities::new(t); ext.register_extension(KeystoreExt(Arc::new(MemoryKeystore::new()) as KeystorePtr)); ext.execute_with(|| System::set_block_number(1)); @@ -645,6 +740,82 @@ pub fn new_test_ext_raw_authorities(authorities: Vec) -> sp_io::TestE System::set_block_number(1); Session::on_initialize(1); >::on_initialize(1); + + let call = ::EvmRunner::call( + Services::address(), + USDC_ERC20, + serde_json::from_value::(json!({ + "name": "initialize", + "inputs": [ + { + "name": "name_", + "type": "string", + "internalType": "string" + }, + { + "name": "symbol_", + "type": "string", + "internalType": "string" + }, + { + "name": "decimals_", + "type": "uint8", + "internalType": "uint8" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + })) + .unwrap() + .encode_input(&[ + ethabi::Token::String("USD Coin".to_string()), + ethabi::Token::String("USDC".to_string()), + ethabi::Token::Uint(6.into()), + ]) + .unwrap(), + Default::default(), + 300_000, + true, + false, + ); + + assert_eq!(call.map(|info| info.exit_reason.is_succeed()).ok(), Some(true)); + // Mint + for a in authorities { + let call = ::EvmRunner::call( + Services::address(), + USDC_ERC20, + serde_json::from_value::(json!({ + "name": "mint", + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + })) + .unwrap() + .encode_input(&[ + ethabi::Token::Address(TestAccount::from(a).into()), + ethabi::Token::Uint(Uint::from(100_000).mul(Uint::from(10).pow(Uint::from(6)))), + ]) + .unwrap(), + Default::default(), + 300_000, + true, + false, + ); + + assert_eq!(call.map(|info| info.exit_reason.is_succeed()).ok(), Some(true)); + } }); ext diff --git a/precompiles/services/src/tests.rs b/precompiles/services/src/tests.rs index e725bd09..447eae2f 100644 --- a/precompiles/services/src/tests.rs +++ b/precompiles/services/src/tests.rs @@ -1,3 +1,5 @@ +use core::ops::Mul; + use crate::mock::*; use crate::mock_evm::PCall; use crate::mock_evm::PrecompilesValue; @@ -26,8 +28,6 @@ fn zero_key() -> ecdsa::Public { ecdsa::Public::from([0; 33]) } -const WETH: AssetId = 1; - #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MachineKind { @@ -197,10 +197,181 @@ fn test_request_service() { service_providers_data: UnboundedBytes::from(service_providers_data.encode()), request_args_data: UnboundedBytes::from(request_args_data), assets: [WETH].into_iter().map(Into::into).collect(), + ttl: U256::from(1000), + payment_asset_id: U256::from(0), + payment_token_address: Default::default(), + amount: U256::from(0), + }, + ) + .execute_returns(()); + + // Approve the service request by the operator(s) + PrecompilesValue::get() + .prepare_test( + TestAccount::Bob, + H160::from_low_u64_be(1), + PCall::approve { request_id: U256::from(0), restaking_percent: 10 }, + ) + .execute_returns(()); + + // Ensure the service instance is created + assert!(Instances::::contains_key(0)); + }); +} + +#[test] +fn test_request_service_with_erc20() { + ExtBuilder.build().execute_with(|| { + assert_ok!(Services::update_master_blueprint_service_manager(RuntimeOrigin::root(), MBSM)); + // First create the blueprint + let blueprint_data = cggmp21_blueprint(); + + PrecompilesValue::get() + .prepare_test( + TestAccount::Alex, + H160::from_low_u64_be(1), + PCall::create_blueprint { + blueprint_data: UnboundedBytes::from(blueprint_data.encode()), }, ) .execute_returns(()); + // Now register operator + let preferences_data = OperatorPreferences { + key: zero_key(), + price_targets: price_targets(MachineKind::Large), + } + .encode(); + + PrecompilesValue::get() + .prepare_test( + TestAccount::Bob, + H160::from_low_u64_be(1), + PCall::register_operator { + blueprint_id: U256::from(0), + preferences: UnboundedBytes::from(preferences_data), + registration_args: UnboundedBytes::from(vec![0u8]), + }, + ) + .execute_returns(()); + + assert_ok!( + Services::query_erc20_balance_of(USDC_ERC20, Services::address()) + .map(|(balance, _)| balance), + U256::zero(), + ); + // Finally, request the service + let permitted_callers_data: Vec = vec![TestAccount::Alex.into()]; + let service_providers_data: Vec = vec![TestAccount::Bob.into()]; + let request_args_data = vec![0u8]; + + let payment_amount = U256::from(5).mul(U256::from(10).pow(6.into())); // 5 USDC + + PrecompilesValue::get() + .prepare_test( + TestAccount::Alex, + H160::from_low_u64_be(1), + PCall::request_service { + blueprint_id: U256::from(0), // Use the first blueprint + permitted_callers_data: UnboundedBytes::from(permitted_callers_data.encode()), + service_providers_data: UnboundedBytes::from(service_providers_data.encode()), + request_args_data: UnboundedBytes::from(request_args_data), + assets: [TNT, WETH].into_iter().map(Into::into).collect(), + ttl: U256::from(1000), + payment_asset_id: U256::from(0), + payment_token_address: USDC_ERC20.into(), + amount: payment_amount, + }, + ) + .execute_returns(()); + + // Services pallet address now should have 5 USDC + assert_ok!( + Services::query_erc20_balance_of(USDC_ERC20, Services::address()) + .map(|(balance, _)| balance), + payment_amount + ); + + // Approve the service request by the operator(s) + PrecompilesValue::get() + .prepare_test( + TestAccount::Bob, + H160::from_low_u64_be(1), + PCall::approve { request_id: U256::from(0), restaking_percent: 10 }, + ) + .execute_returns(()); + + // Ensure the service instance is created + assert!(Instances::::contains_key(0)); + }); +} + +#[test] +fn test_request_service_with_asset() { + ExtBuilder.build().execute_with(|| { + assert_ok!(Services::update_master_blueprint_service_manager(RuntimeOrigin::root(), MBSM)); + // First create the blueprint + let blueprint_data = cggmp21_blueprint(); + + PrecompilesValue::get() + .prepare_test( + TestAccount::Alex, + H160::from_low_u64_be(1), + PCall::create_blueprint { + blueprint_data: UnboundedBytes::from(blueprint_data.encode()), + }, + ) + .execute_returns(()); + + // Now register operator + let preferences_data = OperatorPreferences { + key: zero_key(), + price_targets: price_targets(MachineKind::Large), + } + .encode(); + + PrecompilesValue::get() + .prepare_test( + TestAccount::Bob, + H160::from_low_u64_be(1), + PCall::register_operator { + blueprint_id: U256::from(0), + preferences: UnboundedBytes::from(preferences_data), + registration_args: UnboundedBytes::from(vec![0u8]), + }, + ) + .execute_returns(()); + + assert_eq!(Assets::balance(USDC, Services::account_id()), 0); + + // Finally, request the service + let permitted_callers_data: Vec = vec![TestAccount::Alex.into()]; + let service_providers_data: Vec = vec![TestAccount::Bob.into()]; + let request_args_data = vec![0u8]; + + let payment_amount = U256::from(5).mul(U256::from(10).pow(6.into())); // 5 USDC + + PrecompilesValue::get() + .prepare_test( + TestAccount::Alex, + H160::from_low_u64_be(1), + PCall::request_service { + blueprint_id: U256::from(0), // Use the first blueprint + permitted_callers_data: UnboundedBytes::from(permitted_callers_data.encode()), + service_providers_data: UnboundedBytes::from(service_providers_data.encode()), + request_args_data: UnboundedBytes::from(request_args_data), + assets: [TNT, WETH].into_iter().map(Into::into).collect(), + ttl: U256::from(1000), + payment_asset_id: U256::from(USDC), + payment_token_address: Default::default(), + amount: payment_amount, + }, + ) + .execute_returns(()); + + // Services pallet address now should have 5 USDC + assert_eq!(Assets::balance(USDC, Services::account_id()), payment_amount.as_u128()); + // Approve the service request by the operator(s) PrecompilesValue::get() .prepare_test( @@ -314,6 +485,10 @@ fn test_terminate_service() { service_providers_data: UnboundedBytes::from(service_providers_data.encode()), request_args_data: UnboundedBytes::from(request_args_data), assets: [WETH].into_iter().map(Into::into).collect(), + ttl: U256::from(1000), + payment_asset_id: U256::from(0), + payment_token_address: Default::default(), + amount: U256::from(0), }, ) .execute_returns(()); diff --git a/primitives/src/services/mod.rs b/primitives/src/services/mod.rs index 117b7aa8..d572a46a 100644 --- a/primitives/src/services/mod.rs +++ b/primitives/src/services/mod.rs @@ -602,6 +602,7 @@ pub struct Service { pub ttl: BlockNumber, } +/// Operator's Approval State. #[derive( Default, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Copy, Clone, MaxEncodedLen, )] @@ -622,6 +623,62 @@ pub enum ApprovalState { Rejected, } +/// Different types of assets that can be used. +#[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Copy, Clone, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Asset { + /// Use the specified AssetId. + #[codec(index = 0)] + Custom(AssetId), + + /// Use an ERC20-like token with the specified contract address. + #[codec(index = 1)] + Erc20(sp_core::H160), +} + +impl Default for Asset { + fn default() -> Self { + Asset::Custom(sp_runtime::traits::Zero::zero()) + } +} + +impl Asset { + pub fn to_ethabi_param_type() -> ethabi::ParamType { + ethabi::ParamType::Tuple(vec![ + // Kind of the Asset + ethabi::ParamType::Uint(8), + // Data of the Asset (Contract Address or AssetId) + ethabi::ParamType::FixedBytes(32), + ]) + } + + pub fn to_ethabi_param() -> ethabi::Param { + ethabi::Param { + name: String::from("asset"), + kind: Self::to_ethabi_param_type(), + internal_type: Some(String::from("struct ServiceOperators.Asset")), + } + } + + pub fn to_ethabi(&self) -> ethabi::Token { + match self { + Asset::Custom(asset_id) => { + let asset_id = asset_id.using_encoded(ethabi::Uint::from_little_endian); + let mut asset_id_bytes = [0u8; core::mem::size_of::()]; + asset_id.to_big_endian(&mut asset_id_bytes); + ethabi::Token::Tuple(vec![ + ethabi::Token::Uint(0.into()), + ethabi::Token::FixedBytes(asset_id_bytes.into()), + ]) + }, + Asset::Erc20(addr) => ethabi::Token::Tuple(vec![ + ethabi::Token::Uint(1.into()), + ethabi::Token::FixedBytes(addr.to_fixed_bytes().into()), + ]), + } + } +} + /// Represents the pricing structure for various hardware resources. /// All prices are specified in USD/hr, calculated based on the average block time. #[derive( @@ -663,7 +720,7 @@ impl PriceTargets { ethabi::Param { name: String::from("priceTargets"), kind: Self::to_ethabi_param_type(), - internal_type: Some(String::from("struct IBlueprintServiceManager.PriceTargets")), + internal_type: Some(String::from("struct ServiceOperators.PriceTargets")), } } diff --git a/runtime/mainnet/src/tangle_services.rs b/runtime/mainnet/src/tangle_services.rs index de7b6b27..1cf4c43a 100644 --- a/runtime/mainnet/src/tangle_services.rs +++ b/runtime/mainnet/src/tangle_services.rs @@ -151,6 +151,7 @@ impl pallet_services::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = EnsureRootOrHalfCouncil; type Currency = Balances; + type Fungibles = Assets; type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = PalletEvmRunner; type EvmGasWeightMapping = PalletEVMGasWeightMapping; diff --git a/runtime/testnet/src/tangle_services.rs b/runtime/testnet/src/tangle_services.rs index c7a44766..0cd11350 100644 --- a/runtime/testnet/src/tangle_services.rs +++ b/runtime/testnet/src/tangle_services.rs @@ -148,6 +148,7 @@ impl pallet_services::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = EnsureRootOrHalfCouncil; type Currency = Balances; + type Fungibles = Assets; type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = PalletEvmRunner; type EvmGasWeightMapping = PalletEVMGasWeightMapping;