From 9b596d09cda48834bd93b2e614f1d2e11d1dddb8 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 14 May 2024 20:08:42 +0800 Subject: [PATCH 01/27] add struct currency --- Cargo.lock | 19 ++++ Cargo.toml | 4 + primitives/Cargo.toml | 44 ++++++++ primitives/src/currency.rs | 222 +++++++++++++++++++++++++++++++++++++ primitives/src/lib.rs | 3 + 5 files changed, 292 insertions(+) create mode 100644 primitives/Cargo.toml create mode 100644 primitives/src/currency.rs create mode 100644 primitives/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index d2321107..a16ac35e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4675,6 +4675,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ggx-primitives" +version = "0.0.1" +dependencies = [ + "bstringify", + "frame-support", + "log 0.4.20", + "num_enum 0.5.11", + "parity-scale-codec", + "scale-info", + "serde", + "serde_json", + "sp-api", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", +] + [[package]] name = "ggxchain-node" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 1918c84b..c39cb136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "node", "precompiles/session", "precompiles/zk-groth16-verify", + "primitives", "runtime/sydney", "runtime/brooklyn", "runtime/runtime-common", @@ -24,6 +25,7 @@ repository = "https://github.com/ggxchain/ggxnode/" # General purpose dependencies assert_cmd = "2.0.2" async-trait = "0.1" +bstringify = { version = "0.1.2" } cfg-if = "1.0" clap = { version = "4.1", features = ["derive"] } derive_more = { version = "0.99" } @@ -196,8 +198,10 @@ ggxchain-runtime-brooklyn = { path = "runtime/brooklyn", default-features = fals ggxchain-runtime-sydney = { path = "runtime/sydney", default-features = false } pallet-evm-precompile-session = { path = "precompiles/session", default-features = false } pallet-evm-precompile-zk-groth16-verify = { path = "precompiles/zk-groth16-verify", default-features = false } +ggx-primitives = { path = "primitives", default-features = false } runtime-common = { path = "runtime/runtime-common", default-features = false } + # Astar astar-primitives = { git = "https://github.com/AstarNetwork/Astar.git", rev = "df73ca435bbfa30548bb2446b5dbb58492c928bb", default-features = false } pallet-chain-extension-xvm = { version = "0.1.0", git = "https://github.com/AstarNetwork/Astar.git", rev = "df73ca435bbfa30548bb2446b5dbb58492c928bb", default-features = false } diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml new file mode 100644 index 00000000..7d282be7 --- /dev/null +++ b/primitives/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ggx-primitives" +version = "0.0.1" +authors.workspace = true +edition.workspace = true + +[dependencies] +bstringify = { workspace = true } +log = { workspace = true } +serde = { workspace = true, features = ["alloc", "derive"] } +scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true } +num_enum = { workspace = true } + +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } +sp-api = { workspace = true } + +frame-support = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true, features = ["std"] } + + +[features] +default = ["std"] +std = [ + "serde/std", + "scale-codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-core/std", + "sp-std/std", + "sp-io/std", + "sp-api/std", + + "frame-support/std", + +] +evm-tests = [] +try-runtime = [] +tracing = [] diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs new file mode 100644 index 00000000..f70635d4 --- /dev/null +++ b/primitives/src/currency.rs @@ -0,0 +1,222 @@ +use bstringify::bstringify; +use core::ops::Range; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use scale_codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; +use sp_std::prelude::*; + +use serde::{Deserialize, Serialize}; + +pub type EvmAddress = sp_core::H160; +pub type ForeignAssetId = u16; +pub type Erc20Id = u32; +pub type TokenId = u8; + +pub const H160_POSITION_CURRENCY_ID_TYPE: usize = 9; +pub const H160_POSITION_TOKEN: usize = 19; +pub const H160_POSITION_FOREIGN_ASSET: Range = 18..20; +/// Generate the EvmAddress from CurrencyId so that evm contracts can call the erc20 contract. +/// NOTE: Can not be used directly, need to check the erc20 is mapped. +impl TryFrom for EvmAddress { + type Error = (); + + fn try_from(val: CurrencyId) -> Result { + let mut address = [0u8; 20]; + match val { + CurrencyId::Token(token) => { + address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::Token.into(); + address[H160_POSITION_TOKEN] = token.into(); + } + + CurrencyId::Erc20(erc20) => { + address[..].copy_from_slice(erc20.as_bytes()); + } + CurrencyId::Erc1155(erc1155) => { + address[..].copy_from_slice(erc1155.as_bytes()); + } + + CurrencyId::ForeignAsset(foreign_asset_id) => { + address[H160_POSITION_CURRENCY_ID_TYPE] = CurrencyIdType::ForeignAsset.into(); + address[H160_POSITION_FOREIGN_ASSET] + .copy_from_slice(&foreign_asset_id.to_be_bytes()); + } + }; + + Ok(EvmAddress::from_slice(&address)) + } +} + +macro_rules! create_currency_id { + ($(#[$meta:meta])* +$vis:vis enum TokenSymbol { + $($(#[$vmeta:meta])* $symbol:ident($name:expr, $deci:literal) = $val:literal,)* + }) => { + $(#[$meta])* + $vis enum TokenSymbol { + $($(#[$vmeta])* $symbol = $val,)* + } + + impl TryFrom for TokenSymbol { + type Error = (); + + fn try_from(v: u8) -> Result { + match v { + $($val => Ok(TokenSymbol::$symbol),)* + _ => Err(()), + } + } + } + + impl Into for TokenSymbol { + fn into(self) -> u8 { + match self { + $(TokenSymbol::$symbol => ($val),)* + } + } + } + + impl TryFrom> for CurrencyId { + type Error = (); + fn try_from(v: Vec) -> Result { + match v.as_slice() { + $(bstringify!($symbol) => Ok(CurrencyId::Token(TokenSymbol::$symbol)),)* + _ => Err(()), + } + } + } + + impl TokenInfo for CurrencyId { + fn currency_id(&self) -> Option { + match self { + $(CurrencyId::Token(TokenSymbol::$symbol) => Some($val),)* + _ => None, + } + } + fn name(&self) -> Option<&str> { + match self { + $(CurrencyId::Token(TokenSymbol::$symbol) => Some($name),)* + _ => None, + } + } + fn symbol(&self) -> Option<&str> { + match self { + $(CurrencyId::Token(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + _ => None, + } + } + fn decimals(&self) -> Option { + match self { + $(CurrencyId::Token(TokenSymbol::$symbol) => Some($deci),)* + _ => None, + } + } + } + + $(pub const $symbol: CurrencyId = CurrencyId::Token(TokenSymbol::$symbol);)* + + impl TokenSymbol { + pub fn get_info() -> Vec<(&'static str, u32)> { + vec![ + $((stringify!($symbol), $deci),)* + ] + } + } +} +} + +create_currency_id! { + // Represent a Token symbol with 8 bit + #[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo, MaxEncodedLen, Serialize, Deserialize)] + #[repr(u8)] + pub enum TokenSymbol { + // 0 - 19: Acala & Polkadot native tokens + GGX("GoldenGate", 12) = 0, + DOT("Polkadot", 10) = 1, + KSM("Kusama", 12) = 2, + } +} + +impl Default for TokenSymbol { + fn default() -> Self { + Self::GGX + } +} + +pub trait TokenInfo { + fn currency_id(&self) -> Option; + fn name(&self) -> Option<&str>; + fn symbol(&self) -> Option<&str>; + fn decimals(&self) -> Option; +} + +#[derive( + Encode, + Decode, + Eq, + PartialEq, + Copy, + Clone, + RuntimeDebug, + PartialOrd, + Ord, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +#[serde(rename_all = "camelCase")] +pub enum CurrencyId { + Token(TokenSymbol), + Erc20(EvmAddress), + Erc1155(EvmAddress), + ForeignAsset(ForeignAssetId), +} + +impl CurrencyId { + pub fn is_token_currency_id(&self) -> bool { + matches!(self, CurrencyId::Token(_)) + } + + pub fn is_erc20_currency_id(&self) -> bool { + matches!(self, CurrencyId::Erc20(_)) + } + + pub fn is_erc1155_currency_id(&self) -> bool { + matches!(self, CurrencyId::Erc1155(_)) + } + + pub fn is_foreign_asset_currency_id(&self) -> bool { + matches!(self, CurrencyId::ForeignAsset(_)) + } + + pub fn erc20_address(&self) -> Option { + match self { + CurrencyId::Erc20(address) => Some(*address), + CurrencyId::Erc1155(address) => Some(*address), + CurrencyId::Token(_) => EvmAddress::try_from(*self).ok(), + _ => None, + } + } +} + +/// H160 CurrencyId Type enum +#[derive( + Encode, + Decode, + Eq, + PartialEq, + Copy, + Clone, + RuntimeDebug, + PartialOrd, + Ord, + TryFromPrimitive, + IntoPrimitive, + TypeInfo, +)] +#[repr(u8)] +pub enum CurrencyIdType { + Token = 1, // 0 is prefix of precompile and predeploy + ForeignAsset, +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs new file mode 100644 index 00000000..dbfc951b --- /dev/null +++ b/primitives/src/lib.rs @@ -0,0 +1,3 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod currency; From e69db9e10b5aa9ef0d008579954f0c64f35baee4 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 14 May 2024 20:25:46 +0800 Subject: [PATCH 02/27] init currency pallet --- Cargo.lock | 20 + Cargo.toml | 2 + pallet/currencies/Cargo.toml | 47 + pallet/currencies/README.md | 9 + pallet/currencies/src/default_weight.rs | 29 + pallet/currencies/src/lib.rs | 1295 +++++++++++++++++++++++ pallet/currencies/src/mock.rs | 174 +++ pallet/currencies/src/tests.rs | 473 +++++++++ pallet/currencies/src/weights.rs | 67 ++ runtime/brooklyn/Cargo.toml | 2 + 10 files changed, 2118 insertions(+) create mode 100644 pallet/currencies/Cargo.toml create mode 100644 pallet/currencies/README.md create mode 100644 pallet/currencies/src/default_weight.rs create mode 100644 pallet/currencies/src/lib.rs create mode 100644 pallet/currencies/src/mock.rs create mode 100644 pallet/currencies/src/tests.rs create mode 100644 pallet/currencies/src/weights.rs diff --git a/Cargo.lock b/Cargo.lock index a16ac35e..ac6ca4ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4846,6 +4846,7 @@ dependencies = [ "pallet-contracts", "pallet-contracts-primitives", "pallet-conviction-voting", + "pallet-currencies", "pallet-dex", "pallet-dynamic-fee", "pallet-election-provider-multi-phase", @@ -8627,6 +8628,25 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", ] +[[package]] +name = "pallet-currencies" +version = "0.4.1-dev" +dependencies = [ + "frame-support", + "frame-system", + "orml-tokens", + "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", + "orml-utilities 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", +] + [[package]] name = "pallet-dex" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index c39cb136..6eb8e7dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -260,6 +260,7 @@ ark-std = { version = "0.4.0", default-features = false } # Orml dependencies orml-asset-registry = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "28a2e6f0df9540d91db4018c7ecebb8bfc217a2a", default-features = false } +orml-utilities = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "28a2e6f0df9540d91db4018c7ecebb8bfc217a2a", default-features = false } orml-tokens = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "28a2e6f0df9540d91db4018c7ecebb8bfc217a2a", default-features = false } orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", rev = "28a2e6f0df9540d91db4018c7ecebb8bfc217a2a", default-features = false } @@ -300,6 +301,7 @@ reward-rpc-runtime-api = { git = "https://github.com/ggxchain/interbtc.git", bra vault-registry-rpc-runtime-api = { git = "https://github.com/ggxchain/interbtc.git", branch = "polkadot-v0.9.43", default-features = false } # Dex +pallet-currencies = { path = "pallet/currencies", default-features = false } pallet-dex = { path = "pallet/dex", default-features = false } # Supress warnings from the peerset in logs during syncing diff --git a/pallet/currencies/Cargo.toml b/pallet/currencies/Cargo.toml new file mode 100644 index 00000000..25d3895f --- /dev/null +++ b/pallet/currencies/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "pallet-currencies" +description = "Provide `MultiCurrency` implementation using `pallet-balances` and `orml-tokens` module." +repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/currencies" +license = "Apache-2.0" +version = "0.4.1-dev" +authors = ["Laminar Developers ", "Sora Yu "] +edition = "2021" + +[dependencies] +scale-codec = { workspace = true, features = ["derive"] } +scale-info = { workspace = true, features = ["derive"] } +serde = { workspace = true, optional = true } + +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } + +orml-traits = { workspace = true } +orml-utilities = { workspace = true } + +[dev-dependencies] +pallet-balances = { workspace = true } +sp-core = { workspace = true } + +orml-tokens = { workspace = true } + +[features] +default = ["std"] +std = [ + "serde", + "frame-support/std", + "frame-system/std", + "orml-traits/std", + "orml-utilities/std", + "scale-codec/std", + "scale-info/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/pallet/currencies/README.md b/pallet/currencies/README.md new file mode 100644 index 00000000..c4a330b5 --- /dev/null +++ b/pallet/currencies/README.md @@ -0,0 +1,9 @@ +# Currencies Module + +## Overview + +The currencies module provides a mixed currencies system, by configuring a native currency which implements `BasicCurrencyExtended`, and a multi-currency which implements `MultiCurrency`. + +It also provides an adapter, to adapt `frame_support::traits::Currency` implementations into `BasicCurrencyExtended`. + +The currencies module provides functionality of both `MultiCurrencyExtended` and `BasicCurrencyExtended`, via unified interfaces, and all calls would be delegated to the underlying multi-currency and base currency system. A native currency ID could be set by `Config::GetNativeCurrencyId`, to identify the native currency. diff --git a/pallet/currencies/src/default_weight.rs b/pallet/currencies/src/default_weight.rs new file mode 100644 index 00000000..c0fb9277 --- /dev/null +++ b/pallet/currencies/src/default_weight.rs @@ -0,0 +1,29 @@ +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 2.0.0 + +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::weights::{constants::RocksDbWeight as DbWeight, Weight}; + +impl crate::WeightInfo for () { + fn transfer_non_native_currency() -> Weight { + Weight::from_parts(172_011_000, 0) + .saturating_add(DbWeight::get().reads(5 as u64)) + .saturating_add(DbWeight::get().writes(2 as u64)) + } + fn transfer_native_currency() -> Weight { + Weight::from_parts(43_023_000, 0) + } + fn update_balance_non_native_currency() -> Weight { + Weight::from_parts(137_440_000, 0) + .saturating_add(DbWeight::get().reads(5 as u64)) + .saturating_add(DbWeight::get().writes(2 as u64)) + } + fn update_balance_native_currency_creating() -> Weight { + Weight::from_parts(64_432_000, 0) + } + fn update_balance_native_currency_killing() -> Weight { + Weight::from_parts(62_595_000, 0) + } +} diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs new file mode 100644 index 00000000..6a970afa --- /dev/null +++ b/pallet/currencies/src/lib.rs @@ -0,0 +1,1295 @@ +//! # Currencies Module +//! +//! ## Overview +//! +//! The currencies module provides a mixed currencies system, by configuring a +//! native currency which implements `BasicCurrencyExtended`, and a +//! multi-currency which implements `MultiCurrency`. +//! +//! It also provides an adapter, to adapt `frame_support::traits::Currency` +//! implementations into `BasicCurrencyExtended`. +//! +//! The currencies module provides functionality of both `MultiCurrencyExtended` +//! and `BasicCurrencyExtended`, via unified interfaces, and all calls would be +//! delegated to the underlying multi-currency and base currency system. +//! A native currency ID could be set by `Config::GetNativeCurrencyId`, to +//! identify the native currency. +//! +//! ### Implementations +//! +//! The currencies module provides implementations for following traits. +//! +//! - `MultiCurrency` - Abstraction over a fungible multi-currency system. +//! - `MultiCurrencyExtended` - Extended `MultiCurrency` with additional helper types and methods, +//! like updating balance +//! by a given signed integer amount. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! - `transfer` - Transfer some balance to another account, in a given currency. +//! - `transfer_native_currency` - Transfer some balance to another account, in native currency set +//! in +//! `Config::NativeCurrency`. +//! - `update_balance` - Update balance by signed integer amount, in a given currency, root origin +//! required. + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::unused_unit)] + +use frame_support::{ + pallet_prelude::*, + traits::{ + tokens::{ + fungible, fungibles, DepositConsequence, Fortitude, Precision, Preservation, + Provenance, WithdrawConsequence, + }, + Currency as PalletCurrency, ExistenceRequirement, Get, Imbalance, + LockableCurrency as PalletLockableCurrency, + NamedReservableCurrency as PalletNamedReservableCurrency, + ReservableCurrency as PalletReservableCurrency, WithdrawReasons, + }, +}; +use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; +use orml_traits::{ + arithmetic::{Signed, SimpleArithmetic}, + currency::TransferAll, + BalanceStatus, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, + BasicReservableCurrency, LockIdentifier, MultiCurrency, MultiCurrencyExtended, + MultiLockableCurrency, MultiReservableCurrency, NamedBasicReservableCurrency, + NamedMultiReservableCurrency, +}; +use orml_utilities::with_transaction_result; +use scale_codec::Codec; +use sp_runtime::{ + traits::{CheckedSub, MaybeSerializeDeserialize, StaticLookup, Zero}, + DispatchError, DispatchResult, +}; +use sp_std::{fmt::Debug, marker, result}; + +mod mock; +mod tests; +mod weights; + +pub use module::*; +pub use weights::WeightInfo; + +#[frame_support::pallet] +pub mod module { + use super::*; + + pub(crate) type BalanceOf = <::MultiCurrency as MultiCurrency< + ::AccountId, + >>::Balance; + pub(crate) type CurrencyIdOf = <::MultiCurrency as MultiCurrency< + ::AccountId, + >>::CurrencyId; + pub(crate) type AmountOf = <::MultiCurrency as MultiCurrencyExtended< + ::AccountId, + >>::Amount; + pub(crate) type ReserveIdentifierOf = + <::MultiCurrency as NamedMultiReservableCurrency< + ::AccountId, + >>::ReserveIdentifier; + + #[pallet::config] + pub trait Config: frame_system::Config { + type MultiCurrency: TransferAll + + MultiCurrencyExtended + + MultiLockableCurrency + + MultiReservableCurrency + + NamedMultiReservableCurrency + + fungibles::Inspect< + Self::AccountId, + AssetId = CurrencyIdOf, + Balance = BalanceOf, + > + fungibles::Mutate< + Self::AccountId, + AssetId = CurrencyIdOf, + Balance = BalanceOf, + >; + + type NativeCurrency: BasicCurrencyExtended< + Self::AccountId, + Balance = BalanceOf, + Amount = AmountOf, + > + BasicLockableCurrency> + + BasicReservableCurrency> + + NamedBasicReservableCurrency< + Self::AccountId, + ReserveIdentifierOf, + Balance = BalanceOf, + > + fungible::Inspect> + + fungible::Mutate>; + + #[pallet::constant] + type GetNativeCurrencyId: Get>; + + /// Weight information for extrinsics in this module. + type WeightInfo: WeightInfo; + } + + #[pallet::error] + pub enum Error { + /// Unable to convert the Amount type into Balance. + AmountIntoBalanceFailed, + /// Balance is too low. + BalanceTooLow, + /// Deposit result is not expected + DepositFailed, + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet { + /// Transfer some balance to another account under `currency_id`. + /// + /// The dispatch origin for this call must be `Signed` by the + /// transactor. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::transfer_non_native_currency())] + pub fn transfer( + origin: OriginFor, + dest: ::Source, + currency_id: CurrencyIdOf, + #[pallet::compact] amount: BalanceOf, + ) -> DispatchResult { + let from = ensure_signed(origin)?; + let to = T::Lookup::lookup(dest)?; + >::transfer(currency_id, &from, &to, amount) + } + + /// Transfer some native currency to another account. + /// + /// The dispatch origin for this call must be `Signed` by the + /// transactor. + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::transfer_native_currency())] + pub fn transfer_native_currency( + origin: OriginFor, + dest: ::Source, + #[pallet::compact] amount: BalanceOf, + ) -> DispatchResult { + let from = ensure_signed(origin)?; + let to = T::Lookup::lookup(dest)?; + T::NativeCurrency::transfer(&from, &to, amount) + } + + /// update amount of account `who` under `currency_id`. + /// + /// The dispatch origin of this call must be _Root_. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::update_balance_non_native_currency())] + pub fn update_balance( + origin: OriginFor, + who: ::Source, + currency_id: CurrencyIdOf, + amount: AmountOf, + ) -> DispatchResult { + ensure_root(origin)?; + let dest = T::Lookup::lookup(who)?; + >::update_balance( + currency_id, + &dest, + amount, + ) + } + } +} + +impl MultiCurrency for Pallet { + type CurrencyId = CurrencyIdOf; + type Balance = BalanceOf; + + fn minimum_balance(currency_id: Self::CurrencyId) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::minimum_balance() + } else { + T::MultiCurrency::minimum_balance(currency_id) + } + } + + fn total_issuance(currency_id: Self::CurrencyId) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::total_issuance() + } else { + T::MultiCurrency::total_issuance(currency_id) + } + } + + fn total_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::total_balance(who) + } else { + T::MultiCurrency::total_balance(currency_id, who) + } + } + + fn free_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::free_balance(who) + } else { + T::MultiCurrency::free_balance(currency_id, who) + } + } + + fn ensure_can_withdraw( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::ensure_can_withdraw(who, amount) + } else { + T::MultiCurrency::ensure_can_withdraw(currency_id, who, amount) + } + } + + fn transfer( + currency_id: Self::CurrencyId, + from: &T::AccountId, + to: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if amount.is_zero() || from == to { + return Ok(()); + } + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::transfer(from, to, amount) + } else { + T::MultiCurrency::transfer(currency_id, from, to, amount) + } + } + + fn deposit( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::deposit(who, amount) + } else { + T::MultiCurrency::deposit(currency_id, who, amount) + } + } + + fn withdraw( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::withdraw(who, amount) + } else { + T::MultiCurrency::withdraw(currency_id, who, amount) + } + } + + fn can_slash(currency_id: Self::CurrencyId, who: &T::AccountId, amount: Self::Balance) -> bool { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::can_slash(who, amount) + } else { + T::MultiCurrency::can_slash(currency_id, who, amount) + } + } + + fn slash( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::slash(who, amount) + } else { + T::MultiCurrency::slash(currency_id, who, amount) + } + } +} + +impl MultiCurrencyExtended for Pallet { + type Amount = AmountOf; + + fn update_balance( + currency_id: Self::CurrencyId, + who: &T::AccountId, + by_amount: Self::Amount, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::update_balance(who, by_amount) + } else { + T::MultiCurrency::update_balance(currency_id, who, by_amount) + } + } +} + +impl MultiLockableCurrency for Pallet { + type Moment = BlockNumberFor; + + fn set_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::set_lock(lock_id, who, amount) + } else { + T::MultiCurrency::set_lock(lock_id, currency_id, who, amount) + } + } + + fn extend_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::extend_lock(lock_id, who, amount) + } else { + T::MultiCurrency::extend_lock(lock_id, currency_id, who, amount) + } + } + + fn remove_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::remove_lock(lock_id, who) + } else { + T::MultiCurrency::remove_lock(lock_id, currency_id, who) + } + } +} + +impl MultiReservableCurrency for Pallet { + fn can_reserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> bool { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::can_reserve(who, value) + } else { + T::MultiCurrency::can_reserve(currency_id, who, value) + } + } + + fn slash_reserved( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::slash_reserved(who, value) + } else { + T::MultiCurrency::slash_reserved(currency_id, who, value) + } + } + + fn reserved_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::reserved_balance(who) + } else { + T::MultiCurrency::reserved_balance(currency_id, who) + } + } + + fn reserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::reserve(who, value) + } else { + T::MultiCurrency::reserve(currency_id, who, value) + } + } + + fn unreserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::unreserve(who, value) + } else { + T::MultiCurrency::unreserve(currency_id, who, value) + } + } + + fn repatriate_reserved( + currency_id: Self::CurrencyId, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::repatriate_reserved(slashed, beneficiary, value, status) + } else { + T::MultiCurrency::repatriate_reserved(currency_id, slashed, beneficiary, value, status) + } + } +} + +impl NamedMultiReservableCurrency for Pallet { + type ReserveIdentifier = ReserveIdentifierOf; + + fn slash_reserved_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::slash_reserved_named(id, who, value) + } else { + T::MultiCurrency::slash_reserved_named(id, currency_id, who, value) + } + } + + fn reserved_balance_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::reserved_balance_named(id, who) + } else { + T::MultiCurrency::reserved_balance_named(id, currency_id, who) + } + } + + fn reserve_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::reserve_named(id, who, value) + } else { + T::MultiCurrency::reserve_named(id, currency_id, who, value) + } + } + + fn unreserve_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::unreserve_named(id, who, value) + } else { + T::MultiCurrency::unreserve_named(id, currency_id, who, value) + } + } + + fn repatriate_reserved_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + if currency_id == T::GetNativeCurrencyId::get() { + T::NativeCurrency::repatriate_reserved_named(id, slashed, beneficiary, value, status) + } else { + T::MultiCurrency::repatriate_reserved_named( + id, + currency_id, + slashed, + beneficiary, + value, + status, + ) + } + } +} + +/// impl fungiles for Pallet +impl fungibles::Inspect for Pallet { + type AssetId = CurrencyIdOf; + type Balance = BalanceOf; + + fn total_issuance(asset_id: Self::AssetId) -> Self::Balance { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::total_issuance() + } + _ => >::total_issuance(asset_id), + } + } + + fn minimum_balance(asset_id: Self::AssetId) -> Self::Balance { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::minimum_balance() + } + _ => >::minimum_balance(asset_id), + } + } + + fn balance(asset_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::balance(who) + } + _ => >::balance(asset_id, who), + } + } + + fn total_balance(asset_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::total_balance(who) + } + _ => >::total_balance(asset_id, who), + } + } + + fn reducible_balance( + asset_id: Self::AssetId, + who: &T::AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => >::reducible_balance( + who, preservation, force + ), + _ => >::reducible_balance( + asset_id, + who, + preservation, + force, + ), + } + } + + fn can_deposit( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::can_deposit(who, amount, provenance) + } + _ => >::can_deposit( + asset_id, who, amount, provenance, + ), + } + } + + fn can_withdraw( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::can_withdraw(who, amount) + } + _ => >::can_withdraw(asset_id, who, amount), + } + } + + fn asset_exists(asset_id: Self::AssetId) -> bool { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => true, + _ => >::asset_exists(asset_id), + } + } +} + +impl fungibles::Unbalanced for Pallet { + fn handle_dust(_dust: fungibles::Dust) { + // https://github.com/paritytech/substrate/blob/569aae5341ea0c1d10426fa1ec13a36c0b64393b/frame/support/src/traits/tokens/fungibles/regular.rs#L124 + // Note: currently the field of Dust type is private and there is no constructor for it, so + // we can't construct a Dust value and pass it. Do nothing here. + // `Pallet` overwrites these functions which can be called as user-level operation of + // fungibles traits when calling these functions, it will not actually reach + // `Unbalanced::handle_dust`. + } + + fn write_balance( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::write_balance(who, amount) + } + _ => { + >::write_balance(asset_id, who, amount) + } + } + } + + fn set_total_issuance(asset_id: Self::AssetId, amount: Self::Balance) { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::set_total_issuance(amount) + } + _ => { + >::set_total_issuance(asset_id, amount) + } + } + } +} + +impl fungibles::Mutate for Pallet { + fn mint_into( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Result { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::mint_into(who, amount) + } + _ => >::mint_into(asset_id, who, amount), + } + } + + fn burn_from( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + precision: Precision, + fortitude: Fortitude, + ) -> Result { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => { + >::burn_from( + who, amount, precision, fortitude, + ) + } + _ => >::burn_from( + asset_id, who, amount, precision, fortitude, + ), + } + } + + fn transfer( + asset_id: Self::AssetId, + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + match asset_id { + id if id == T::GetNativeCurrencyId::get() => >::transfer( + source, dest, amount, preservation + ), + _ => >::transfer( + asset_id, + source, + dest, + amount, + preservation, + ), + } + } +} + +pub struct Currency(marker::PhantomData, marker::PhantomData); + +impl BasicCurrency for Currency +where + T: Config, + GetCurrencyId: Get>, +{ + type Balance = BalanceOf; + + fn minimum_balance() -> Self::Balance { + >::minimum_balance(GetCurrencyId::get()) + } + + fn total_issuance() -> Self::Balance { + >::total_issuance(GetCurrencyId::get()) + } + + fn total_balance(who: &T::AccountId) -> Self::Balance { + >::total_balance(GetCurrencyId::get(), who) + } + + fn free_balance(who: &T::AccountId) -> Self::Balance { + >::free_balance(GetCurrencyId::get(), who) + } + + fn ensure_can_withdraw(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { + >::ensure_can_withdraw(GetCurrencyId::get(), who, amount) + } + + fn transfer(from: &T::AccountId, to: &T::AccountId, amount: Self::Balance) -> DispatchResult { + as MultiCurrency>::transfer(GetCurrencyId::get(), from, to, amount) + } + + fn deposit(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { + >::deposit(GetCurrencyId::get(), who, amount) + } + + fn withdraw(who: &T::AccountId, amount: Self::Balance) -> DispatchResult { + >::withdraw(GetCurrencyId::get(), who, amount) + } + + fn can_slash(who: &T::AccountId, amount: Self::Balance) -> bool { + >::can_slash(GetCurrencyId::get(), who, amount) + } + + fn slash(who: &T::AccountId, amount: Self::Balance) -> Self::Balance { + >::slash(GetCurrencyId::get(), who, amount) + } +} + +impl BasicCurrencyExtended for Currency +where + T: Config, + GetCurrencyId: Get>, +{ + type Amount = AmountOf; + + fn update_balance(who: &T::AccountId, by_amount: Self::Amount) -> DispatchResult { + as MultiCurrencyExtended>::update_balance( + GetCurrencyId::get(), + who, + by_amount, + ) + } +} + +impl BasicLockableCurrency for Currency +where + T: Config, + GetCurrencyId: Get>, +{ + type Moment = BlockNumberFor; + + fn set_lock( + lock_id: LockIdentifier, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + as MultiLockableCurrency>::set_lock( + lock_id, + GetCurrencyId::get(), + who, + amount, + ) + } + + fn extend_lock( + lock_id: LockIdentifier, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + as MultiLockableCurrency>::extend_lock( + lock_id, + GetCurrencyId::get(), + who, + amount, + ) + } + + fn remove_lock(lock_id: LockIdentifier, who: &T::AccountId) -> DispatchResult { + as MultiLockableCurrency>::remove_lock( + lock_id, + GetCurrencyId::get(), + who, + ) + } +} + +impl BasicReservableCurrency for Currency +where + T: Config, + GetCurrencyId: Get>, +{ + fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { + as MultiReservableCurrency>::can_reserve( + GetCurrencyId::get(), + who, + value, + ) + } + + fn slash_reserved(who: &T::AccountId, value: Self::Balance) -> Self::Balance { + as MultiReservableCurrency>::slash_reserved( + GetCurrencyId::get(), + who, + value, + ) + } + + fn reserved_balance(who: &T::AccountId) -> Self::Balance { + as MultiReservableCurrency>::reserved_balance( + GetCurrencyId::get(), + who, + ) + } + + fn reserve(who: &T::AccountId, value: Self::Balance) -> DispatchResult { + as MultiReservableCurrency>::reserve( + GetCurrencyId::get(), + who, + value, + ) + } + + fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { + as MultiReservableCurrency>::unreserve( + GetCurrencyId::get(), + who, + value, + ) + } + + fn repatriate_reserved( + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + as MultiReservableCurrency>::repatriate_reserved( + GetCurrencyId::get(), + slashed, + beneficiary, + value, + status, + ) + } +} + +impl NamedBasicReservableCurrency> + for Currency +where + T: Config, + GetCurrencyId: Get>, +{ + fn slash_reserved_named( + id: &ReserveIdentifierOf, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + as NamedMultiReservableCurrency>::slash_reserved_named( + id, + GetCurrencyId::get(), + who, + value, + ) + } + + fn reserved_balance_named(id: &ReserveIdentifierOf, who: &T::AccountId) -> Self::Balance { + as NamedMultiReservableCurrency>::reserved_balance_named( + id, + GetCurrencyId::get(), + who, + ) + } + + fn reserve_named( + id: &ReserveIdentifierOf, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + as NamedMultiReservableCurrency>::reserve_named( + id, + GetCurrencyId::get(), + who, + value, + ) + } + + fn unreserve_named( + id: &ReserveIdentifierOf, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + as NamedMultiReservableCurrency>::unreserve_named( + id, + GetCurrencyId::get(), + who, + value, + ) + } + + fn repatriate_reserved_named( + id: &ReserveIdentifierOf, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + as NamedMultiReservableCurrency>::repatriate_reserved_named( + id, + GetCurrencyId::get(), + slashed, + beneficiary, + value, + status, + ) + } +} + +pub type NativeCurrencyOf = Currency::GetNativeCurrencyId>; + +/// Adapt other currency traits implementation to `BasicCurrency`. +pub struct BasicCurrencyAdapter( + marker::PhantomData<(T, Currency, Amount, Moment)>, +); + +type PalletBalanceOf = >::Balance; + +// Adapt `frame_support::traits::Currency` +impl BasicCurrency + for BasicCurrencyAdapter +where + Currency: PalletCurrency, + T: Config, +{ + type Balance = PalletBalanceOf; + + fn minimum_balance() -> Self::Balance { + Currency::minimum_balance() + } + + fn total_issuance() -> Self::Balance { + Currency::total_issuance() + } + + fn total_balance(who: &AccountId) -> Self::Balance { + Currency::total_balance(who) + } + + fn free_balance(who: &AccountId) -> Self::Balance { + Currency::free_balance(who) + } + + fn ensure_can_withdraw(who: &AccountId, amount: Self::Balance) -> DispatchResult { + let new_balance = Self::free_balance(who) + .checked_sub(&amount) + .ok_or(Error::::BalanceTooLow)?; + + Currency::ensure_can_withdraw(who, amount, WithdrawReasons::all(), new_balance) + } + + fn transfer(from: &AccountId, to: &AccountId, amount: Self::Balance) -> DispatchResult { + Currency::transfer(from, to, amount, ExistenceRequirement::AllowDeath) + } + + fn deposit(who: &AccountId, amount: Self::Balance) -> DispatchResult { + if !amount.is_zero() { + let deposit_result = Currency::deposit_creating(who, amount); + let actual_deposit = deposit_result.peek(); + ensure!(actual_deposit == amount, Error::::DepositFailed); + } + Ok(()) + } + + fn withdraw(who: &AccountId, amount: Self::Balance) -> DispatchResult { + Currency::withdraw( + who, + amount, + WithdrawReasons::all(), + ExistenceRequirement::AllowDeath, + ) + .map(|_| ()) + } + + fn can_slash(who: &AccountId, amount: Self::Balance) -> bool { + Currency::can_slash(who, amount) + } + + fn slash(who: &AccountId, amount: Self::Balance) -> Self::Balance { + let (_, gap) = Currency::slash(who, amount); + gap + } +} + +// Adapt `frame_support::traits::Currency` +impl BasicCurrencyExtended + for BasicCurrencyAdapter +where + Amount: Signed + + TryInto> + + TryFrom> + + SimpleArithmetic + + Codec + + Copy + + MaybeSerializeDeserialize + + Debug + + Default + + MaxEncodedLen, + Currency: PalletCurrency, + T: Config, +{ + type Amount = Amount; + + fn update_balance(who: &AccountId, by_amount: Self::Amount) -> DispatchResult { + let by_balance = by_amount + .abs() + .try_into() + .map_err(|_| Error::::AmountIntoBalanceFailed)?; + if by_amount.is_positive() { + Self::deposit(who, by_balance) + } else { + Self::withdraw(who, by_balance) + } + } +} + +// Adapt `frame_support::traits::LockableCurrency` +impl BasicLockableCurrency + for BasicCurrencyAdapter +where + Currency: PalletLockableCurrency, + T: Config, +{ + type Moment = Moment; + + fn set_lock(lock_id: LockIdentifier, who: &AccountId, amount: Self::Balance) -> DispatchResult { + Currency::set_lock(lock_id, who, amount, WithdrawReasons::all()); + Ok(()) + } + + fn extend_lock( + lock_id: LockIdentifier, + who: &AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Currency::extend_lock(lock_id, who, amount, WithdrawReasons::all()); + Ok(()) + } + + fn remove_lock(lock_id: LockIdentifier, who: &AccountId) -> DispatchResult { + Currency::remove_lock(lock_id, who); + Ok(()) + } +} + +// Adapt `frame_support::traits::ReservableCurrency` +impl BasicReservableCurrency + for BasicCurrencyAdapter +where + Currency: PalletReservableCurrency, + T: Config, +{ + fn can_reserve(who: &AccountId, value: Self::Balance) -> bool { + Currency::can_reserve(who, value) + } + + fn slash_reserved(who: &AccountId, value: Self::Balance) -> Self::Balance { + let (_, gap) = Currency::slash_reserved(who, value); + gap + } + + fn reserved_balance(who: &AccountId) -> Self::Balance { + Currency::reserved_balance(who) + } + + fn reserve(who: &AccountId, value: Self::Balance) -> DispatchResult { + Currency::reserve(who, value) + } + + fn unreserve(who: &AccountId, value: Self::Balance) -> Self::Balance { + Currency::unreserve(who, value) + } + + fn repatriate_reserved( + slashed: &AccountId, + beneficiary: &AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + Currency::repatriate_reserved(slashed, beneficiary, value, status) + } +} + +// Adapt `frame_support::traits::NamedReservableCurrency` +impl + NamedBasicReservableCurrency + for BasicCurrencyAdapter +where + Currency: PalletNamedReservableCurrency, + T: Config, +{ + fn slash_reserved_named( + id: &ReserveIdentifier, + who: &AccountId, + value: Self::Balance, + ) -> Self::Balance { + let (_, gap) = Currency::slash_reserved_named(id, who, value); + gap + } + + fn reserved_balance_named(id: &ReserveIdentifier, who: &AccountId) -> Self::Balance { + Currency::reserved_balance_named(id, who) + } + + fn reserve_named( + id: &ReserveIdentifier, + who: &AccountId, + value: Self::Balance, + ) -> DispatchResult { + Currency::reserve_named(id, who, value) + } + + fn unreserve_named( + id: &ReserveIdentifier, + who: &AccountId, + value: Self::Balance, + ) -> Self::Balance { + Currency::unreserve_named(id, who, value) + } + + fn repatriate_reserved_named( + id: &ReserveIdentifier, + slashed: &AccountId, + beneficiary: &AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> result::Result { + Currency::repatriate_reserved_named(id, slashed, beneficiary, value, status) + } +} + +/// impl fungile for Currency +type FungibleBalanceOf = >::Balance; +impl fungible::Inspect + for BasicCurrencyAdapter +where + Currency: fungible::Inspect, + T: Config, +{ + type Balance = FungibleBalanceOf; + + fn total_issuance() -> Self::Balance { + >::total_issuance() + } + fn minimum_balance() -> Self::Balance { + >::minimum_balance() + } + fn balance(who: &T::AccountId) -> Self::Balance { + >::balance(who) + } + fn total_balance(who: &T::AccountId) -> Self::Balance { + >::total_balance(who) + } + fn reducible_balance( + who: &T::AccountId, + preservation: Preservation, + force: Fortitude, + ) -> Self::Balance { + >::reducible_balance(who, preservation, force) + } + fn can_deposit( + who: &T::AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + >::can_deposit(who, amount, provenance) + } + fn can_withdraw( + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + >::can_withdraw(who, amount) + } +} + +impl fungible::Unbalanced + for BasicCurrencyAdapter +where + Currency: fungible::Unbalanced, + T: Config, +{ + fn handle_dust(_dust: fungible::Dust) { + // https://github.com/paritytech/substrate/blob/569aae5341ea0c1d10426fa1ec13a36c0b64393b/frame/support/src/traits/tokens/fungibles/regular.rs#L124 + // Note: currently the field of Dust type is private and there is no constructor for it, so + // we can't construct a Dust value and pass it. + // `BasicCurrencyAdapter` overwrites these functions which can be called as user-level + // operation of fungible traits when calling these functions, it will not actually reach + // `Unbalanced::handle_dust`. + } + + fn write_balance( + who: &T::AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + >::write_balance(who, amount) + } + + fn set_total_issuance(amount: Self::Balance) { + >::set_total_issuance(amount) + } +} + +impl fungible::Mutate + for BasicCurrencyAdapter +where + Currency: fungible::Mutate, + T: Config, +{ + fn mint_into( + who: &T::AccountId, + amount: Self::Balance, + ) -> Result { + >::mint_into(who, amount) + } + + fn burn_from( + who: &T::AccountId, + amount: Self::Balance, + precision: Precision, + fortitude: Fortitude, + ) -> Result { + >::burn_from(who, amount, precision, fortitude) + } + + fn transfer( + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + >::transfer(source, dest, amount, preservation) + } +} + +impl TransferAll for Pallet { + fn transfer_all(source: &T::AccountId, dest: &T::AccountId) -> DispatchResult { + with_transaction_result(|| { + // transfer non-native free to dest + T::MultiCurrency::transfer_all(source, dest)?; + + // transfer all free to dest + T::NativeCurrency::transfer(source, dest, T::NativeCurrency::free_balance(source)) + }) + } +} diff --git a/pallet/currencies/src/mock.rs b/pallet/currencies/src/mock.rs new file mode 100644 index 00000000..210e99cc --- /dev/null +++ b/pallet/currencies/src/mock.rs @@ -0,0 +1,174 @@ +//! Mocks for the currencies module. + +#![cfg(test)] + +use super::*; +use frame_support::{ + construct_runtime, derive_impl, parameter_types, + traits::{ConstU32, ConstU64, Nothing}, + PalletId, +}; +use orml_traits::{currency::MutationHooks, parameter_type_with_key}; +use sp_runtime::{ + traits::{AccountIdConversion, IdentityLookup}, + AccountId32, BuildStorage, +}; + +use crate as currencies; + +pub type ReserveIdentifier = [u8; 8]; + +pub type AccountId = AccountId32; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Runtime { + type Block = Block; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type AccountData = pallet_balances::AccountData; +} + +type CurrencyId = u32; +type Balance = u64; + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<2>; + type AccountStore = frame_system::Pallet; + type MaxLocks = (); + type MaxReserves = ConstU32<2>; + type ReserveIdentifier = ReserveIdentifier; + type WeightInfo = (); + type FreezeIdentifier = [u8; 8]; + type MaxHolds = (); + type MaxFreezes = (); + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; +} + +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Default::default() + }; +} + +parameter_types! { + pub DustAccount: AccountId = PalletId(*b"orml/dst").into_account_truncating(); +} + +pub struct CurrencyHooks(marker::PhantomData); +impl MutationHooks + for CurrencyHooks +where + T::AccountId: From, +{ + type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type PreDeposit = (); + type PostDeposit = (); + type PreTransfer = (); + type PostTransfer = (); + type OnNewTokenAccount = (); + type OnKilledTokenAccount = (); +} + +impl orml_tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = i64; + type CurrencyId = CurrencyId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = CurrencyHooks; + type MaxLocks = ConstU32<100_000>; + type MaxReserves = ConstU32<100_000>; + type ReserveIdentifier = ReserveIdentifier; + type DustRemovalWhitelist = Nothing; +} + +pub const NATIVE_CURRENCY_ID: CurrencyId = 1; +pub const X_TOKEN_ID: CurrencyId = 2; + +parameter_types! { + pub const GetNativeCurrencyId: CurrencyId = NATIVE_CURRENCY_ID; +} + +impl Config for Runtime { + type MultiCurrency = Tokens; + type NativeCurrency = AdaptedBasicCurrency; + type GetNativeCurrencyId = GetNativeCurrencyId; + type WeightInfo = (); +} +pub type NativeCurrency = NativeCurrencyOf; +pub type AdaptedBasicCurrency = BasicCurrencyAdapter; + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Runtime { + System: frame_system, + Currencies: currencies, + Tokens: orml_tokens, + PalletBalances: pallet_balances, + } +); + +pub const ALICE: AccountId = AccountId32::new([1u8; 32]); +pub const BOB: AccountId = AccountId32::new([2u8; 32]); +pub const EVA: AccountId = AccountId32::new([5u8; 32]); +pub const ID_1: LockIdentifier = *b"1 "; +pub const RID_1: ReserveIdentifier = [1u8; 8]; +pub const RID_2: ReserveIdentifier = [2u8; 8]; + +#[derive(Default)] +pub struct ExtBuilder { + balances: Vec<(AccountId, CurrencyId, Balance)>, +} + +impl ExtBuilder { + pub fn balances(mut self, balances: Vec<(AccountId, CurrencyId, Balance)>) -> Self { + self.balances = balances; + self + } + + pub fn one_hundred_for_alice_n_bob(self) -> Self { + self.balances(vec![ + (ALICE, NATIVE_CURRENCY_ID, 100), + (BOB, NATIVE_CURRENCY_ID, 100), + (ALICE, X_TOKEN_ID, 100), + (BOB, X_TOKEN_ID, 100), + ]) + } + + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self + .balances + .clone() + .into_iter() + .filter(|(_, currency_id, _)| *currency_id == NATIVE_CURRENCY_ID) + .map(|(account_id, _, initial_balance)| (account_id, initial_balance)) + .collect::>(), + } + .assimilate_storage(&mut t) + .unwrap(); + + orml_tokens::GenesisConfig:: { + balances: self + .balances + .into_iter() + .filter(|(_, currency_id, _)| *currency_id != NATIVE_CURRENCY_ID) + .collect::>(), + } + .assimilate_storage(&mut t) + .unwrap(); + + t.into() + } +} diff --git a/pallet/currencies/src/tests.rs b/pallet/currencies/src/tests.rs new file mode 100644 index 00000000..88bc4981 --- /dev/null +++ b/pallet/currencies/src/tests.rs @@ -0,0 +1,473 @@ +//! Unit tests for the currencies module. + +#![cfg(test)] + +use super::*; +use frame_support::{assert_noop, assert_ok}; +use mock::*; +use sp_runtime::traits::BadOrigin; + +#[test] +fn multi_lockable_currency_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(Currencies::set_lock(ID_1, X_TOKEN_ID, &ALICE, 50)); + assert_eq!(Tokens::locks(&ALICE, X_TOKEN_ID).len(), 1); + assert_ok!(Currencies::set_lock(ID_1, NATIVE_CURRENCY_ID, &ALICE, 50)); + assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + }); +} + +#[test] +fn multi_reservable_currency_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_eq!(Currencies::total_issuance(NATIVE_CURRENCY_ID), 200); + assert_eq!(Currencies::total_issuance(X_TOKEN_ID), 200); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 100); + assert_eq!(NativeCurrency::free_balance(&ALICE), 100); + + assert_ok!(Currencies::reserve(X_TOKEN_ID, &ALICE, 30)); + assert_ok!(Currencies::reserve(NATIVE_CURRENCY_ID, &ALICE, 40)); + assert_eq!(Currencies::reserved_balance(X_TOKEN_ID, &ALICE), 30); + assert_eq!(Currencies::reserved_balance(NATIVE_CURRENCY_ID, &ALICE), 40); + }); +} + +#[test] +fn named_multi_reservable_currency_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_eq!(Currencies::total_issuance(NATIVE_CURRENCY_ID), 200); + assert_eq!(Currencies::total_issuance(X_TOKEN_ID), 200); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 100); + assert_eq!(NativeCurrency::free_balance(&ALICE), 100); + + assert_ok!(Currencies::reserve_named(&RID_1, X_TOKEN_ID, &ALICE, 30)); + assert_ok!(Currencies::reserve_named(&RID_2, X_TOKEN_ID, &ALICE, 50)); + assert_ok!(Currencies::reserve_named( + &RID_1, + NATIVE_CURRENCY_ID, + &ALICE, + 20 + )); + assert_ok!(Currencies::reserve_named( + &RID_2, + NATIVE_CURRENCY_ID, + &ALICE, + 60 + )); + let r1x_before = 30; + assert_eq!( + Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), + r1x_before + ); + let r2x_before = 50; + assert_eq!( + Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), + r2x_before + ); + let r1n_before = 20; + assert_eq!( + Currencies::reserved_balance_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE), + r1n_before + ); + let r2n_before = 60; + assert_eq!( + Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), + r2n_before + ); + + let n_free_before = 20; + assert_eq!(NativeCurrency::free_balance(&ALICE), n_free_before); + let x_free_before = 20; + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), x_free_before); + + assert_eq!( + Currencies::unreserve_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE, 100), + 80 + ); + assert_eq!(NativeCurrency::free_balance(&ALICE), n_free_before + 20); + assert_eq!( + Currencies::reserved_balance_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE), + 0 + ); + + assert_eq!( + Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), + r2n_before + ); + assert_eq!( + Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), + r1x_before + ); + assert_eq!( + Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), + r2x_before + ); + + assert_eq!( + Currencies::unreserve_named(&RID_1, X_TOKEN_ID, &ALICE, 100), + 70 + ); + assert_eq!( + Currencies::free_balance(X_TOKEN_ID, &ALICE), + x_free_before + 30 + ); + assert_eq!( + Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), + 0 + ); + + assert_eq!( + Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), + r2x_before + ); + assert_eq!( + Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), + r2n_before + ); + }); +} + +#[test] +fn native_currency_lockable_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(NativeCurrency::set_lock(ID_1, &ALICE, 10)); + assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + assert_ok!(NativeCurrency::remove_lock(ID_1, &ALICE)); + assert_eq!(PalletBalances::locks(&ALICE).len(), 0); + }); +} + +#[test] +fn native_currency_reservable_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(NativeCurrency::reserve(&ALICE, 50)); + assert_eq!(NativeCurrency::reserved_balance(&ALICE), 50); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_lockable() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::set_lock(ID_1, &ALICE, 10)); + assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + assert_ok!(AdaptedBasicCurrency::remove_lock(ID_1, &ALICE)); + assert_eq!(PalletBalances::locks(&ALICE).len(), 0); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_reservable() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::reserve(&ALICE, 50)); + assert_eq!(AdaptedBasicCurrency::reserved_balance(&ALICE), 50); + }); +} + +#[test] +fn named_basic_currency_adapting_pallet_balances_reservable() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::reserve_named(&RID_1, &ALICE, 50)); + assert_ok!(AdaptedBasicCurrency::reserve_named(&RID_2, &ALICE, 30)); + assert_eq!( + AdaptedBasicCurrency::reserved_balance_named(&RID_1, &ALICE), + 50 + ); + assert_eq!( + AdaptedBasicCurrency::reserved_balance_named(&RID_2, &ALICE), + 30 + ); + assert_eq!(AdaptedBasicCurrency::free_balance(&ALICE), 20); + + assert_eq!( + AdaptedBasicCurrency::unreserve_named(&RID_1, &ALICE, 80), + 30 + ); + assert_eq!(AdaptedBasicCurrency::free_balance(&ALICE), 70); + assert_eq!( + AdaptedBasicCurrency::reserved_balance_named(&RID_1, &ALICE), + 0 + ); + + assert_eq!( + AdaptedBasicCurrency::reserved_balance_named(&RID_2, &ALICE), + 30 + ); + }); +} + +#[test] +fn multi_currency_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(Currencies::transfer( + Some(ALICE).into(), + BOB, + X_TOKEN_ID, + 50 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 50); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &BOB), 150); + }); +} + +#[test] +fn multi_currency_extended_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!( + >::update_balance( + X_TOKEN_ID, &ALICE, 50 + ) + ); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 150); + }); +} + +#[test] +fn native_currency_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(Currencies::transfer_native_currency( + Some(ALICE).into(), + BOB, + 50 + )); + assert_eq!(NativeCurrency::free_balance(&ALICE), 50); + assert_eq!(NativeCurrency::free_balance(&BOB), 150); + + assert_ok!(NativeCurrency::transfer(&ALICE, &BOB, 10)); + assert_eq!(NativeCurrency::free_balance(&ALICE), 40); + assert_eq!(NativeCurrency::free_balance(&BOB), 160); + + assert_eq!(Currencies::slash(NATIVE_CURRENCY_ID, &ALICE, 10), 0); + assert_eq!(NativeCurrency::free_balance(&ALICE), 30); + assert_eq!(NativeCurrency::total_issuance(), 190); + }); +} + +#[test] +fn native_currency_extended_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(NativeCurrency::update_balance(&ALICE, 10)); + assert_eq!(NativeCurrency::free_balance(&ALICE), 110); + + assert_ok!( + >::update_balance( + NATIVE_CURRENCY_ID, + &ALICE, + 10 + ) + ); + assert_eq!(NativeCurrency::free_balance(&ALICE), 120); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_transfer() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::transfer(&ALICE, &BOB, 50)); + assert_eq!(PalletBalances::total_balance(&ALICE), 50); + assert_eq!(PalletBalances::total_balance(&BOB), 150); + + // creation fee + assert_ok!(AdaptedBasicCurrency::transfer(&ALICE, &EVA, 10)); + assert_eq!(PalletBalances::total_balance(&ALICE), 40); + assert_eq!(PalletBalances::total_balance(&EVA), 10); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_deposit() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::deposit(&EVA, 50)); + assert_eq!(PalletBalances::total_balance(&EVA), 50); + assert_eq!(PalletBalances::total_issuance(), 250); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_deposit_throw_error_when_actual_deposit_is_not_expected() +{ + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_eq!(PalletBalances::total_balance(&EVA), 0); + assert_eq!(PalletBalances::total_issuance(), 200); + assert_noop!( + AdaptedBasicCurrency::deposit(&EVA, 1), + Error::::DepositFailed + ); + assert_eq!(PalletBalances::total_balance(&EVA), 0); + assert_eq!(PalletBalances::total_issuance(), 200); + assert_ok!(AdaptedBasicCurrency::deposit(&EVA, 2)); + assert_eq!(PalletBalances::total_balance(&EVA), 2); + assert_eq!(PalletBalances::total_issuance(), 202); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_withdraw() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::withdraw(&ALICE, 100)); + assert_eq!(PalletBalances::total_balance(&ALICE), 0); + assert_eq!(PalletBalances::total_issuance(), 100); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_slash() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_eq!(AdaptedBasicCurrency::slash(&ALICE, 101), 1); + assert_eq!(PalletBalances::total_balance(&ALICE), 0); + assert_eq!(PalletBalances::total_issuance(), 100); + }); +} + +#[test] +fn basic_currency_adapting_pallet_balances_update_balance() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(AdaptedBasicCurrency::update_balance(&ALICE, -10)); + assert_eq!(PalletBalances::total_balance(&ALICE), 90); + assert_eq!(PalletBalances::total_issuance(), 190); + }); +} + +#[test] +fn update_balance_call_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + assert_ok!(Currencies::update_balance( + RuntimeOrigin::root(), + ALICE, + NATIVE_CURRENCY_ID, + -10 + )); + assert_eq!(NativeCurrency::free_balance(&ALICE), 90); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 100); + assert_ok!(Currencies::update_balance( + RuntimeOrigin::root(), + ALICE, + X_TOKEN_ID, + 10 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 110); + }); +} + +#[test] +fn update_balance_call_fails_if_not_root_origin() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Currencies::update_balance(Some(ALICE).into(), ALICE, X_TOKEN_ID, 100), + BadOrigin + ); + }); +} + +#[test] +fn call_event_should_work() { + ExtBuilder::default() + .one_hundred_for_alice_n_bob() + .build() + .execute_with(|| { + System::set_block_number(1); + + assert_ok!(Currencies::transfer( + Some(ALICE).into(), + BOB, + X_TOKEN_ID, + 50 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 50); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &BOB), 150); + System::assert_last_event(RuntimeEvent::Tokens(orml_tokens::Event::Transfer { + currency_id: X_TOKEN_ID, + from: ALICE, + to: BOB, + amount: 50, + })); + + assert_ok!(>::transfer( + X_TOKEN_ID, &ALICE, &BOB, 10 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 40); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &BOB), 160); + System::assert_last_event(RuntimeEvent::Tokens(orml_tokens::Event::Transfer { + currency_id: X_TOKEN_ID, + from: ALICE, + to: BOB, + amount: 10, + })); + + assert_ok!(>::deposit( + X_TOKEN_ID, &ALICE, 100 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 140); + System::assert_last_event(RuntimeEvent::Tokens(orml_tokens::Event::Deposited { + currency_id: X_TOKEN_ID, + who: ALICE, + amount: 100, + })); + + assert_ok!(>::withdraw( + X_TOKEN_ID, &ALICE, 20 + )); + assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 120); + System::assert_last_event(RuntimeEvent::Tokens(orml_tokens::Event::Withdrawn { + currency_id: X_TOKEN_ID, + who: ALICE, + amount: 20, + })); + }); +} diff --git a/pallet/currencies/src/weights.rs b/pallet/currencies/src/weights.rs new file mode 100644 index 00000000..d6119781 --- /dev/null +++ b/pallet/currencies/src/weights.rs @@ -0,0 +1,67 @@ +//! Autogenerated weights for module_currencies +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 +//! DATE: 2021-05-04, STEPS: [50, ], REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// /Users/xiliangchen/projects/acala/target/release/acala +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=module_currencies +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./currencies/src/weights.rs +// --template +// ../templates/orml-weight-template.hbs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for module_currencies. +pub trait WeightInfo { + fn transfer_non_native_currency() -> Weight; + fn transfer_native_currency() -> Weight; + fn update_balance_non_native_currency() -> Weight; + fn update_balance_native_currency_creating() -> Weight; + fn update_balance_native_currency_killing() -> Weight; +} + +/// Default weights. +impl WeightInfo for () { + fn transfer_non_native_currency() -> Weight { + Weight::from_parts(60_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + } + fn transfer_native_currency() -> Weight { + Weight::from_parts(60_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + fn update_balance_non_native_currency() -> Weight { + Weight::from_parts(29_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + fn update_balance_native_currency_creating() -> Weight { + Weight::from_parts(31_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } + fn update_balance_native_currency_killing() -> Weight { + Weight::from_parts(37_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } +} diff --git a/runtime/brooklyn/Cargo.toml b/runtime/brooklyn/Cargo.toml index 886d0e88..9ef9b285 100644 --- a/runtime/brooklyn/Cargo.toml +++ b/runtime/brooklyn/Cargo.toml @@ -152,6 +152,7 @@ reward-rpc-runtime-api.workspace = true vault-registry-rpc-runtime-api.workspace = true # Dex +pallet-currencies.workspace = true pallet-dex.workspace = true [build-dependencies] @@ -287,6 +288,7 @@ std = [ "vault-registry-rpc-runtime-api/std", #Dex + "pallet-currencies/std", "pallet-dex/std", ] aura = [] From 44546f550c4b0c991f8e8884abeff135ecd2f3b5 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 15 May 2024 21:34:17 +0800 Subject: [PATCH 03/27] init erc-20 pallet --- Cargo.lock | 25 +++ Cargo.toml | 2 + pallet/erc-20/Cargo.toml | 57 ++++++ pallet/erc-20/src/lib.rs | 349 ++++++++++++++++++++++++++++++++++++ primitives/Cargo.toml | 2 + primitives/src/evm.rs | 37 ++++ primitives/src/lib.rs | 1 + runtime/brooklyn/Cargo.toml | 2 + 8 files changed, 475 insertions(+) create mode 100644 pallet/erc-20/Cargo.toml create mode 100644 pallet/erc-20/src/lib.rs create mode 100644 primitives/src/evm.rs diff --git a/Cargo.lock b/Cargo.lock index ac6ca4ea..eababd95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4679,6 +4679,7 @@ dependencies = [ name = "ggx-primitives" version = "0.0.1" dependencies = [ + "astar-primitives", "bstringify", "frame-support", "log 0.4.20", @@ -4850,6 +4851,7 @@ dependencies = [ "pallet-dex", "pallet-dynamic-fee", "pallet-election-provider-multi-phase", + "pallet-erc20", "pallet-eth2-light-client", "pallet-ethereum", "pallet-ethereum-checked", @@ -8716,6 +8718,29 @@ dependencies = [ "sp-runtime 7.0.0", ] +[[package]] +name = "pallet-erc20" +version = "2.25.0" +dependencies = [ + "astar-primitives", + "ethereum-types 0.14.1", + "frame-support", + "frame-system", + "ggx-primitives", + "hex", + "impl-trait-for-tuples", + "num_enum 0.5.11", + "pallet-balances", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "serde_json", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", +] + [[package]] name = "pallet-eth2-light-client" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 6eb8e7dd..a6be3b73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ bstringify = { version = "0.1.2" } cfg-if = "1.0" clap = { version = "4.1", features = ["derive"] } derive_more = { version = "0.99" } +ethereum-types = { version = "0.14.0", default-features = false } env_logger = "0.10.0" ethers = { version = "2.0.4" } futures = "0.3.28" @@ -302,6 +303,7 @@ vault-registry-rpc-runtime-api = { git = "https://github.com/ggxchain/interbtc.g # Dex pallet-currencies = { path = "pallet/currencies", default-features = false } +pallet-erc20 = { path = "pallet/erc-20", default-features = false } pallet-dex = { path = "pallet/dex", default-features = false } # Supress warnings from the peerset in logs during syncing diff --git a/pallet/erc-20/Cargo.toml b/pallet/erc-20/Cargo.toml new file mode 100644 index 00000000..713c3d31 --- /dev/null +++ b/pallet/erc-20/Cargo.toml @@ -0,0 +1,57 @@ +[package] +name = "pallet-erc20" +version = "2.25.0" +authors = ["Acala Developers"] +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +ethereum-types = { workspace = true } +impl-trait-for-tuples = { workspace = true } +num_enum = { workspace = true } + +scale-codec = { workspace = true } +scale-info = { workspace = true } +frame-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +sp-std = { workspace = true } +sp-io = { workspace = true } + +ggx-primitives = { workspace = true } +astar-primitives = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true, features = ["std"] } +hex = { workspace = true, features = ["std"] } +pallet-balances = { workspace = true, features = ["std"] } +pallet-timestamp = { workspace = true, features = ["std"] } + +[features] +default = ["std"] +std = [ + "astar-primitives/std", + "ethereum-types/std", + "frame-support/std", + "frame-system/std", + "num_enum/std", + "ggx-primitives/std", + "scale-codec/std", + "scale-info/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs new file mode 100644 index 00000000..09554baf --- /dev/null +++ b/pallet/erc-20/src/lib.rs @@ -0,0 +1,349 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2024 Acala Foundation. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::unused_unit)] + +use ethereum_types::BigEndianHash; +use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + traits::{OriginTrait, ReservableCurrency}, + PalletId, +}; +use frame_system::pallet_prelude::*; +// use module_evm::{ExitReason, ExitSucceed}; +// use module_support::{ +// evm::limits::{erc20, liquidation}, +// EVMBridge as EVMBridgeTrait, ExecutionMode, Context, LiquidationEvmBridge as LiquidationEvmBridgeT, EVM, +// }; +use frame_support::{sp_runtime::traits::AccountIdConversion, traits::Currency}; +use ggx_primitives::evm::{EVMBridgeTrait, EvmAddress}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +use sp_core::{H160, H256, U256}; +use sp_runtime::{ArithmeticError, DispatchError, SaturatedConversion}; +use sp_std::{vec, vec::Vec}; + +use astar_primitives::{ + ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx, EthereumTxInput}, + xvm::{ + CallFailure, CallOutput, CallResult, Context, FailureError::*, FailureRevert::*, VmId, + XvmCall, + }, + Balance, +}; + +type AccountIdOf = ::AccountId; +//type BalanceOf = <::EVM as EVM>>::Balance; +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +// #[module_evm_utility_macro::generate_function_selector] +// #[derive(RuntimeDebug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +// #[repr(u32)] +// pub enum Action { +// Name = "name()", +// Symbol = "symbol()", +// Decimals = "decimals()", +// TotalSupply = "totalSupply()", +// BalanceOf = "balanceOf(address)", +// Transfer = "transfer(address,uint256)", +// Liquidate = "liquidate(address,address,uint256,uint256)", +// OnCollateralTransfer = "onCollateralTransfer(address,uint256)", +// OnRepaymentRefund = "onRepaymentRefund(address,uint256)", +// } + +// mod mock; +// mod tests; + +pub use module::*; + +#[frame_support::pallet] +pub mod module { + use super::*; + + /// EvmBridge module trait + #[pallet::config] + pub trait Config: frame_system::Config { + //type EVM: EVM>; + + /// The currency mechanism. //todo need replace to EVM> + type Currency: ReservableCurrency; + + #[pallet::constant] + type PalletId: Get; + + type XvmCallApi: XvmCall; + } + + #[pallet::error] + pub enum Error { + /// Execution failed + ExecutionFail, + /// Execution reverted + ExecutionRevert, + /// Execution fatal + ExecutionFatal, + /// Execution error + ExecutionError, + /// Invalid return value + InvalidReturnValue, + } + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} +} + +pub struct EVMBridge(sp_std::marker::PhantomData); + +impl EVMBridgeTrait, BalanceOf> for EVMBridge { + // Calls the name method on an ERC20 contract using the given context + // and returns the token name. + fn name(context: Context) -> Result, DispatchError> { + // // ERC20.name method hash + // let input = Into::::into(Action::Name).to_be_bytes().to_vec(); + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::NAME.gas, + // erc20::NAME.storage, + // ExecutionMode::View, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + // Pallet::::decode_string(info.value.as_slice().to_vec()) + + // let context = Context { + // source_vm_id: VmId::Wasm, + // weight_limit: Weight::from_parts(1_000_000, 1_000_000), + // }; + // let vm_id = VmId::Evm; + // let target = H160::repeat_byte(0xFF); + // let input = vec![1; 65_536]; + // let value = 1_000_000u128; + + // T::XvmCallApi::call( + // context, + // vm_id, + // T::account_id(), //ALICE, + // target.encode(), + // input.clone(), + // value, + // None, + // ); + + Ok(vec![]) + } + + // Calls the symbol method on an ERC20 contract using the given context + // and returns the token symbol. + fn symbol(context: Context) -> Result, DispatchError> { + // ERC20.symbol method hash + // let input = Into::::into(Action::Symbol).to_be_bytes().to_vec(); + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::SYMBOL.gas, + // erc20::SYMBOL.storage, + // ExecutionMode::View, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + // Pallet::::decode_string(info.value.as_slice().to_vec()) + Ok(vec![]) + } + + // Calls the decimals method on an ERC20 contract using the given context + // and returns the decimals. + fn decimals(context: Context) -> Result { + // ERC20.decimals method hash + // let input = Into::::into(Action::Decimals).to_be_bytes().to_vec(); + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::DECIMALS.gas, + // erc20::DECIMALS.storage, + // ExecutionMode::View, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + + // ensure!(info.value.len() == 32, Error::::InvalidReturnValue); + // let value: u8 = U256::from(info.value.as_slice()) + // .try_into() + // .map_err(|_| ArithmeticError::Overflow)?; + // Ok(value) + Ok(0) + } + + // Calls the totalSupply method on an ERC20 contract using the given context + // and returns the total supply. + fn total_supply(context: Context) -> Result, DispatchError> { + // ERC20.totalSupply method hash + // let input = Into::::into(Action::TotalSupply) + // .to_be_bytes() + // .to_vec(); + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::TOTAL_SUPPLY.gas, + // erc20::TOTAL_SUPPLY.storage, + // ExecutionMode::View, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + + // ensure!(info.value.len() == 32, Error::::InvalidReturnValue); + // let value: u128 = U256::from(info.value.as_slice()) + // .try_into() + // .map_err(|_| ArithmeticError::Overflow)?; + // let supply = value.try_into().map_err(|_| ArithmeticError::Overflow)?; + // Ok(supply) + Ok(Default::default()) + } + + // Calls the balanceOf method on an ERC20 contract using the given context + // and returns the address's balance. + fn balance_of(context: Context, address: H160) -> Result, DispatchError> { + // // ERC20.balanceOf method hash + // let mut input = Into::::into(Action::BalanceOf).to_be_bytes().to_vec(); + // // append address + // input.extend_from_slice(H256::from(address).as_bytes()); + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::BALANCE_OF.gas, + // erc20::BALANCE_OF.storage, + // ExecutionMode::View, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + + // let value: u128 = U256::from(info.value.as_slice()) + // .try_into() + // .map_err(|_| ArithmeticError::Overflow)?; + // let balance = value.try_into().map_err(|_| ArithmeticError::Overflow)?; + // Ok(balance) + Ok(Default::default()) + } + + // Calls the transfer method on an ERC20 contract using the given context. + fn transfer( + context: Context, + source: AccountIdOf, + to: H160, + value: BalanceOf, + ) -> DispatchResult { + // // ERC20.transfer method hash + // let mut input = Into::::into(Action::Transfer).to_be_bytes().to_vec(); + // // append receiver address + // input.extend_from_slice(H256::from(to).as_bytes()); + // // append amount to be transferred + // input.extend_from_slice( + // H256::from_uint(&U256::from(value.saturated_into::())).as_bytes(), + // ); + + // let storage_limit = if context.origin == Default::default() { + // 0 + // } else { + // erc20::TRANSFER.storage + // }; + + // let info = T::EVM::execute( + // context, + // input, + // Default::default(), + // erc20::TRANSFER.gas, + // storage_limit, + // ExecutionMode::Execute, + // )?; + + // Pallet::::handle_exit_reason(info.exit_reason)?; + + // // return value is true. + // let mut bytes = [0u8; 32]; + // U256::from(1).to_big_endian(&mut bytes); + + // // Check return value to make sure not calling on empty contracts. + // ensure!( + // !info.value.is_empty() && info.value == bytes, + // Error::::InvalidReturnValue + // ); + Ok(()) + } +} + +impl Pallet { + pub fn account_id() -> ::AccountId { + ::PalletId::get().into_account_truncating() + } + // fn handle_exit_reason(exit_reason: ExitReason) -> Result<(), DispatchError> { + // match exit_reason { + // ExitReason::Succeed(ExitSucceed::Returned) => Ok(()), + // ExitReason::Succeed(ExitSucceed::Stopped) => Ok(()), + // ExitReason::Succeed(_) => Err(Error::::ExecutionFail.into()), + // ExitReason::Revert(_) => Err(Error::::ExecutionRevert.into()), + // ExitReason::Fatal(_) => Err(Error::::ExecutionFatal.into()), + // ExitReason::Error(_) => Err(Error::::ExecutionError.into()), + // } + // } + + // fn decode_string(output: Vec) -> Result, DispatchError> { + // // output is 32-byte aligned and consists of 3 parts: + // // - part 1: 32 byte, the offset of its description is passed in the position of + // // the corresponding parameter or return value. + // // - part 2: 32 byte, string length + // // - part 3: string data + // ensure!( + // output.len() >= 64 && output.len() % 32 == 0, + // Error::::InvalidReturnValue + // ); + + // let offset = U256::from_big_endian(&output[0..32]); + // let length = U256::from_big_endian(&output[offset.as_usize()..offset.as_usize() + 32]); + // ensure!( + // // output is 32-byte aligned. ensure total_length >= offset + string length + string data length. + // output.len() >= offset.as_usize() + 32 + length.as_usize(), + // Error::::InvalidReturnValue + // ); + + // let mut data = Vec::new(); + // data.extend_from_slice( + // &output[offset.as_usize() + 32..offset.as_usize() + 32 + length.as_usize()], + // ); + + // Ok(data.to_vec()) + // } +} diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 7d282be7..e83061fc 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -5,6 +5,7 @@ authors.workspace = true edition.workspace = true [dependencies] +astar-primitives = { workspace = true } bstringify = { workspace = true } log = { workspace = true } serde = { workspace = true, features = ["alloc", "derive"] } @@ -27,6 +28,7 @@ serde_json = { workspace = true, features = ["std"] } [features] default = ["std"] std = [ + "astar-primitives/std", "serde/std", "scale-codec/std", "scale-info/std", diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs new file mode 100644 index 00000000..df6ca6a6 --- /dev/null +++ b/primitives/src/evm.rs @@ -0,0 +1,37 @@ +use astar_primitives::xvm::Context; + +use frame_support::inherent::Vec; +use sp_runtime::{DispatchError, DispatchResult}; + +pub type EvmAddress = sp_core::H160; + +/// An abstraction of EVMBridge +pub trait EVMBridgeTrait { + /// Execute ERC20.name() to read token name from ERC20 contract + fn name(context: Context) -> Result, DispatchError>; + /// Execute ERC20.symbol() to read token symbol from ERC20 contract + fn symbol(context: Context) -> Result, DispatchError>; + /// Execute ERC20.decimals() to read token decimals from ERC20 contract + fn decimals(context: Context) -> Result; + /// Execute ERC20.totalSupply() to read total supply from ERC20 contract + fn total_supply(context: Context) -> Result; + /// Execute ERC20.balanceOf(address) to read balance of address from ERC20 + /// contract + fn balance_of(context: Context, address: EvmAddress) -> Result; + /// Execute ERC20.transfer(address, uint256) to transfer value to `to` + fn transfer(context: Context, to: EvmAddress, value: Balance) -> DispatchResult; + // /// Get the real origin account and charge storage rent from the origin. + // fn get_origin() -> Option; + // /// Set the EVM origin + // fn set_origin(origin: AccountId); + // /// Kill the EVM origin + // fn kill_origin(); + // /// Push new EVM origin in xcm + // fn push_xcm_origin(origin: AccountId); + // /// Pop EVM origin in xcm + // fn pop_xcm_origin(); + // /// Kill the EVM origin in xcm + // fn kill_xcm_origin(); + // /// Get the real origin account or xcm origin and charge storage rent from the origin. + // fn get_real_or_xcm_origin() -> Option; +} diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index dbfc951b..c49b11bf 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -1,3 +1,4 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod currency; +pub mod evm; diff --git a/runtime/brooklyn/Cargo.toml b/runtime/brooklyn/Cargo.toml index 9ef9b285..12c38cfc 100644 --- a/runtime/brooklyn/Cargo.toml +++ b/runtime/brooklyn/Cargo.toml @@ -154,6 +154,7 @@ vault-registry-rpc-runtime-api.workspace = true # Dex pallet-currencies.workspace = true pallet-dex.workspace = true +pallet-erc20.workspace = true [build-dependencies] substrate-wasm-builder.workspace = true @@ -290,6 +291,7 @@ std = [ #Dex "pallet-currencies/std", "pallet-dex/std", + "pallet-erc20/std", ] aura = [] allowlist = [] From a32f76be33f488fd75250883a787adac6281984b Mon Sep 17 00:00:00 2001 From: Li Smith Date: Thu, 16 May 2024 20:24:20 +0800 Subject: [PATCH 04/27] impl erc-20 transfer --- Cargo.lock | 2 ++ pallet/erc-20/Cargo.toml | 5 +++- pallet/erc-20/src/lib.rs | 52 ++++++++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eababd95..68d61118 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8728,9 +8728,11 @@ dependencies = [ "frame-system", "ggx-primitives", "hex", + "hex-literal 0.3.4", "impl-trait-for-tuples", "num_enum 0.5.11", "pallet-balances", + "pallet-evm", "pallet-timestamp", "parity-scale-codec", "scale-info", diff --git a/pallet/erc-20/Cargo.toml b/pallet/erc-20/Cargo.toml index 713c3d31..d7daef35 100644 --- a/pallet/erc-20/Cargo.toml +++ b/pallet/erc-20/Cargo.toml @@ -9,6 +9,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ethereum-types = { workspace = true } +hex-literal = { workspace = true } impl-trait-for-tuples = { workspace = true } num_enum = { workspace = true } @@ -21,8 +22,9 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } sp-io = { workspace = true } -ggx-primitives = { workspace = true } astar-primitives = { workspace = true } +ggx-primitives = { workspace = true } +pallet-evm = { workspace = true } [dev-dependencies] serde_json = { workspace = true, features = ["std"] } @@ -39,6 +41,7 @@ std = [ "frame-system/std", "num_enum/std", "ggx-primitives/std", + "pallet-evm/std", "scale-codec/std", "scale-info/std", "sp-core/std", diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 09554baf..8ef8a346 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -34,7 +34,9 @@ use frame_system::pallet_prelude::*; // }; use frame_support::{sp_runtime::traits::AccountIdConversion, traits::Currency}; use ggx_primitives::evm::{EVMBridgeTrait, EvmAddress}; +use hex_literal::hex; use num_enum::{IntoPrimitive, TryFromPrimitive}; +use pallet_evm::AddressMapping; use sp_core::{H160, H256, U256}; use sp_runtime::{ArithmeticError, DispatchError, SaturatedConversion}; use sp_std::{vec, vec::Vec}; @@ -63,7 +65,6 @@ pub type BalanceOf = // TotalSupply = "totalSupply()", // BalanceOf = "balanceOf(address)", // Transfer = "transfer(address,uint256)", -// Liquidate = "liquidate(address,address,uint256,uint256)", // OnCollateralTransfer = "onCollateralTransfer(address,uint256)", // OnRepaymentRefund = "onRepaymentRefund(address,uint256)", // } @@ -80,6 +81,7 @@ pub mod module { /// EvmBridge module trait #[pallet::config] pub trait Config: frame_system::Config { + //+ pallet_evm::Config //type EVM: EVM>; /// The currency mechanism. //todo need replace to EVM> @@ -260,12 +262,7 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { } // Calls the transfer method on an ERC20 contract using the given context. - fn transfer( - context: Context, - source: AccountIdOf, - to: H160, - value: BalanceOf, - ) -> DispatchResult { + fn transfer(context: Context, to: H160, value: BalanceOf) -> DispatchResult { // // ERC20.transfer method hash // let mut input = Into::::into(Action::Transfer).to_be_bytes().to_vec(); // // append receiver address @@ -301,6 +298,47 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { // !info.value.is_empty() && info.value == bytes, // Error::::InvalidReturnValue // ); + + // ############# + // @dev Transfer token for a specified address + // @custom:selector a9059cbb + // @param to The address to transfer to. + // @param value The amount to be transferred. + // function transfer(address to, uint256 value) external returns (bool); + + let context = Context { + source_vm_id: VmId::Wasm, + weight_limit: Weight::from_parts(1_000_000, 1_000_000), + }; + + const TRANSFER_SELECTOR: [u8; 4] = hex!["6057361d"]; + // ERC20.transfer method hash + let mut input = TRANSFER_SELECTOR.to_vec(); + // append receiver address + input.extend_from_slice(H256::from(to).as_bytes()); + // append amount to be transferred + input.extend_from_slice( + H256::from_uint(&U256::from(value.saturated_into::())).as_bytes(), + ); + + let gas = 200_000; + let storage_limit = 960; + + let call_result = T::XvmCallApi::call( + context, + VmId::Evm, + ::PalletId::get().into_account_truncating(), + to.as_bytes().to_vec(), + input, + value.saturated_into::(), + Some(storage_limit), + ); + + let used_weight = match &call_result { + Ok(s) => s.used_weight, + Err(f) => f.used_weight, + }; + Ok(()) } } From ac656e72077273d08bb9654bc541ffedd109f1a9 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Fri, 17 May 2024 23:29:38 +0800 Subject: [PATCH 05/27] intergrate erc20 transfer to currencies module --- Cargo.lock | 3 + pallet/currencies/Cargo.toml | 5 + pallet/currencies/src/lib.rs | 325 ++++++++--------------------- runtime/brooklyn/Cargo.toml | 3 + runtime/brooklyn/src/currencies.rs | 28 +++ runtime/brooklyn/src/erc20.rs | 13 ++ runtime/brooklyn/src/lib.rs | 5 + 7 files changed, 147 insertions(+), 235 deletions(-) create mode 100644 runtime/brooklyn/src/currencies.rs create mode 100644 runtime/brooklyn/src/erc20.rs diff --git a/Cargo.lock b/Cargo.lock index 68d61118..7da282e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4821,6 +4821,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", + "ggx-primitives", "ibc 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "ibc-proto 0.25.0 (git+https://github.com/octopus-network/ibc-proto-rs?branch=ibc)", "interbtc-primitives", @@ -8634,8 +8635,10 @@ dependencies = [ name = "pallet-currencies" version = "0.4.1-dev" dependencies = [ + "astar-primitives", "frame-support", "frame-system", + "ggx-primitives", "orml-tokens", "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "orml-utilities 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", diff --git a/pallet/currencies/Cargo.toml b/pallet/currencies/Cargo.toml index 25d3895f..0bc4c8f4 100644 --- a/pallet/currencies/Cargo.toml +++ b/pallet/currencies/Cargo.toml @@ -21,6 +21,9 @@ sp-std = { workspace = true } orml-traits = { workspace = true } orml-utilities = { workspace = true } +astar-primitives = { workspace = true } +ggx-primitives = { workspace = true } + [dev-dependencies] pallet-balances = { workspace = true } sp-core = { workspace = true } @@ -30,9 +33,11 @@ orml-tokens = { workspace = true } [features] default = ["std"] std = [ + "astar-primitives/std", "serde", "frame-support/std", "frame-system/std", + "ggx-primitives/std", "orml-traits/std", "orml-utilities/std", "scale-codec/std", diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 6a970afa..18a5016d 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -57,8 +57,7 @@ use orml_traits::{ currency::TransferAll, BalanceStatus, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, BasicReservableCurrency, LockIdentifier, MultiCurrency, MultiCurrencyExtended, - MultiLockableCurrency, MultiReservableCurrency, NamedBasicReservableCurrency, - NamedMultiReservableCurrency, + MultiLockableCurrency, MultiReservableCurrency, NamedMultiReservableCurrency, }; use orml_utilities::with_transaction_result; use scale_codec::Codec; @@ -68,6 +67,15 @@ use sp_runtime::{ }; use sp_std::{fmt::Debug, marker, result}; +use astar_primitives::{ + ethereum_checked::AccountMapping, + xvm::{Context, VmId}, +}; +use ggx_primitives::{ + currency::CurrencyId, + evm::{EVMBridgeTrait, EvmAddress}, +}; + mod mock; mod tests; mod weights; @@ -82,9 +90,6 @@ pub mod module { pub(crate) type BalanceOf = <::MultiCurrency as MultiCurrency< ::AccountId, >>::Balance; - pub(crate) type CurrencyIdOf = <::MultiCurrency as MultiCurrency< - ::AccountId, - >>::CurrencyId; pub(crate) type AmountOf = <::MultiCurrency as MultiCurrencyExtended< ::AccountId, >>::Amount; @@ -96,19 +101,12 @@ pub mod module { #[pallet::config] pub trait Config: frame_system::Config { type MultiCurrency: TransferAll - + MultiCurrencyExtended - + MultiLockableCurrency - + MultiReservableCurrency + + MultiCurrencyExtended + + MultiLockableCurrency + + MultiReservableCurrency + NamedMultiReservableCurrency - + fungibles::Inspect< - Self::AccountId, - AssetId = CurrencyIdOf, - Balance = BalanceOf, - > + fungibles::Mutate< - Self::AccountId, - AssetId = CurrencyIdOf, - Balance = BalanceOf, - >; + + fungibles::Inspect> + + fungibles::Mutate>; type NativeCurrency: BasicCurrencyExtended< Self::AccountId, @@ -116,18 +114,22 @@ pub mod module { Amount = AmountOf, > + BasicLockableCurrency> + BasicReservableCurrency> - + NamedBasicReservableCurrency< - Self::AccountId, - ReserveIdentifierOf, - Balance = BalanceOf, - > + fungible::Inspect> + + fungible::Inspect> + fungible::Mutate>; #[pallet::constant] - type GetNativeCurrencyId: Get>; + type GetNativeCurrencyId: Get; /// Weight information for extrinsics in this module. type WeightInfo: WeightInfo; + + /// Used as temporary account for ERC20 token `withdraw` and `deposit`. + // #[pallet::constant] + // type Erc20HoldingAccount: Get; + + /// Mapping from address to account id. + type AddressMapping: AccountMapping; + type EVMBridge: EVMBridgeTrait>; } #[pallet::error] @@ -136,10 +138,44 @@ pub mod module { AmountIntoBalanceFailed, /// Balance is too low. BalanceTooLow, + /// Erc20 invalid operation + Erc20InvalidOperation, + /// EVM account not found + EvmAccountNotFound, /// Deposit result is not expected DepositFailed, } + // #[pallet::event] + // #[pallet::generate_deposit(pub(super) fn deposit_event)] + // pub enum Event { + // /// Currency transfer success. + // Transferred { + // currency_id: CurrencyId, + // from: T::AccountId, + // to: T::AccountId, + // amount: BalanceOf, + // }, + // /// Withdrawn some balances from an account + // Withdrawn { + // currency_id: CurrencyId, + // who: T::AccountId, + // amount: BalanceOf, + // }, + // /// Deposited some balance into an account + // Deposited { + // currency_id: CurrencyId, + // who: T::AccountId, + // amount: BalanceOf, + // }, + // /// Dust swept. + // DustSwept { + // currency_id: CurrencyId, + // who: T::AccountId, + // amount: BalanceOf, + // }, + // } + #[pallet::pallet] pub struct Pallet(_); @@ -157,7 +193,7 @@ pub mod module { pub fn transfer( origin: OriginFor, dest: ::Source, - currency_id: CurrencyIdOf, + currency_id: CurrencyId, #[pallet::compact] amount: BalanceOf, ) -> DispatchResult { let from = ensure_signed(origin)?; @@ -189,7 +225,7 @@ pub mod module { pub fn update_balance( origin: OriginFor, who: ::Source, - currency_id: CurrencyIdOf, + currency_id: CurrencyId, amount: AmountOf, ) -> DispatchResult { ensure_root(origin)?; @@ -204,14 +240,14 @@ pub mod module { } impl MultiCurrency for Pallet { - type CurrencyId = CurrencyIdOf; + type CurrencyId = CurrencyId; type Balance = BalanceOf; fn minimum_balance(currency_id: Self::CurrencyId) -> Self::Balance { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::minimum_balance() - } else { - T::MultiCurrency::minimum_balance(currency_id) + match currency_id { + CurrencyId::Erc20(_) => Zero::zero(), + id if id == T::GetNativeCurrencyId::get() => T::NativeCurrency::minimum_balance(), + _ => T::MultiCurrency::minimum_balance(currency_id), } } @@ -260,11 +296,26 @@ impl MultiCurrency for Pallet { if amount.is_zero() || from == to { return Ok(()); } - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::transfer(from, to, amount) - } else { - T::MultiCurrency::transfer(currency_id, from, to, amount) + match currency_id { + CurrencyId::Erc20(contract) => { + let sender = T::AddressMapping::into_h160(from.clone()); + let address = T::AddressMapping::into_h160(to.clone()); + T::EVMBridge::transfer( + Context { + source_vm_id: VmId::Wasm, + weight_limit: Weight::from_parts(1_000_000, 1_000_000), + }, + address, + amount, + )?; + } + id if id == T::GetNativeCurrencyId::get() => { + T::NativeCurrency::transfer(from, to, amount)? + } + _ => T::MultiCurrency::transfer(currency_id, from, to, amount)?, } + + Ok(()) } fn deposit( @@ -448,86 +499,9 @@ impl MultiReservableCurrency for Pallet { } } -impl NamedMultiReservableCurrency for Pallet { - type ReserveIdentifier = ReserveIdentifierOf; - - fn slash_reserved_named( - id: &Self::ReserveIdentifier, - currency_id: Self::CurrencyId, - who: &T::AccountId, - value: Self::Balance, - ) -> Self::Balance { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::slash_reserved_named(id, who, value) - } else { - T::MultiCurrency::slash_reserved_named(id, currency_id, who, value) - } - } - - fn reserved_balance_named( - id: &Self::ReserveIdentifier, - currency_id: Self::CurrencyId, - who: &T::AccountId, - ) -> Self::Balance { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::reserved_balance_named(id, who) - } else { - T::MultiCurrency::reserved_balance_named(id, currency_id, who) - } - } - - fn reserve_named( - id: &Self::ReserveIdentifier, - currency_id: Self::CurrencyId, - who: &T::AccountId, - value: Self::Balance, - ) -> DispatchResult { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::reserve_named(id, who, value) - } else { - T::MultiCurrency::reserve_named(id, currency_id, who, value) - } - } - - fn unreserve_named( - id: &Self::ReserveIdentifier, - currency_id: Self::CurrencyId, - who: &T::AccountId, - value: Self::Balance, - ) -> Self::Balance { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::unreserve_named(id, who, value) - } else { - T::MultiCurrency::unreserve_named(id, currency_id, who, value) - } - } - - fn repatriate_reserved_named( - id: &Self::ReserveIdentifier, - currency_id: Self::CurrencyId, - slashed: &T::AccountId, - beneficiary: &T::AccountId, - value: Self::Balance, - status: BalanceStatus, - ) -> result::Result { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::repatriate_reserved_named(id, slashed, beneficiary, value, status) - } else { - T::MultiCurrency::repatriate_reserved_named( - id, - currency_id, - slashed, - beneficiary, - value, - status, - ) - } - } -} - /// impl fungiles for Pallet impl fungibles::Inspect for Pallet { - type AssetId = CurrencyIdOf; + type AssetId = CurrencyId; type Balance = BalanceOf; fn total_issuance(asset_id: Self::AssetId) -> Self::Balance { @@ -723,7 +697,7 @@ pub struct Currency(marker::PhantomData, marker::PhantomDat impl BasicCurrency for Currency where T: Config, - GetCurrencyId: Get>, + GetCurrencyId: Get, { type Balance = BalanceOf; @@ -771,7 +745,7 @@ where impl BasicCurrencyExtended for Currency where T: Config, - GetCurrencyId: Get>, + GetCurrencyId: Get, { type Amount = AmountOf; @@ -787,7 +761,7 @@ where impl BasicLockableCurrency for Currency where T: Config, - GetCurrencyId: Get>, + GetCurrencyId: Get, { type Moment = BlockNumberFor; @@ -829,7 +803,7 @@ where impl BasicReservableCurrency for Currency where T: Config, - GetCurrencyId: Get>, + GetCurrencyId: Get, { fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { as MultiReservableCurrency>::can_reserve( @@ -886,77 +860,6 @@ where } } -impl NamedBasicReservableCurrency> - for Currency -where - T: Config, - GetCurrencyId: Get>, -{ - fn slash_reserved_named( - id: &ReserveIdentifierOf, - who: &T::AccountId, - value: Self::Balance, - ) -> Self::Balance { - as NamedMultiReservableCurrency>::slash_reserved_named( - id, - GetCurrencyId::get(), - who, - value, - ) - } - - fn reserved_balance_named(id: &ReserveIdentifierOf, who: &T::AccountId) -> Self::Balance { - as NamedMultiReservableCurrency>::reserved_balance_named( - id, - GetCurrencyId::get(), - who, - ) - } - - fn reserve_named( - id: &ReserveIdentifierOf, - who: &T::AccountId, - value: Self::Balance, - ) -> DispatchResult { - as NamedMultiReservableCurrency>::reserve_named( - id, - GetCurrencyId::get(), - who, - value, - ) - } - - fn unreserve_named( - id: &ReserveIdentifierOf, - who: &T::AccountId, - value: Self::Balance, - ) -> Self::Balance { - as NamedMultiReservableCurrency>::unreserve_named( - id, - GetCurrencyId::get(), - who, - value, - ) - } - - fn repatriate_reserved_named( - id: &ReserveIdentifierOf, - slashed: &T::AccountId, - beneficiary: &T::AccountId, - value: Self::Balance, - status: BalanceStatus, - ) -> result::Result { - as NamedMultiReservableCurrency>::repatriate_reserved_named( - id, - GetCurrencyId::get(), - slashed, - beneficiary, - value, - status, - ) - } -} - pub type NativeCurrencyOf = Currency::GetNativeCurrencyId>; /// Adapt other currency traits implementation to `BasicCurrency`. @@ -1131,54 +1034,6 @@ where } } -// Adapt `frame_support::traits::NamedReservableCurrency` -impl - NamedBasicReservableCurrency - for BasicCurrencyAdapter -where - Currency: PalletNamedReservableCurrency, - T: Config, -{ - fn slash_reserved_named( - id: &ReserveIdentifier, - who: &AccountId, - value: Self::Balance, - ) -> Self::Balance { - let (_, gap) = Currency::slash_reserved_named(id, who, value); - gap - } - - fn reserved_balance_named(id: &ReserveIdentifier, who: &AccountId) -> Self::Balance { - Currency::reserved_balance_named(id, who) - } - - fn reserve_named( - id: &ReserveIdentifier, - who: &AccountId, - value: Self::Balance, - ) -> DispatchResult { - Currency::reserve_named(id, who, value) - } - - fn unreserve_named( - id: &ReserveIdentifier, - who: &AccountId, - value: Self::Balance, - ) -> Self::Balance { - Currency::unreserve_named(id, who, value) - } - - fn repatriate_reserved_named( - id: &ReserveIdentifier, - slashed: &AccountId, - beneficiary: &AccountId, - value: Self::Balance, - status: BalanceStatus, - ) -> result::Result { - Currency::repatriate_reserved_named(id, slashed, beneficiary, value, status) - } -} - /// impl fungile for Currency type FungibleBalanceOf = >::Balance; impl fungible::Inspect diff --git a/runtime/brooklyn/Cargo.toml b/runtime/brooklyn/Cargo.toml index 12c38cfc..a4989b8c 100644 --- a/runtime/brooklyn/Cargo.toml +++ b/runtime/brooklyn/Cargo.toml @@ -156,6 +156,8 @@ pallet-currencies.workspace = true pallet-dex.workspace = true pallet-erc20.workspace = true +ggx-primitives.workspace = true + [build-dependencies] substrate-wasm-builder.workspace = true @@ -292,6 +294,7 @@ std = [ "pallet-currencies/std", "pallet-dex/std", "pallet-erc20/std", + "ggx-primitives/std", ] aura = [] allowlist = [] diff --git a/runtime/brooklyn/src/currencies.rs b/runtime/brooklyn/src/currencies.rs new file mode 100644 index 00000000..2ff191ee --- /dev/null +++ b/runtime/brooklyn/src/currencies.rs @@ -0,0 +1,28 @@ +use crate::{prelude::*, Assets, BlakeTwo256, BlockNumber, Erc20, Tokens, H160}; + +use ggx_primitives::currency::{CurrencyId, TokenSymbol}; +use pallet_currencies::BasicCurrencyAdapter; +pub type Amount = i128; + +///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +parameter_types! { + pub const NativeCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::GGX); +} + +impl pallet_currencies::Config for Runtime { + type MultiCurrency = Tokens; + type NativeCurrency = BasicCurrencyAdapter; + type GetNativeCurrencyId = NativeCurrencyId; + type WeightInfo = (); + //type Erc20HoldingAccount = ; + type AddressMapping = HashedAccountMapping; + type EVMBridge = pallet_erc20::EVMBridge; +} diff --git a/runtime/brooklyn/src/erc20.rs b/runtime/brooklyn/src/erc20.rs new file mode 100644 index 00000000..87c4487b --- /dev/null +++ b/runtime/brooklyn/src/erc20.rs @@ -0,0 +1,13 @@ +use frame_support::PalletId; + +use crate::{prelude::*, Assets, BlockNumber, Xvm}; + +parameter_types! { + pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); +} + +impl pallet_erc20::Config for Runtime { + type Currency = Balances; + type PalletId = ERC20PalletId; + type XvmCallApi = Xvm; +} diff --git a/runtime/brooklyn/src/lib.rs b/runtime/brooklyn/src/lib.rs index edcd9705..c18497e8 100644 --- a/runtime/brooklyn/src/lib.rs +++ b/runtime/brooklyn/src/lib.rs @@ -16,8 +16,10 @@ pub const CALL_PARAMS_MAX_SIZE: usize = 304; pub mod btcbridge; mod chain_extensions; +pub mod currencies; pub mod dex; mod dex_chain_extensions; +pub mod erc20; pub mod ethereum; pub mod governance; mod ibc; @@ -670,6 +672,9 @@ construct_runtime!( // Dex Dex: pallet_dex, + + Erc20: pallet_erc20, + //GGXCurrencies: currencies, } ); From f48da713124a398b83aa359f42e3eeb8658c5d4c Mon Sep 17 00:00:00 2001 From: Li Smith Date: Mon, 20 May 2024 17:59:54 +0800 Subject: [PATCH 06/27] add ggx-tokens --- Cargo.lock | 23 +- Cargo.toml | 1 + node/Cargo.toml | 3 + node/src/runtime/testnet.rs | 14 + pallet/erc-20/Cargo.toml | 7 +- pallet/ggx-tokens/Cargo.toml | 49 + pallet/ggx-tokens/src/imbalances.rs | 178 + pallet/ggx-tokens/src/impls.rs | 378 +++ pallet/ggx-tokens/src/lib.rs | 2880 +++++++++++++++++ pallet/ggx-tokens/src/weights.rs | 66 + runtime/brooklyn/Cargo.toml | 4 +- runtime/brooklyn/src/btcbridge.rs | 2 +- runtime/brooklyn/src/currencies.rs | 29 +- runtime/brooklyn/src/lib.rs | 2 +- runtime/runtime-common/Cargo.toml | 6 + runtime/runtime-common/src/weights/mod.rs | 1 + .../src/weights/pallet_ggx_tokens.rs | 164 + 17 files changed, 3798 insertions(+), 9 deletions(-) create mode 100644 pallet/ggx-tokens/Cargo.toml create mode 100644 pallet/ggx-tokens/src/imbalances.rs create mode 100644 pallet/ggx-tokens/src/impls.rs create mode 100644 pallet/ggx-tokens/src/lib.rs create mode 100644 pallet/ggx-tokens/src/weights.rs create mode 100644 runtime/runtime-common/src/weights/pallet_ggx_tokens.rs diff --git a/Cargo.lock b/Cargo.lock index 7da282e8..93370d37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4723,6 +4723,7 @@ dependencies = [ "frame-benchmarking-cli", "frame-system", "futures 0.3.30", + "ggx-primitives", "ggxchain-runtime-brooklyn", "ggxchain-runtime-sydney", "hex", @@ -4858,6 +4859,7 @@ dependencies = [ "pallet-ethereum-checked", "pallet-evm", "pallet-evm-chain-id", + "pallet-ggx-tokens", "pallet-grandpa", "pallet-hotfix-sufficients", "pallet-ibc", @@ -8723,7 +8725,7 @@ dependencies = [ [[package]] name = "pallet-erc20" -version = "2.25.0" +version = "0.0.1" dependencies = [ "astar-primitives", "ethereum-types 0.14.1", @@ -9094,6 +9096,24 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", ] +[[package]] +name = "pallet-ggx-tokens" +version = "0.4.1-dev" +dependencies = [ + "frame-support", + "frame-system", + "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", + "pallet-treasury", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic 6.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", + "sp-core 7.0.0", + "sp-io 7.0.0", + "sp-runtime 7.0.0", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", +] + [[package]] name = "pallet-grandpa" version = "4.0.0-dev" @@ -11464,6 +11484,7 @@ dependencies = [ "pallet-evm-precompile-substrate-ecdsa", "pallet-evm-precompile-xvm", "pallet-evm-precompile-zk-groth16-verify", + "pallet-ggx-tokens", "pallet-receipt-registry", "pallet-scheduler", "pallet-session", diff --git a/Cargo.toml b/Cargo.toml index a6be3b73..6578b1b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -305,6 +305,7 @@ vault-registry-rpc-runtime-api = { git = "https://github.com/ggxchain/interbtc.g pallet-currencies = { path = "pallet/currencies", default-features = false } pallet-erc20 = { path = "pallet/erc-20", default-features = false } pallet-dex = { path = "pallet/dex", default-features = false } +pallet-ggx-tokens = { path = "pallet/ggx-tokens", default-features = false } # Supress warnings from the peerset in logs during syncing # The polkadot did the same in the next release. See: diff --git a/node/Cargo.toml b/node/Cargo.toml index e8934ba7..84afebf6 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -100,6 +100,9 @@ replace-rpc.workspace = true reward-rpc.workspace = true vault-registry-rpc.workspace = true +# dex +ggx-primitives.workspace = true + [dev-dependencies] alloy-rlp = { workspace = true } assert_cmd = { workspace = true } diff --git a/node/src/runtime/testnet.rs b/node/src/runtime/testnet.rs index 2b5d34b5..ca3e216d 100644 --- a/node/src/runtime/testnet.rs +++ b/node/src/runtime/testnet.rs @@ -299,6 +299,20 @@ pub fn testnet_genesis( .flat_map(|k| vec![(k.clone().0, Token(GGXT), 1 << 70)]) .collect(), }, + ggx_tokens: GGXTokensConfig { + balances: endowed_accounts + .iter() + .flat_map(|k| { + vec![( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), + 1u128 << 70, + )] + }) + .collect(), + }, oracle: OracleConfig { authorized_oracles: endowed_accounts .iter() diff --git a/pallet/erc-20/Cargo.toml b/pallet/erc-20/Cargo.toml index d7daef35..26add119 100644 --- a/pallet/erc-20/Cargo.toml +++ b/pallet/erc-20/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "pallet-erc20" -version = "2.25.0" -authors = ["Acala Developers"] -edition = "2021" +version = "0.0.1" +edition.workspace = true +authors.workspace = true +repository.workspace = true [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/pallet/ggx-tokens/Cargo.toml b/pallet/ggx-tokens/Cargo.toml new file mode 100644 index 00000000..62771ace --- /dev/null +++ b/pallet/ggx-tokens/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "pallet-ggx-tokens" +description = "Fungible tokens module that implements `MultiCurrency` trait." +license = "Apache-2.0" +version = "0.4.1-dev" +edition.workspace = true +authors.workspace = true +repository.workspace = true + +[dependencies] +scale-codec = { workspace = true, features = ["max-encoded-len"] } +scale-info = { workspace = true, features = ["derive"] } +serde = { workspace = true, optional = true } + +frame-support.workspace = true +frame-system.workspace = true +sp-arithmetic.workspace = true +sp-runtime.workspace = true +sp-std.workspace = true + +orml-traits.workspace = true + +[dev-dependencies] +pallet-treasury.workspace = true +sp-core.workspace = true +sp-io.workspace = true + +[features] +default = ["std"] +std = [ + "serde", + + "frame-support/std", + "frame-system/std", + "orml-traits/std", + "scale-codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] \ No newline at end of file diff --git a/pallet/ggx-tokens/src/imbalances.rs b/pallet/ggx-tokens/src/imbalances.rs new file mode 100644 index 00000000..636b8490 --- /dev/null +++ b/pallet/ggx-tokens/src/imbalances.rs @@ -0,0 +1,178 @@ +// wrapping these imbalances in a private module is necessary to ensure absolute +// privacy of the inner member. +use crate::{Config, TotalIssuance}; +use frame_support::traits::{Get, Imbalance, SameOrOther, TryDrop}; +use sp_runtime::traits::{Saturating, Zero}; +use sp_std::{marker, mem, result}; + +/// Opaque, move-only struct with private fields that serves as a token +/// denoting that funds have been created without any equal and opposite +/// accounting. +#[must_use] +pub struct PositiveImbalance>( + T::Balance, + marker::PhantomData, +); + +impl> PositiveImbalance { + /// Create a new positive imbalance from a balance. + pub fn new(amount: T::Balance) -> Self { + PositiveImbalance(amount, marker::PhantomData::) + } +} + +impl> Default for PositiveImbalance { + fn default() -> Self { + Self::zero() + } +} + +/// Opaque, move-only struct with private fields that serves as a token +/// denoting that funds have been destroyed without any equal and opposite +/// accounting. +#[must_use] +pub struct NegativeImbalance>( + T::Balance, + marker::PhantomData, +); + +impl> NegativeImbalance { + /// Create a new negative imbalance from a balance. + pub fn new(amount: T::Balance) -> Self { + NegativeImbalance(amount, marker::PhantomData::) + } +} + +impl> Default for NegativeImbalance { + fn default() -> Self { + Self::zero() + } +} + +impl> TryDrop for PositiveImbalance { + fn try_drop(self) -> result::Result<(), Self> { + self.drop_zero() + } +} + +impl> Imbalance + for PositiveImbalance +{ + type Opposite = NegativeImbalance; + + fn zero() -> Self { + Self::new(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0.saturating_sub(first); + + mem::forget(self); + (Self::new(first), Self::new(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + // allow to make the impl same with `pallet-balances` + #[allow(clippy::comparison_chain)] + fn offset(self, other: Self::Opposite) -> SameOrOther { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a > b { + SameOrOther::Same(Self::new(a.saturating_sub(b))) + } else if b > a { + SameOrOther::Other(NegativeImbalance::new(b.saturating_sub(a))) + } else { + SameOrOther::None + } + } + fn peek(&self) -> T::Balance { + self.0 + } +} + +impl> TryDrop for NegativeImbalance { + fn try_drop(self) -> result::Result<(), Self> { + self.drop_zero() + } +} + +impl> Imbalance + for NegativeImbalance +{ + type Opposite = PositiveImbalance; + + fn zero() -> Self { + Self::new(Zero::zero()) + } + fn drop_zero(self) -> result::Result<(), Self> { + if self.0.is_zero() { + Ok(()) + } else { + Err(self) + } + } + fn split(self, amount: T::Balance) -> (Self, Self) { + let first = self.0.min(amount); + let second = self.0.saturating_sub(first); + + mem::forget(self); + (Self::new(first), Self::new(second)) + } + fn merge(mut self, other: Self) -> Self { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + + self + } + fn subsume(&mut self, other: Self) { + self.0 = self.0.saturating_add(other.0); + mem::forget(other); + } + // allow to make the impl same with `pallet-balances` + #[allow(clippy::comparison_chain)] + fn offset(self, other: Self::Opposite) -> SameOrOther { + let (a, b) = (self.0, other.0); + mem::forget((self, other)); + + if a > b { + SameOrOther::Same(Self::new(a.saturating_sub(b))) + } else if b > a { + SameOrOther::Other(PositiveImbalance::new(b.saturating_sub(a))) + } else { + SameOrOther::None + } + } + fn peek(&self) -> T::Balance { + self.0 + } +} + +impl> Drop for PositiveImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + TotalIssuance::::mutate(GetCurrencyId::get(), |v| *v = v.saturating_add(self.0)); + } +} + +impl> Drop for NegativeImbalance { + /// Basic drop handler will just square up the total issuance. + fn drop(&mut self) { + TotalIssuance::::mutate(GetCurrencyId::get(), |v| *v = v.saturating_sub(self.0)); + } +} diff --git a/pallet/ggx-tokens/src/impls.rs b/pallet/ggx-tokens/src/impls.rs new file mode 100644 index 00000000..d2a86951 --- /dev/null +++ b/pallet/ggx-tokens/src/impls.rs @@ -0,0 +1,378 @@ +use frame_support::{ + dispatch::DispatchError, + traits::{ + fungible, fungibles, + tokens::{ + Balance as BalanceT, DepositConsequence, Fortitude, Precision, Preservation, + Provenance, WithdrawConsequence, + }, + Contains, Get, + }, +}; +use sp_arithmetic::{traits::Bounded, ArithmeticError}; + +pub struct Combiner( + sp_std::marker::PhantomData<(AccountId, TestKey, A, B)>, +); + +impl fungibles::Inspect for Combiner +where + TestKey: Contains<>::AssetId>, + A: fungible::Inspect>::Balance>, + B: fungibles::Inspect, +{ + type AssetId = >::AssetId; + type Balance = >::Balance; + + fn total_issuance(asset: Self::AssetId) -> Self::Balance { + if TestKey::contains(&asset) { + A::total_issuance() + } else { + B::total_issuance(asset) + } + } + + fn minimum_balance(asset: Self::AssetId) -> Self::Balance { + if TestKey::contains(&asset) { + A::minimum_balance() + } else { + B::minimum_balance(asset) + } + } + + fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + if TestKey::contains(&asset) { + A::balance(who) + } else { + B::balance(asset, who) + } + } + + fn total_balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance { + if TestKey::contains(&asset) { + A::total_balance(who) + } else { + B::total_balance(asset, who) + } + } + + fn reducible_balance( + asset: Self::AssetId, + who: &AccountId, + preservation: Preservation, + fortitude: Fortitude, + ) -> Self::Balance { + if TestKey::contains(&asset) { + A::reducible_balance(who, preservation, fortitude) + } else { + B::reducible_balance(asset, who, preservation, fortitude) + } + } + + fn can_deposit( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + if TestKey::contains(&asset) { + A::can_deposit(who, amount, provenance) + } else { + B::can_deposit(asset, who, amount, provenance) + } + } + + fn can_withdraw( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + if TestKey::contains(&asset) { + A::can_withdraw(who, amount) + } else { + B::can_withdraw(asset, who, amount) + } + } + + fn asset_exists(asset: Self::AssetId) -> bool { + if TestKey::contains(&asset) { + true + } else { + B::asset_exists(asset) + } + } +} + +impl fungibles::Mutate for Combiner +where + TestKey: Contains<>::AssetId>, + A: fungible::Mutate>::Balance>, + B: fungibles::Mutate, +{ + fn mint_into( + asset: Self::AssetId, + dest: &AccountId, + amount: Self::Balance, + ) -> Result { + if TestKey::contains(&asset) { + A::mint_into(dest, amount) + } else { + B::mint_into(asset, dest, amount) + } + } + + fn burn_from( + asset: Self::AssetId, + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + fortitude: Fortitude, + ) -> Result { + if TestKey::contains(&asset) { + A::burn_from(dest, amount, precision, fortitude) + } else { + B::burn_from(asset, dest, amount, precision, fortitude) + } + } + + fn transfer( + asset: Self::AssetId, + source: &AccountId, + dest: &AccountId, + amount: Self::Balance, + preservation: Preservation, + ) -> Result { + if TestKey::contains(&asset) { + A::transfer(source, dest, amount, preservation) + } else { + B::transfer(asset, source, dest, amount, preservation) + } + } +} + +impl fungibles::Unbalanced + for Combiner +where + TestKey: Contains<>::AssetId>, + A: fungible::Mutate>::Balance>, + B: fungibles::Mutate, +{ + fn handle_dust(_dust: fungibles::Dust) { + // FIXME: only way to access internals of Dust is into_credit, but T is + // not balanced + } + + fn write_balance( + asset: Self::AssetId, + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + if TestKey::contains(&asset) { + A::write_balance(who, amount) + } else { + B::write_balance(asset, who, amount) + } + } + + fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) { + if TestKey::contains(&asset) { + A::set_total_issuance(amount) + } else { + B::set_total_issuance(asset, amount) + } + } +} + +pub trait ConvertBalance { + type AssetId; + fn convert_balance(amount: A, asset_id: Self::AssetId) -> Result; + fn convert_balance_back(amount: B, asset_id: Self::AssetId) -> Result; + + fn convert_balance_saturated(amount: A, asset_id: Self::AssetId) -> B { + Self::convert_balance(amount, asset_id).unwrap_or_else(|e| match e { + ArithmeticError::Overflow => B::max_value(), + ArithmeticError::Underflow => B::min_value(), + ArithmeticError::DivisionByZero => B::max_value(), + }) + } + fn convert_balance_back_saturated(amount: B, asset_id: Self::AssetId) -> A { + Self::convert_balance_back(amount, asset_id).unwrap_or_else(|e| match e { + ArithmeticError::Overflow => A::max_value(), + ArithmeticError::Underflow => A::min_value(), + ArithmeticError::DivisionByZero => A::max_value(), + }) + } +} + +pub struct Mapper( + sp_std::marker::PhantomData<(AccountId, T, C, B, GetCurrencyId)>, +); +impl fungible::Inspect + for Mapper +where + T: fungibles::Inspect, + C: ConvertBalance< + >::Balance, + B, + AssetId = >::AssetId, + >, + B: BalanceT, + GetCurrencyId: Get<>::AssetId>, +{ + type Balance = B; + + fn total_issuance() -> Self::Balance { + C::convert_balance_saturated( + T::total_issuance(GetCurrencyId::get()), + GetCurrencyId::get(), + ) + } + + fn minimum_balance() -> Self::Balance { + C::convert_balance_saturated( + T::minimum_balance(GetCurrencyId::get()), + GetCurrencyId::get(), + ) + } + + fn balance(who: &AccountId) -> Self::Balance { + C::convert_balance_saturated(T::balance(GetCurrencyId::get(), who), GetCurrencyId::get()) + } + + fn total_balance(who: &AccountId) -> Self::Balance { + C::convert_balance_saturated( + T::total_balance(GetCurrencyId::get(), who), + GetCurrencyId::get(), + ) + } + + fn reducible_balance( + who: &AccountId, + preservation: Preservation, + fortitude: Fortitude, + ) -> Self::Balance { + C::convert_balance_saturated( + T::reducible_balance(GetCurrencyId::get(), who, preservation, fortitude), + GetCurrencyId::get(), + ) + } + + fn can_deposit( + who: &AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + let amount = C::convert_balance_back(amount, GetCurrencyId::get()); + let amount = match amount { + Ok(amount) => amount, + Err(_) => return DepositConsequence::Overflow, + }; + T::can_deposit(GetCurrencyId::get(), who, amount, provenance) + } + + fn can_withdraw(who: &AccountId, amount: Self::Balance) -> WithdrawConsequence { + use WithdrawConsequence::*; + + let amount = C::convert_balance_back(amount, GetCurrencyId::get()); + let amount = match amount { + Ok(amount) => amount, + Err(ArithmeticError::Overflow) => return Overflow, + Err(ArithmeticError::Underflow) => return Underflow, + Err(ArithmeticError::DivisionByZero) => return Overflow, + }; + + let res = T::can_withdraw(GetCurrencyId::get(), who, amount); + match res { + WithdrawConsequence::ReducedToZero(b) => WithdrawConsequence::ReducedToZero( + C::convert_balance_saturated(b, GetCurrencyId::get()), + ), + BalanceLow => BalanceLow, + WouldDie => WouldDie, + UnknownAsset => UnknownAsset, + Underflow => Underflow, + Overflow => Overflow, + Frozen => Frozen, + Success => Success, + } + } +} + +impl fungible::Mutate + for Mapper +where + T: fungibles::Mutate, + C: ConvertBalance< + >::Balance, + B, + AssetId = >::AssetId, + >, + B: BalanceT, + GetCurrencyId: Get<>::AssetId>, +{ + fn mint_into(dest: &AccountId, amount: Self::Balance) -> Result { + T::mint_into( + GetCurrencyId::get(), + dest, + C::convert_balance_back(amount, GetCurrencyId::get())?, + ) + } + + fn burn_from( + dest: &AccountId, + amount: Self::Balance, + precision: Precision, + fortitude: Fortitude, + ) -> Result { + T::burn_from( + GetCurrencyId::get(), + dest, + C::convert_balance_back(amount, GetCurrencyId::get())?, + precision, + fortitude, + ) + } + + fn transfer( + source: &AccountId, + dest: &AccountId, + amount: B, + preservation: Preservation, + ) -> Result { + T::transfer( + GetCurrencyId::get(), + source, + dest, + C::convert_balance_back(amount, GetCurrencyId::get())?, + preservation, + ) + } +} + +impl fungible::Unbalanced + for Mapper +where + T: fungibles::Unbalanced, + C: ConvertBalance< + >::Balance, + B, + AssetId = >::AssetId, + >, + B: BalanceT, + GetCurrencyId: Get<>::AssetId>, +{ + fn handle_dust(_dust: fungible::Dust) { + // FIXME: only way to access internals of Dust is into_credit, but T is + // not balanced + } + + fn write_balance( + who: &AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + T::write_balance(GetCurrencyId::get(), who, amount) + } + + fn set_total_issuance(amount: Self::Balance) { + T::set_total_issuance(GetCurrencyId::get(), amount) + } +} diff --git a/pallet/ggx-tokens/src/lib.rs b/pallet/ggx-tokens/src/lib.rs new file mode 100644 index 00000000..c0b9b3a4 --- /dev/null +++ b/pallet/ggx-tokens/src/lib.rs @@ -0,0 +1,2880 @@ +//! # Tokens Module +//! +//! ## Overview +//! +//! The tokens module provides fungible multi-currency functionality that +//! implements `MultiCurrency` trait. +//! +//! The tokens module provides functions for: +//! +//! - Querying and setting the balance of a given account. +//! - Getting and managing total issuance. +//! - Balance transfer between accounts. +//! - Depositing and withdrawing balance. +//! - Slashing an account balance. +//! +//! ### Implementations +//! +//! The tokens module provides implementations for following traits. +//! +//! - `MultiCurrency` - Abstraction over a fungible multi-currency system. +//! - `MultiCurrencyExtended` - Extended `MultiCurrency` with additional helper +//! types and methods, like updating balance +//! by a given signed integer amount. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! - `transfer` - Transfer some balance to another account. +//! - `transfer_all` - Transfer all balance to another account. +//! +//! ### Genesis Config +//! +//! The tokens module depends on the `GenesisConfig`. Endowed accounts could be +//! configured in genesis configs. + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::unused_unit)] +#![allow(clippy::comparison_chain)] + +pub use crate::imbalances::{NegativeImbalance, PositiveImbalance}; + +use frame_support::{ + ensure, log, + pallet_prelude::*, + traits::{ + tokens::{ + fungible, fungibles, DepositConsequence, Fortitude, Precision, Preservation, + Provenance, Restriction, WithdrawConsequence, + }, + BalanceStatus as Status, Contains, Currency as PalletCurrency, DefensiveSaturating, + ExistenceRequirement, Get, Imbalance, LockableCurrency as PalletLockableCurrency, + NamedReservableCurrency as PalletNamedReservableCurrency, + ReservableCurrency as PalletReservableCurrency, SignedImbalance, WithdrawReasons, + }, + transactional, BoundedVec, +}; +use frame_system::{ensure_signed, pallet_prelude::*}; +use scale_codec::MaxEncodedLen; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{ + AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Member, + Saturating, StaticLookup, Zero, + }, + ArithmeticError, DispatchError, DispatchResult, FixedPointOperand, RuntimeDebug, TokenError, +}; +use sp_std::{cmp, convert::Infallible, marker, prelude::*, vec::Vec}; + +use orml_traits::{ + arithmetic::{self, Signed}, + currency::{MutationHooks, OnDeposit, OnDust, OnSlash, OnTransfer, TransferAll}, + BalanceStatus, GetByKey, Happened, LockIdentifier, MultiCurrency, MultiCurrencyExtended, + MultiLockableCurrency, MultiReservableCurrency, NamedMultiReservableCurrency, +}; + +mod imbalances; +mod impls; +// mod mock; +// mod tests; +// mod tests_currency_adapter; +// mod tests_events; +// mod tests_fungibles; +// mod tests_multicurrency; + +mod weights; + +pub use impls::*; +pub use weights::WeightInfo; + +pub struct TransferDust(marker::PhantomData<(T, GetAccountId)>); +impl OnDust + for TransferDust +where + T: Config, + GetAccountId: Get, +{ + fn on_dust(who: &T::AccountId, currency_id: T::CurrencyId, amount: T::Balance) { + // transfer the dust to treasury account, ignore the result, + // if failed will leave some dust which still could be recycled. + let _ = Pallet::::do_transfer( + currency_id, + who, + &GetAccountId::get(), + amount, + ExistenceRequirement::AllowDeath, + ); + } +} + +pub struct BurnDust(marker::PhantomData); +impl OnDust for BurnDust { + fn on_dust(who: &T::AccountId, currency_id: T::CurrencyId, amount: T::Balance) { + // burn the dust, ignore the result, + // if failed will leave some dust which still could be recycled. + let _ = Pallet::::do_withdraw( + currency_id, + who, + amount, + ExistenceRequirement::AllowDeath, + true, + ); + } +} + +/// A single lock on a balance. There can be many of these on an account and +/// they "overlap", so the same balance is frozen by multiple locks. +#[derive(Encode, Decode, Clone, PartialEq, Eq, MaxEncodedLen, RuntimeDebug, TypeInfo)] +pub struct BalanceLock { + /// An identifier for this lock. Only one lock may be in existence for + /// each identifier. + pub id: LockIdentifier, + /// The amount which the free balance may not drop below when this lock + /// is in effect. + pub amount: Balance, +} + +/// Store named reserved balance. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct ReserveData { + /// The identifier for the named reserve. + pub id: ReserveIdentifier, + /// The amount of the named reserve. + pub amount: Balance, +} + +/// balance information for an account. +#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, MaxEncodedLen, RuntimeDebug, TypeInfo)] +pub struct AccountData { + /// Non-reserved part of the balance. There may still be restrictions on + /// this, but it is the total pool what may in principle be transferred, + /// reserved. + /// + /// This is the only balance that matters in terms of most operations on + /// tokens. + pub free: Balance, + /// Balance which is reserved and may not be used at all. + /// + /// This can still get slashed, but gets slashed last of all. + /// + /// This balance is a 'reserve' balance that other subsystems use in + /// order to set aside tokens that are still 'owned' by the account + /// holder, but which are suspendable. + pub reserved: Balance, + /// The amount that `free` may not drop below when withdrawing. + pub frozen: Balance, +} + +impl AccountData { + /// The amount that this account's free balance may not be reduced + /// beyond. + pub(crate) fn frozen(&self) -> Balance { + self.frozen + } + /// The total balance in this account including any that is reserved and + /// ignoring any frozen. + fn total(&self) -> Balance { + self.free.saturating_add(self.reserved) + } +} + +pub use module::*; + +#[frame_support::pallet] +pub mod module { + use orml_traits::currency::MutationHooks; + + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The balance type + type Balance: Parameter + + Member + + AtLeast32BitUnsigned + + Default + + Copy + + MaybeSerializeDeserialize + + MaxEncodedLen + + FixedPointOperand; + + /// The amount type, should be signed version of `Balance` + type Amount: Signed + + TryInto + + TryFrom + + Parameter + + Member + + arithmetic::SimpleArithmetic + + Default + + Copy + + MaybeSerializeDeserialize + + MaxEncodedLen; + + /// The currency ID type + type CurrencyId: Parameter + + Member + + Copy + + MaybeSerializeDeserialize + + Ord + + TypeInfo + + MaxEncodedLen; + + /// Weight information for extrinsics in this module. + type WeightInfo: WeightInfo; + + /// The minimum amount required to keep an account. + /// It's deprecated to config 0 as ED for any currency_id, + /// zero ED will retain account even if its total is zero. + /// Since accounts of orml_tokens are also used as providers of + /// System::AccountInfo, zero ED may cause some problems. + type ExistentialDeposits: GetByKey; + + /// Hooks are actions that are executed on certain events. + /// For example: OnDust, OnNewTokenAccount + type CurrencyHooks: MutationHooks; + + #[pallet::constant] + type MaxLocks: Get; + + /// The maximum number of named reserves that can exist on an account. + #[pallet::constant] + type MaxReserves: Get; + + /// The id type for named reserves. + type ReserveIdentifier: Parameter + Member + MaxEncodedLen + Ord + Copy; + + // The whitelist of accounts that will not be reaped even if its total + // is zero or below ED. + type DustRemovalWhitelist: Contains; + } + + #[pallet::error] + pub enum Error { + /// The balance is too low + BalanceTooLow, + /// Cannot convert Amount into Balance type + AmountIntoBalanceFailed, + /// Failed because liquidity restrictions due to locking + LiquidityRestrictions, + /// Failed because the maximum locks was exceeded + MaxLocksExceeded, + /// Transfer/payment would kill account + KeepAlive, + /// Value too low to create account due to existential deposit + ExistentialDeposit, + /// Beneficiary account must pre-exist + DeadAccount, + // Number of named reserves exceed `T::MaxReserves` + TooManyReserves, + } + + #[pallet::event] + #[pallet::generate_deposit(pub(crate) fn deposit_event)] + pub enum Event { + /// An account was created with some free balance. + Endowed { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// An account was removed whose balance was non-zero but below + /// ExistentialDeposit, resulting in an outright loss. + DustLost { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Transfer succeeded. + Transfer { + currency_id: T::CurrencyId, + from: T::AccountId, + to: T::AccountId, + amount: T::Balance, + }, + /// Some balance was reserved (moved from free to reserved). + Reserved { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some balance was unreserved (moved from reserved to free). + Unreserved { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some reserved balance was repatriated (moved from reserved to + /// another account). + ReserveRepatriated { + currency_id: T::CurrencyId, + from: T::AccountId, + to: T::AccountId, + amount: T::Balance, + status: BalanceStatus, + }, + /// A balance was set by root. + BalanceSet { + currency_id: T::CurrencyId, + who: T::AccountId, + free: T::Balance, + reserved: T::Balance, + }, + /// The total issuance of an currency has been set + TotalIssuanceSet { + currency_id: T::CurrencyId, + amount: T::Balance, + }, + /// Some balances were withdrawn (e.g. pay for transaction fee) + Withdrawn { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some balances were slashed (e.g. due to mis-behavior) + Slashed { + currency_id: T::CurrencyId, + who: T::AccountId, + free_amount: T::Balance, + reserved_amount: T::Balance, + }, + /// Deposited some balance into an account + Deposited { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some funds are locked + LockSet { + lock_id: LockIdentifier, + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some locked funds were unlocked + LockRemoved { + lock_id: LockIdentifier, + currency_id: T::CurrencyId, + who: T::AccountId, + }, + /// Some free balance was locked. + Locked { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + /// Some locked balance was freed. + Unlocked { + currency_id: T::CurrencyId, + who: T::AccountId, + amount: T::Balance, + }, + } + + /// The total issuance of a token type. + #[pallet::storage] + #[pallet::getter(fn total_issuance)] + pub type TotalIssuance = + StorageMap<_, Twox64Concat, T::CurrencyId, T::Balance, ValueQuery>; + + /// Any liquidity locks of a token type under an account. + /// NOTE: Should only be accessed when setting, changing and freeing a lock. + #[pallet::storage] + #[pallet::getter(fn locks)] + pub type Locks = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Twox64Concat, + T::CurrencyId, + BoundedVec, T::MaxLocks>, + ValueQuery, + >; + + /// The balance of a token type under an account. + /// + /// NOTE: If the total is ever zero, decrease account ref account. + /// + /// NOTE: This is only used in the case that this module is used to store + /// balances. + #[pallet::storage] + #[pallet::getter(fn accounts)] + pub type Accounts = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Twox64Concat, + T::CurrencyId, + AccountData, + ValueQuery, + >; + + /// Named reserves on some account balances. + #[pallet::storage] + #[pallet::getter(fn reserves)] + pub type Reserves = StorageDoubleMap< + _, + Blake2_128Concat, + T::AccountId, + Twox64Concat, + T::CurrencyId, + BoundedVec, T::MaxReserves>, + ValueQuery, + >; + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub balances: Vec<(T::AccountId, T::CurrencyId, T::Balance)>, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { balances: vec![] } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + // ensure no duplicates exist. + let unique_endowed_accounts = self + .balances + .iter() + .map(|(account_id, currency_id, _)| (account_id, currency_id)) + .collect::>(); + assert!( + unique_endowed_accounts.len() == self.balances.len(), + "duplicate endowed accounts in genesis." + ); + + self.balances + .iter() + .for_each(|(account_id, currency_id, initial_balance)| { + assert!( + *initial_balance >= T::ExistentialDeposits::get(currency_id), + "the balance of any account should always be more than existential deposit.", + ); + Pallet::::mutate_account(account_id, *currency_id, |account_data, _| { + account_data.free = *initial_balance + }); + TotalIssuance::::mutate(*currency_id, |total_issuance| { + *total_issuance = total_issuance + .checked_add(initial_balance) + .expect("total issuance cannot overflow when building genesis") + }); + }); + } + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::hooks] + impl Hooks for Pallet {} + + #[pallet::call] + impl Pallet { + /// Transfer some liquid free balance to another account. + /// + /// `transfer` will set the `FreeBalance` of the sender and receiver. + /// It will decrease the total issuance of the system by the + /// `TransferFee`. If the sender's account is below the existential + /// deposit as a result of the transfer, the account will be reaped. + /// + /// The dispatch origin for this call must be `Signed` by the + /// transactor. + /// + /// - `dest`: The recipient of the transfer. + /// - `currency_id`: currency type. + /// - `amount`: free balance amount to tranfer. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::transfer())] + pub fn transfer( + origin: OriginFor, + dest: ::Source, + currency_id: T::CurrencyId, + #[pallet::compact] amount: T::Balance, + ) -> DispatchResult { + let from = ensure_signed(origin)?; + let to = T::Lookup::lookup(dest)?; + Self::do_transfer( + currency_id, + &from, + &to, + amount, + ExistenceRequirement::AllowDeath, + ) + } + + /// Transfer all remaining balance to the given account. + /// + /// NOTE: This function only attempts to transfer _transferable_ + /// balances. This means that any locked, reserved, or existential + /// deposits (when `keep_alive` is `true`), will not be transferred by + /// this function. To ensure that this function results in a killed + /// account, you might need to prepare the account by removing any + /// reference counters, storage deposits, etc... + /// + /// The dispatch origin for this call must be `Signed` by the + /// transactor. + /// + /// - `dest`: The recipient of the transfer. + /// - `currency_id`: currency type. + /// - `keep_alive`: A boolean to determine if the `transfer_all` + /// operation should send all of the funds the account has, causing + /// the sender account to be killed (false), or transfer everything + /// except at least the existential deposit, which will guarantee to + /// keep the sender account alive (true). + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::transfer_all())] + pub fn transfer_all( + origin: OriginFor, + dest: ::Source, + currency_id: T::CurrencyId, + keep_alive: bool, + ) -> DispatchResult { + let from = ensure_signed(origin)?; + let to = T::Lookup::lookup(dest)?; + let preservation = if keep_alive { + Preservation::Protect + } else { + Preservation::Expendable + }; + let reducible_balance = >::reducible_balance( + currency_id, + &from, + preservation, + Fortitude::Polite, + ); + >::transfer( + currency_id, + &from, + &to, + reducible_balance, + preservation, + ) + .map(|_| ()) + } + + /// Same as the [`transfer`] call, but with a check that the transfer + /// will not kill the origin account. + /// + /// 99% of the time you want [`transfer`] instead. + /// + /// The dispatch origin for this call must be `Signed` by the + /// transactor. + /// + /// - `dest`: The recipient of the transfer. + /// - `currency_id`: currency type. + /// - `amount`: free balance amount to tranfer. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::transfer_keep_alive())] + pub fn transfer_keep_alive( + origin: OriginFor, + dest: ::Source, + currency_id: T::CurrencyId, + #[pallet::compact] amount: T::Balance, + ) -> DispatchResultWithPostInfo { + let from = ensure_signed(origin)?; + let to = T::Lookup::lookup(dest)?; + Self::do_transfer( + currency_id, + &from, + &to, + amount, + ExistenceRequirement::KeepAlive, + )?; + Ok(().into()) + } + + /// Exactly as `transfer`, except the origin must be root and the source + /// account may be specified. + /// + /// The dispatch origin for this call must be _Root_. + /// + /// - `source`: The sender of the transfer. + /// - `dest`: The recipient of the transfer. + /// - `currency_id`: currency type. + /// - `amount`: free balance amount to tranfer. + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::force_transfer())] + pub fn force_transfer( + origin: OriginFor, + source: ::Source, + dest: ::Source, + currency_id: T::CurrencyId, + #[pallet::compact] amount: T::Balance, + ) -> DispatchResult { + ensure_root(origin)?; + let from = T::Lookup::lookup(source)?; + let to = T::Lookup::lookup(dest)?; + Self::do_transfer( + currency_id, + &from, + &to, + amount, + ExistenceRequirement::AllowDeath, + ) + } + + /// Set the balances of a given account. + /// + /// This will alter `FreeBalance` and `ReservedBalance` in storage. it + /// will also decrease the total issuance of the system + /// (`TotalIssuance`). If the new free or reserved balance is below the + /// existential deposit, it will reap the `AccountInfo`. + /// + /// The dispatch origin for this call is `root`. + #[pallet::call_index(4)] + #[pallet::weight(T::WeightInfo::set_balance())] + pub fn set_balance( + origin: OriginFor, + who: ::Source, + currency_id: T::CurrencyId, + #[pallet::compact] new_free: T::Balance, + #[pallet::compact] new_reserved: T::Balance, + ) -> DispatchResult { + ensure_root(origin)?; + let who = T::Lookup::lookup(who)?; + + Self::try_mutate_account(&who, currency_id, |account, _| -> DispatchResult { + let mut new_total = new_free + .checked_add(&new_reserved) + .ok_or(ArithmeticError::Overflow)?; + let (new_free, new_reserved) = + if new_total < T::ExistentialDeposits::get(¤cy_id) { + new_total = Zero::zero(); + (Zero::zero(), Zero::zero()) + } else { + (new_free, new_reserved) + }; + let old_total = account.total(); + + account.free = new_free; + account.reserved = new_reserved; + + if new_total > old_total { + TotalIssuance::::try_mutate(currency_id, |t| -> DispatchResult { + *t = t + .checked_add(&(new_total.defensive_saturating_sub(old_total))) + .ok_or(ArithmeticError::Overflow)?; + Ok(()) + })?; + } else if new_total < old_total { + TotalIssuance::::try_mutate(currency_id, |t| -> DispatchResult { + *t = t + .checked_sub(&(old_total.defensive_saturating_sub(new_total))) + .ok_or(ArithmeticError::Underflow)?; + Ok(()) + })?; + } + + Self::deposit_event(Event::BalanceSet { + currency_id, + who: who.clone(), + free: new_free, + reserved: new_reserved, + }); + Ok(()) + })?; + + Ok(()) + } + } +} + +impl Pallet { + pub(crate) fn deposit_consequence( + _who: &T::AccountId, + currency_id: T::CurrencyId, + amount: T::Balance, + account: &AccountData, + ) -> DepositConsequence { + if amount.is_zero() { + return DepositConsequence::Success; + } + + if TotalIssuance::::get(currency_id) + .checked_add(&amount) + .is_none() + { + return DepositConsequence::Overflow; + } + + let new_total_balance = match account.total().checked_add(&amount) { + Some(x) => x, + None => return DepositConsequence::Overflow, + }; + + if new_total_balance < T::ExistentialDeposits::get(¤cy_id) { + return DepositConsequence::BelowMinimum; + } + + // NOTE: We assume that we are a provider, so don't need to do any checks in the + // case of account creation. + + DepositConsequence::Success + } + + pub(crate) fn withdraw_consequence( + who: &T::AccountId, + currency_id: T::CurrencyId, + amount: T::Balance, + account: &AccountData, + ) -> WithdrawConsequence { + if amount.is_zero() { + return WithdrawConsequence::Success; + } + + if TotalIssuance::::get(currency_id) + .checked_sub(&amount) + .is_none() + { + return WithdrawConsequence::Underflow; + } + + let new_total_balance = match account.total().checked_sub(&amount) { + Some(x) => x, + None => return WithdrawConsequence::BalanceLow, + }; + + // Provider restriction - total account balance cannot be reduced to zero if it + // cannot sustain the loss of a provider reference. + // NOTE: This assumes that the pallet is a provider (which is true). Is this + // ever changes, then this will need to adapt accordingly. + let ed = T::ExistentialDeposits::get(¤cy_id); + let success = if new_total_balance < ed { + if frame_system::Pallet::::can_dec_provider(who) { + WithdrawConsequence::ReducedToZero(new_total_balance) + } else { + return WithdrawConsequence::WouldDie; + } + } else { + WithdrawConsequence::Success + }; + + // Enough free funds to have them be reduced. + let new_free_balance = match account.free.checked_sub(&amount) { + Some(b) => b, + None => return WithdrawConsequence::BalanceLow, + }; + + // Eventual free funds must be no less than the frozen balance. + if new_free_balance < account.frozen() { + return WithdrawConsequence::Frozen; + } + + success + } + + // Ensure that an account can withdraw from their free balance given any + // existing withdrawal restrictions like locks and vesting balance. + // Is a no-op if amount to be withdrawn is zero. + pub(crate) fn ensure_can_withdraw( + currency_id: T::CurrencyId, + who: &T::AccountId, + amount: T::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + + let new_balance = Self::free_balance(currency_id, who) + .checked_sub(&amount) + .ok_or(Error::::BalanceTooLow)?; + ensure!( + new_balance >= Self::accounts(who, currency_id).frozen(), + Error::::LiquidityRestrictions + ); + Ok(()) + } + + pub(crate) fn try_mutate_account( + who: &T::AccountId, + currency_id: T::CurrencyId, + f: impl FnOnce(&mut AccountData, bool) -> sp_std::result::Result, + ) -> sp_std::result::Result<(R, Option), E> { + Accounts::::try_mutate_exists(who, currency_id, |maybe_account| { + let existed = maybe_account.is_some(); + let mut account = maybe_account.take().unwrap_or_default(); + f(&mut account, existed).map(move |result| { + let maybe_endowed = if !existed { Some(account.free) } else { None }; + let mut maybe_dust: Option = None; + let total = account.total(); + *maybe_account = if total < T::ExistentialDeposits::get(¤cy_id) { + // if ED is not zero, but account total is zero, account will be reaped + if total.is_zero() { + None + } else { + if !T::DustRemovalWhitelist::contains(who) { + maybe_dust = Some(total); + } + Some(account) + } + } else { + // Note: if ED is zero, account will never be reaped + Some(account) + }; + + (maybe_endowed, existed, maybe_account.is_some(), maybe_dust, result) + }) + }) + .map(|(maybe_endowed, existed, exists, maybe_dust, result)| { + if existed && !exists { + // If existed before, decrease account provider. + // Ignore the result, because if it failed then there are remaining consumers, + // and the account storage in frame_system shouldn't be reaped. + let _ = frame_system::Pallet::::dec_providers(who); + >::OnKilledTokenAccount::happened(&(who.clone(), currency_id)); + } else if !existed && exists { + // if new, increase account provider + frame_system::Pallet::::inc_providers(who); + >::OnNewTokenAccount::happened(&(who.clone(), currency_id)); + } + + if let Some(endowed) = maybe_endowed { + Self::deposit_event(Event::Endowed { + currency_id, + who: who.clone(), + amount: endowed, + }); + } + + if let Some(dust_amount) = maybe_dust { + // `OnDust` maybe get/set storage `Accounts` of `who`, trigger handler here + // to avoid some unexpected errors. + >::OnDust::on_dust(who, currency_id, dust_amount); + + Self::deposit_event(Event::DustLost { + currency_id, + who: who.clone(), + amount: dust_amount, + }); + } + + (result, maybe_dust) + }) + } + + pub(crate) fn mutate_account( + who: &T::AccountId, + currency_id: T::CurrencyId, + f: impl FnOnce(&mut AccountData, bool) -> R, + ) -> (R, Option) { + Self::try_mutate_account( + who, + currency_id, + |account, existed| -> Result { Ok(f(account, existed)) }, + ) + .expect("Error is infallible; qed") + } + + /// Set free balance of `who` to a new value. + /// + /// Note: this will not maintain total issuance, and the caller is expected + /// to do it. If it will cause the account to be removed dust, shouldn't use + /// it, because maybe the account that should be reaped to remain due to + /// failed transfer/withdraw dust. + pub(crate) fn set_free_balance( + currency_id: T::CurrencyId, + who: &T::AccountId, + amount: T::Balance, + ) { + Self::mutate_account(who, currency_id, |account, _| { + account.free = amount; + + Self::deposit_event(Event::BalanceSet { + currency_id, + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); + }); + } + + /// Set reserved balance of `who` to a new value. + /// + /// Note: this will not maintain total issuance, and the caller is expected + /// to do it. If it will cause the account to be removed dust, shouldn't use + /// it, because maybe the account that should be reaped to remain due to + /// failed transfer/withdraw dust. + pub(crate) fn set_reserved_balance( + currency_id: T::CurrencyId, + who: &T::AccountId, + amount: T::Balance, + ) { + Self::mutate_account(who, currency_id, |account, _| { + account.reserved = amount; + + Self::deposit_event(Event::BalanceSet { + currency_id, + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); + }); + } + + /// Update the account entry for `who` under `currency_id`, given the + /// locks. + pub(crate) fn update_locks( + currency_id: T::CurrencyId, + who: &T::AccountId, + locks: &[BalanceLock], + ) -> DispatchResult { + // track lock delta + let mut total_frozen_prev = Zero::zero(); + let mut total_frozen_after = Zero::zero(); + + // update account data + Self::mutate_account(who, currency_id, |account, _| { + total_frozen_prev = account.frozen; + account.frozen = Zero::zero(); + for lock in locks.iter() { + account.frozen = account.frozen.max(lock.amount); + } + total_frozen_after = account.frozen; + }); + + // update locks + let existed = Locks::::contains_key(who, currency_id); + if locks.is_empty() { + Locks::::remove(who, currency_id); + if existed { + // decrease account ref count when destruct lock + frame_system::Pallet::::dec_consumers(who); + } + } else { + let bounded_locks: BoundedVec, T::MaxLocks> = locks + .to_vec() + .try_into() + .map_err(|_| Error::::MaxLocksExceeded)?; + Locks::::insert(who, currency_id, bounded_locks); + if !existed { + // increase account ref count when initialize lock + if frame_system::Pallet::::inc_consumers(who).is_err() { + // No providers for the locks. This is impossible under normal circumstances + // since the funds that are under the lock will themselves be stored in the + // account and therefore will need a reference. + log::warn!( + "Warning: Attempt to introduce lock consumer reference, yet no providers. \ + This is unexpected but should be safe." + ); + } + } + } + + if total_frozen_prev < total_frozen_after { + let amount = total_frozen_after.saturating_sub(total_frozen_prev); + Self::deposit_event(Event::Locked { + currency_id, + who: who.clone(), + amount, + }); + } else if total_frozen_prev > total_frozen_after { + let amount = total_frozen_prev.saturating_sub(total_frozen_after); + Self::deposit_event(Event::Unlocked { + currency_id, + who: who.clone(), + amount, + }); + } + + Ok(()) + } + + /// Transfer some free balance from `from` to `to`. Ensure from_account + /// allow death or new balance will not be reaped, and ensure + /// to_account will not be removed dust. + /// + /// Is a no-op if value to be transferred is zero or the `from` is the same + /// as `to`. + pub(crate) fn do_transfer( + currency_id: T::CurrencyId, + from: &T::AccountId, + to: &T::AccountId, + amount: T::Balance, + existence_requirement: ExistenceRequirement, + ) -> DispatchResult { + if amount.is_zero() || from == to { + return Ok(()); + } + + >::PreTransfer::on_transfer( + currency_id, + from, + to, + amount, + )?; + Self::try_mutate_account(to, currency_id, |to_account, _existed| -> DispatchResult { + Self::try_mutate_account( + from, + currency_id, + |from_account, _existed| -> DispatchResult { + from_account.free = from_account + .free + .checked_sub(&amount) + .ok_or(Error::::BalanceTooLow)?; + to_account.free = to_account + .free + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + + let ed = T::ExistentialDeposits::get(¤cy_id); + // if the total of `to_account` is below existential deposit, would return an + // error. + // Note: if `to_account` is in `T::DustRemovalWhitelist`, can bypass this check. + ensure!( + to_account.total() >= ed || T::DustRemovalWhitelist::contains(to), + Error::::ExistentialDeposit + ); + + Self::ensure_can_withdraw(currency_id, from, amount)?; + + let allow_death = existence_requirement == ExistenceRequirement::AllowDeath; + let allow_death = + allow_death && frame_system::Pallet::::can_dec_provider(from); + let would_be_dead = if from_account.total() < ed { + if from_account.total().is_zero() { + true + } else { + // Note: if account is not in `T::DustRemovalWhitelist`, account will eventually + // be reaped due to the dust removal. + !T::DustRemovalWhitelist::contains(from) + } + } else { + false + }; + + ensure!(allow_death || !would_be_dead, Error::::KeepAlive); + Ok(()) + }, + )?; + Ok(()) + })?; + + >::PostTransfer::on_transfer( + currency_id, + from, + to, + amount, + )?; + Self::deposit_event(Event::Transfer { + currency_id, + from: from.clone(), + to: to.clone(), + amount, + }); + Ok(()) + } + + /// Withdraw some free balance from an account, respecting existence + /// requirements. + /// + /// `change_total_issuance`: + /// - true, decrease the total issuance by burned amount. + /// - false, do not update the total issuance. + /// + /// Is a no-op if value to be withdrawn is zero. + pub(crate) fn do_withdraw( + currency_id: T::CurrencyId, + who: &T::AccountId, + amount: T::Balance, + existence_requirement: ExistenceRequirement, + change_total_issuance: bool, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + + Self::try_mutate_account(who, currency_id, |account, _existed| -> DispatchResult { + Self::ensure_can_withdraw(currency_id, who, amount)?; + let previous_total = account.total(); + account.free = account.free.defensive_saturating_sub(amount); + + let ed = T::ExistentialDeposits::get(¤cy_id); + let would_be_dead = if account.total() < ed { + if account.total().is_zero() { + true + } else { + // Note: if account is not in `T::DustRemovalWhitelist`, account will eventually + // be reaped due to the dust removal. + !T::DustRemovalWhitelist::contains(who) + } + } else { + false + }; + let would_kill = would_be_dead && (previous_total >= ed || !previous_total.is_zero()); + ensure!( + existence_requirement == ExistenceRequirement::AllowDeath || !would_kill, + Error::::KeepAlive + ); + + if change_total_issuance { + TotalIssuance::::mutate(currency_id, |v| { + *v = v.defensive_saturating_sub(amount) + }); + } + + Self::deposit_event(Event::Withdrawn { + currency_id, + who: who.clone(), + amount, + }); + Ok(()) + })?; + + Ok(()) + } + + /// Deposit some `value` into the free balance of `who`. + /// + /// `require_existed`: + /// - true, the account must already exist, do not require ED. + /// - false, possibly creating a new account, require ED if the account does + /// not yet exist, but except this account is in the dust removal + /// whitelist. + /// + /// `change_total_issuance`: + /// - true, increase the issued amount to total issuance. + /// - false, do not update the total issuance. + pub(crate) fn do_deposit( + currency_id: T::CurrencyId, + who: &T::AccountId, + amount: T::Balance, + require_existed: bool, + change_total_issuance: bool, + ) -> Result { + if amount.is_zero() { + return Ok(amount); + } + + >::PreDeposit::on_deposit( + currency_id, + who, + amount, + )?; + Self::try_mutate_account(who, currency_id, |account, existed| -> DispatchResult { + if require_existed { + ensure!(existed, Error::::DeadAccount); + } else { + let ed = T::ExistentialDeposits::get(¤cy_id); + // Note: if who is in dust removal whitelist, allow to deposit the amount that + // below ED to it. + ensure!( + amount >= ed || existed || T::DustRemovalWhitelist::contains(who), + Error::::ExistentialDeposit + ); + } + + let new_total_issuance = Self::total_issuance(currency_id) + .checked_add(&amount) + .ok_or(ArithmeticError::Overflow)?; + if change_total_issuance { + TotalIssuance::::mutate(currency_id, |v| *v = new_total_issuance); + } + account.free = account.free.defensive_saturating_add(amount); + Ok(()) + })?; + >::PostDeposit::on_deposit( + currency_id, + who, + amount, + )?; + Self::deposit_event(Event::Deposited { + currency_id, + who: who.clone(), + amount, + }); + Ok(amount) + } +} + +impl MultiCurrency for Pallet { + type CurrencyId = T::CurrencyId; + type Balance = T::Balance; + + fn minimum_balance(currency_id: Self::CurrencyId) -> Self::Balance { + T::ExistentialDeposits::get(¤cy_id) + } + + fn total_issuance(currency_id: Self::CurrencyId) -> Self::Balance { + Self::total_issuance(currency_id) + } + + fn total_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, currency_id).total() + } + + fn free_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, currency_id).free + } + + fn ensure_can_withdraw( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + Self::ensure_can_withdraw(currency_id, who, amount) + } + + fn transfer( + currency_id: Self::CurrencyId, + from: &T::AccountId, + to: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // allow death + Self::do_transfer( + currency_id, + from, + to, + amount, + ExistenceRequirement::AllowDeath, + ) + } + + fn deposit( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // do not require existing + Self::do_deposit(currency_id, who, amount, false, true)?; + Ok(()) + } + + fn withdraw( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // allow death + Self::do_withdraw( + currency_id, + who, + amount, + ExistenceRequirement::AllowDeath, + true, + ) + } + + // Check if `value` amount of free balance can be slashed from `who`. + fn can_slash(currency_id: Self::CurrencyId, who: &T::AccountId, value: Self::Balance) -> bool { + if value.is_zero() { + return true; + } + Self::free_balance(currency_id, who) >= value + } + + /// Is a no-op if `value` to be slashed is zero. + /// + /// NOTE: `slash()` prefers free balance, but assumes that reserve + /// balance can be drawn from in extreme circumstances. `can_slash()` + /// should be used prior to `slash()` to avoid having to draw from + /// reserved funds, however we err on the side of punishment if things + /// are inconsistent or `can_slash` wasn't used appropriately. + fn slash( + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Self::Balance { + if amount.is_zero() { + return amount; + } + + >::OnSlash::on_slash( + currency_id, + who, + amount, + ); + let account = Self::accounts(who, currency_id); + let free_slashed_amount = account.free.min(amount); + // Cannot underflow because free_slashed_amount can never be greater than amount + // but just to be defensive here. + let mut remaining_slash = amount.defensive_saturating_sub(free_slashed_amount); + + // slash free balance + if !free_slashed_amount.is_zero() { + // Cannot underflow becuase free_slashed_amount can never be greater than + // account.free but just to be defensive here. + Self::set_free_balance( + currency_id, + who, + account.free.defensive_saturating_sub(free_slashed_amount), + ); + } + + // slash reserved balance + let reserved_slashed_amount = account.reserved.min(remaining_slash); + + if !reserved_slashed_amount.is_zero() { + // Cannot underflow due to above line but just to be defensive here. + remaining_slash = remaining_slash.defensive_saturating_sub(reserved_slashed_amount); + Self::set_reserved_balance( + currency_id, + who, + account + .reserved + .defensive_saturating_sub(reserved_slashed_amount), + ); + } + + // Cannot underflow because the slashed value cannot be greater than total + // issuance but just to be defensive here. + TotalIssuance::::mutate(currency_id, |v| { + *v = v.defensive_saturating_sub(amount.defensive_saturating_sub(remaining_slash)) + }); + + Self::deposit_event(Event::Slashed { + currency_id, + who: who.clone(), + free_amount: free_slashed_amount, + reserved_amount: reserved_slashed_amount, + }); + remaining_slash + } +} + +impl MultiCurrencyExtended for Pallet { + type Amount = T::Amount; + + fn update_balance( + currency_id: Self::CurrencyId, + who: &T::AccountId, + by_amount: Self::Amount, + ) -> DispatchResult { + if by_amount.is_zero() { + return Ok(()); + } + + // Ensure this doesn't overflow. There isn't any traits that exposes + // `saturating_abs` so we need to do it manually. + let by_amount_abs = if by_amount == Self::Amount::min_value() { + Self::Amount::max_value() + } else { + by_amount.abs() + }; + + let by_balance = TryInto::::try_into(by_amount_abs) + .map_err(|_| Error::::AmountIntoBalanceFailed)?; + if by_amount.is_positive() { + Self::deposit(currency_id, who, by_balance) + } else { + Self::withdraw(currency_id, who, by_balance).map(|_| ()) + } + } +} + +impl MultiLockableCurrency for Pallet { + type Moment = T::BlockNumber; + + // Set a lock on the balance of `who` under `currency_id`. + // Is a no-op if lock amount is zero. + fn set_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + let mut new_lock = Some(BalanceLock { + id: lock_id, + amount, + }); + let mut locks = Self::locks(who, currency_id) + .into_iter() + .filter_map(|lock| { + if lock.id == lock_id { + new_lock.take() + } else { + Some(lock) + } + }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + Self::update_locks(currency_id, who, &locks[..])?; + + Self::deposit_event(Event::LockSet { + lock_id, + currency_id, + who: who.clone(), + amount, + }); + Ok(()) + } + + // Extend a lock on the balance of `who` under `currency_id`. + // Is a no-op if lock amount is zero + fn extend_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + if amount.is_zero() { + return Ok(()); + } + let mut new_lock = Some(BalanceLock { + id: lock_id, + amount, + }); + let mut locks = Self::locks(who, currency_id) + .into_iter() + .filter_map(|lock| { + if lock.id == lock_id { + new_lock.take().map(|nl| BalanceLock { + id: lock.id, + amount: lock.amount.max(nl.amount), + }) + } else { + Some(lock) + } + }) + .collect::>(); + if let Some(lock) = new_lock { + locks.push(lock) + } + Self::update_locks(currency_id, who, &locks[..]) + } + + fn remove_lock( + lock_id: LockIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + ) -> DispatchResult { + let mut locks = Self::locks(who, currency_id); + locks.retain(|lock| lock.id != lock_id); + let locks_vec = locks.to_vec(); + Self::update_locks(currency_id, who, &locks_vec[..])?; + + Self::deposit_event(Event::LockRemoved { + lock_id, + currency_id, + who: who.clone(), + }); + Ok(()) + } +} + +impl MultiReservableCurrency for Pallet { + /// Check if `who` can reserve `value` from their free balance. + /// + /// Always `true` if value to be reserved is zero. + fn can_reserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> bool { + if value.is_zero() { + return true; + } + Self::ensure_can_withdraw(currency_id, who, value).is_ok() + } + + /// Slash from reserved balance, returning any amount that was unable to + /// be slashed. + /// + /// Is a no-op if the value to be slashed is zero. + fn slash_reserved( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if value.is_zero() { + return value; + } + + >::OnSlash::on_slash( + currency_id, + who, + value, + ); + let reserved_balance = Self::reserved_balance(currency_id, who); + let actual = reserved_balance.min(value); + Self::mutate_account(who, currency_id, |account, _| { + // ensured reserved_balance >= actual but just to be defensive here. + account.reserved = reserved_balance.defensive_saturating_sub(actual); + }); + TotalIssuance::::mutate(currency_id, |v| *v = v.defensive_saturating_sub(actual)); + + Self::deposit_event(Event::Slashed { + currency_id, + who: who.clone(), + free_amount: Zero::zero(), + reserved_amount: actual, + }); + value.defensive_saturating_sub(actual) + } + + fn reserved_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, currency_id).reserved + } + + /// Move `value` from the free balance from `who` to their reserved + /// balance. + /// + /// Is a no-op if value to be reserved is zero. + fn reserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if value.is_zero() { + return Ok(()); + } + Self::ensure_can_withdraw(currency_id, who, value)?; + + Self::mutate_account(who, currency_id, |account, _| { + account.free = account.free.defensive_saturating_sub(value); + account.reserved = account.reserved.defensive_saturating_add(value); + + Self::deposit_event(Event::Reserved { + currency_id, + who: who.clone(), + amount: value, + }); + }); + + Ok(()) + } + + /// Unreserve some funds, returning any amount that was unable to be + /// unreserved. + /// + /// Is a no-op if the value to be unreserved is zero. + fn unreserve( + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if value.is_zero() { + return value; + } + + let (remaining, _) = Self::mutate_account(who, currency_id, |account, _| { + let actual = account.reserved.min(value); + account.reserved = account.reserved.defensive_saturating_sub(actual); + account.free = account.free.defensive_saturating_add(actual); + + Self::deposit_event(Event::Unreserved { + currency_id, + who: who.clone(), + amount: actual, + }); + value.defensive_saturating_sub(actual) + }); + + remaining + } + + /// Move the reserved balance of one account into the balance of + /// another, according to `status`. + /// + /// Is a no-op if: + /// - the value to be moved is zero; or + /// - the `slashed` id equal to `beneficiary` and the `status` is + /// `Reserved`. + fn repatriate_reserved( + currency_id: Self::CurrencyId, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: BalanceStatus, + ) -> sp_std::result::Result { + if value.is_zero() { + return Ok(value); + } + + if slashed == beneficiary { + return match status { + BalanceStatus::Free => Ok(Self::unreserve(currency_id, slashed, value)), + BalanceStatus::Reserved => { + Ok(value.saturating_sub(Self::reserved_balance(currency_id, slashed))) + } + }; + } + + let from_account = Self::accounts(slashed, currency_id); + let to_account = Self::accounts(beneficiary, currency_id); + let actual = from_account.reserved.min(value); + match status { + BalanceStatus::Free => { + Self::set_free_balance( + currency_id, + beneficiary, + to_account.free.defensive_saturating_add(actual), + ); + } + BalanceStatus::Reserved => { + Self::set_reserved_balance( + currency_id, + beneficiary, + to_account.reserved.defensive_saturating_add(actual), + ); + } + } + Self::set_reserved_balance( + currency_id, + slashed, + from_account.reserved.defensive_saturating_sub(actual), + ); + + Self::deposit_event(Event::::ReserveRepatriated { + currency_id, + from: slashed.clone(), + to: beneficiary.clone(), + amount: actual, + status, + }); + Ok(value.defensive_saturating_sub(actual)) + } +} + +impl NamedMultiReservableCurrency for Pallet { + type ReserveIdentifier = T::ReserveIdentifier; + + fn reserved_balance_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + ) -> Self::Balance { + let reserves = Self::reserves(who, currency_id); + reserves + .binary_search_by_key(id, |data| data.id) + .map(|index| reserves[index].amount) + .unwrap_or_default() + } + + /// Move `value` from the free balance from `who` to a named reserve + /// balance. + /// + /// Is a no-op if value to be reserved is zero. + fn reserve_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + if value.is_zero() { + return Ok(()); + } + + Reserves::::try_mutate(who, currency_id, |reserves| -> DispatchResult { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + // this add can't overflow but just to be defensive. + reserves[index].amount = reserves[index].amount.defensive_saturating_add(value); + } + Err(index) => { + reserves + .try_insert( + index, + ReserveData { + id: *id, + amount: value, + }, + ) + .map_err(|_| Error::::TooManyReserves)?; + } + }; + >::reserve(currency_id, who, value) + }) + } + + /// Unreserve some funds, returning any amount that was unable to be + /// unreserved. + /// + /// Is a no-op if the value to be unreserved is zero. + fn unreserve_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if value.is_zero() { + return Zero::zero(); + } + + Reserves::::mutate_exists(who, currency_id, |maybe_reserves| -> Self::Balance { + if let Some(reserves) = maybe_reserves.as_mut() { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let remain = >::unreserve( + currency_id, + who, + to_change, + ); + + // remain should always be zero but just to be defensive here. + let actual = to_change.defensive_saturating_sub(remain); + + // `actual <= to_change` and `to_change <= amount`, but just to be defensive + // here. + reserves[index].amount = + reserves[index].amount.defensive_saturating_sub(actual); + + if reserves[index].amount.is_zero() { + if reserves.len() == 1 { + // no more named reserves + *maybe_reserves = None; + } else { + // remove this named reserve + reserves.remove(index); + } + } + value.defensive_saturating_sub(actual) + } + Err(_) => value, + } + } else { + value + } + }) + } + + /// Slash from reserved balance, returning the amount that was unable to be + /// slashed. + /// + /// Is a no-op if the value to be slashed is zero. + fn slash_reserved_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + if value.is_zero() { + return Zero::zero(); + } + + Reserves::::mutate(who, currency_id, |reserves| -> Self::Balance { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let remain = >::slash_reserved( + currency_id, + who, + to_change, + ); + + // remain should always be zero but just to be defensive here. + let actual = to_change.defensive_saturating_sub(remain); + + // `actual <= to_change` and `to_change <= amount` but just to be defensive + // here. + reserves[index].amount = + reserves[index].amount.defensive_saturating_sub(actual); + + Self::deposit_event(Event::Slashed { + who: who.clone(), + currency_id, + free_amount: Zero::zero(), + reserved_amount: actual, + }); + value.defensive_saturating_sub(actual) + } + Err(_) => value, + } + }) + } + + /// Move the reserved balance of one account into the balance of another, + /// according to `status`. If `status` is `Reserved`, the balance will be + /// reserved with given `id`. + /// + /// Is a no-op if: + /// - the value to be moved is zero; or + /// - the `slashed` id equal to `beneficiary` and the `status` is + /// `Reserved`. + fn repatriate_reserved_named( + id: &Self::ReserveIdentifier, + currency_id: Self::CurrencyId, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: Status, + ) -> Result { + if value.is_zero() { + return Ok(Zero::zero()); + } + + if slashed == beneficiary { + return match status { + Status::Free => Ok(Self::unreserve_named(id, currency_id, slashed, value)), + Status::Reserved => Ok(value.saturating_sub(Self::reserved_balance_named( + id, + currency_id, + slashed, + ))), + }; + } + + Reserves::::try_mutate( + slashed, + currency_id, + |reserves| -> Result { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let to_change = cmp::min(reserves[index].amount, value); + + let actual = if status == Status::Reserved { + // make it the reserved under same identifier + Reserves::::try_mutate( + beneficiary, + currency_id, + |reserves| -> Result { + match reserves.binary_search_by_key(id, |data| data.id) { + Ok(index) => { + let remain = >::repatriate_reserved( + currency_id, + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive + // here. + let actual = to_change.defensive_saturating_sub(remain); + + // this add can't overflow but just to be defensive. + reserves[index].amount = reserves[index] + .amount + .defensive_saturating_add(actual); + + Ok(actual) + } + Err(index) => { + let remain = >::repatriate_reserved( + currency_id, + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive + // here + let actual = to_change.defensive_saturating_sub(remain); + + reserves + .try_insert( + index, + ReserveData { + id: *id, + amount: actual, + }, + ) + .map_err(|_| Error::::TooManyReserves)?; + + Ok(actual) + } + } + }, + )? + } else { + let remain = >::repatriate_reserved( + currency_id, + slashed, + beneficiary, + to_change, + status, + )?; + + // remain should always be zero but just to be defensive here + to_change.defensive_saturating_sub(remain) + }; + + // `actual <= to_change` and `to_change <= amount` but just to be defensive + // here. + reserves[index].amount = + reserves[index].amount.defensive_saturating_sub(actual); + Ok(value.defensive_saturating_sub(actual)) + } + Err(_) => Ok(value), + } + }, + ) + } +} + +impl fungibles::Inspect for Pallet { + type AssetId = T::CurrencyId; + type Balance = T::Balance; + + fn total_issuance(asset_id: Self::AssetId) -> Self::Balance { + Self::total_issuance(asset_id) + } + + fn minimum_balance(asset_id: Self::AssetId) -> Self::Balance { + T::ExistentialDeposits::get(&asset_id) + } + + fn balance(asset_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, asset_id).free + } + + fn total_balance(asset_id: Self::AssetId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, asset_id).total() + } + + fn reducible_balance( + asset_id: Self::AssetId, + who: &T::AccountId, + preservation: Preservation, + _force: Fortitude, + ) -> Self::Balance { + let a = Self::accounts(who, asset_id); + // Liquid balance is what is neither reserved nor locked/frozen. + let liquid = a.free.saturating_sub(a.frozen); + if frame_system::Pallet::::can_dec_provider(who) + && !matches!(preservation, Preservation::Protect) + { + liquid + } else { + // `must_remain_to_exist` is the part of liquid balance which must remain to + // keep total over ED. + let must_remain_to_exist = T::ExistentialDeposits::get(&asset_id) + .saturating_sub(a.total().saturating_sub(liquid)); + liquid.saturating_sub(must_remain_to_exist) + } + } + + fn can_deposit( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + _provenance: Provenance, + ) -> DepositConsequence { + Self::deposit_consequence(who, asset_id, amount, &Self::accounts(who, asset_id)) + } + + fn can_withdraw( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + Self::withdraw_consequence(who, asset_id, amount, &Self::accounts(who, asset_id)) + } + + fn asset_exists(asset: Self::AssetId) -> bool { + TotalIssuance::::contains_key(asset) + } +} + +impl fungibles::Mutate for Pallet { + fn mint_into( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Result { + Self::deposit_consequence(who, asset_id, amount, &Self::accounts(who, asset_id)) + .into_result()?; + // do not require existing + Self::do_deposit(asset_id, who, amount, false, true) + } + + fn burn_from( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + // TODO: Respect precision + _precision: Precision, + // TODO: Respect fortitude + _fortitude: Fortitude, + ) -> Result { + let extra = + Self::withdraw_consequence(who, asset_id, amount, &Self::accounts(who, asset_id)) + .into_result(false)?; + let actual = amount.defensive_saturating_add(extra); + // allow death + Self::do_withdraw( + asset_id, + who, + actual, + ExistenceRequirement::AllowDeath, + true, + ) + .map(|_| actual) + } + + fn transfer( + asset_id: Self::AssetId, + source: &T::AccountId, + dest: &T::AccountId, + amount: T::Balance, + preservation: Preservation, + ) -> Result { + let existence_requirement = match preservation { + Preservation::Expendable => ExistenceRequirement::AllowDeath, + Preservation::Protect | Preservation::Preserve => ExistenceRequirement::KeepAlive, + }; + Self::do_transfer(asset_id, source, dest, amount, existence_requirement).map(|_| amount) + } +} + +impl fungibles::Unbalanced for Pallet { + fn handle_dust(_dust: fungibles::Dust) { + // Dust is handled in account mutate method + } + + fn write_balance( + asset_id: Self::AssetId, + who: &T::AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + let max_reduction = >::reducible_balance( + asset_id, + who, + Preservation::Expendable, + Fortitude::Force, + ); + + // Balance is the same type and will not overflow + let (_, dust_amount) = + Self::try_mutate_account(who, asset_id, |account, _| -> Result<(), DispatchError> { + // Make sure the reduction (if there is one) is no more than the maximum + // allowed. + let reduction = account.free.saturating_sub(amount); + ensure!(reduction <= max_reduction, Error::::BalanceTooLow); + + account.free = amount; + Self::deposit_event(Event::BalanceSet { + currency_id: asset_id, + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); + + Ok(()) + })?; + + Ok(dust_amount) + } + + fn set_total_issuance(asset_id: Self::AssetId, amount: Self::Balance) { + // Balance is the same type and will not overflow + TotalIssuance::::mutate(asset_id, |t| *t = amount); + + Self::deposit_event(Event::TotalIssuanceSet { + currency_id: asset_id, + amount, + }); + } + + fn decrease_balance( + asset: Self::AssetId, + who: &T::AccountId, + mut amount: Self::Balance, + precision: Precision, + preservation: Preservation, + force: Fortitude, + ) -> Result { + let old_balance = as fungibles::Inspect>::balance(asset, who); + let free = as fungibles::Inspect>::reducible_balance( + asset, + who, + preservation, + force, + ); + if let Precision::BestEffort = precision { + amount = amount.min(free); + } + let new_balance = old_balance + .checked_sub(&amount) + .ok_or(TokenError::FundsUnavailable)?; + let _dust_amount = Self::write_balance(asset, who, new_balance)?.unwrap_or_default(); + + // here just return decrease amount, shouldn't count the dust_amount + Ok(old_balance.saturating_sub(new_balance)) + } +} + +type ReasonOf =

::AccountId>>::Reason; +impl fungibles::InspectHold for Pallet { + type Reason = (); + + fn balance_on_hold( + asset_id: Self::AssetId, + _reason: &Self::Reason, + who: &T::AccountId, + ) -> T::Balance { + Self::accounts(who, asset_id).reserved + } + + fn total_balance_on_hold(asset: Self::AssetId, who: &T::AccountId) -> Self::Balance { + Self::accounts(who, asset).reserved + } + + fn reducible_total_balance_on_hold( + _asset: Self::AssetId, + _who: &T::AccountId, + _force: Fortitude, + ) -> Self::Balance { + 0u32.into() + } + + fn hold_available(_asset: Self::AssetId, _reason: &Self::Reason, _who: &T::AccountId) -> bool { + true + } + + fn can_hold( + asset_id: Self::AssetId, + _reason: &Self::Reason, + who: &T::AccountId, + amount: T::Balance, + ) -> bool { + let a = Self::accounts(who, asset_id); + let min_balance = T::ExistentialDeposits::get(&asset_id).max(a.frozen); + if a.reserved.checked_add(&amount).is_none() { + return false; + } + // We require it to be min_balance + amount to ensure that the full reserved + // funds may be slashed without compromising locked funds or destroying the + // account. + let required_free = match min_balance.checked_add(&amount) { + Some(x) => x, + None => return false, + }; + a.free >= required_free + } +} + +impl fungibles::MutateHold for Pallet { + fn hold( + asset_id: Self::AssetId, + _reason: &ReasonOf, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + as MultiReservableCurrency<_>>::reserve(asset_id, who, amount) + } + + fn release( + asset_id: Self::AssetId, + _reason: &ReasonOf, + who: &T::AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + if amount.is_zero() { + return Ok(amount); + } + + // Done on a best-effort basis. + let (released, _) = Self::try_mutate_account( + who, + asset_id, + |a, _existed| -> Result { + let new_free = a.free.saturating_add(amount.min(a.reserved)); + let actual = new_free.defensive_saturating_sub(a.free); + // Guaranteed to be <= amount and <= a.reserved + ensure!( + matches!(precision, Precision::BestEffort) || actual == amount, + Error::::BalanceTooLow + ); + a.free = new_free; + a.reserved = a.reserved.saturating_sub(actual); + + Self::deposit_event(Event::Unreserved { + currency_id: asset_id, + who: who.clone(), + amount, + }); + Ok(actual) + }, + )?; + + Ok(released) + } + + fn transfer_on_hold( + asset_id: Self::AssetId, + reason: &ReasonOf, + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + precision: Precision, + restriction: Restriction, + _fortitude: Fortitude, + ) -> Result { + let status = if restriction == Restriction::OnHold { + Status::Reserved + } else { + Status::Free + }; + ensure!( + amount + <= >::balance_on_hold( + asset_id, reason, source + ) || precision == Precision::BestEffort, + Error::::BalanceTooLow + ); + let gap = Self::repatriate_reserved(asset_id, source, dest, amount, status)?; + // return actual transferred amount + Ok(amount.saturating_sub(gap)) + } +} + +impl fungibles::UnbalancedHold for Pallet { + fn set_balance_on_hold( + asset: Self::AssetId, + _reason: &Self::Reason, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + // Balance is the same type and will not overflow + Self::try_mutate_account(who, asset, |account, _| -> Result<(), DispatchError> { + let old_reserved = account.reserved; + account.reserved = amount; + // free = free + old - new + account.free = account + .free + .checked_add(&old_reserved) + .ok_or(ArithmeticError::Overflow)? + .checked_sub(&account.reserved) + .ok_or(TokenError::BelowMinimum)?; + + Self::deposit_event(Event::BalanceSet { + currency_id: asset, + who: who.clone(), + free: account.free, + reserved: account.reserved, + }); + + Ok(()) + }) + .map(|_| ()) + } +} + +pub struct CurrencyAdapter(marker::PhantomData<(T, GetCurrencyId)>); + +impl PalletCurrency for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + type Balance = T::Balance; + type PositiveImbalance = PositiveImbalance; + type NegativeImbalance = NegativeImbalance; + + fn total_balance(who: &T::AccountId) -> Self::Balance { + as MultiCurrency<_>>::total_balance(GetCurrencyId::get(), who) + } + + fn can_slash(who: &T::AccountId, value: Self::Balance) -> bool { + as MultiCurrency<_>>::can_slash(GetCurrencyId::get(), who, value) + } + + fn total_issuance() -> Self::Balance { + as MultiCurrency<_>>::total_issuance(GetCurrencyId::get()) + } + + fn minimum_balance() -> Self::Balance { + as MultiCurrency<_>>::minimum_balance(GetCurrencyId::get()) + } + + fn burn(mut amount: Self::Balance) -> Self::PositiveImbalance { + if amount.is_zero() { + return PositiveImbalance::zero(); + } + let currency_id = GetCurrencyId::get(); + TotalIssuance::::mutate(currency_id, |issued| { + *issued = issued.checked_sub(&amount).unwrap_or_else(|| { + amount = *issued; + Zero::zero() + }) + }); + + Pallet::::deposit_event(Event::TotalIssuanceSet { + currency_id, + amount: Self::total_issuance(), + }); + PositiveImbalance::new(amount) + } + + fn issue(mut amount: Self::Balance) -> Self::NegativeImbalance { + if amount.is_zero() { + return NegativeImbalance::zero(); + } + TotalIssuance::::mutate(GetCurrencyId::get(), |issued| { + *issued = issued.checked_add(&amount).unwrap_or_else(|| { + amount = Self::Balance::max_value().defensive_saturating_sub(*issued); + Self::Balance::max_value() + }) + }); + + Pallet::::deposit_event(Event::TotalIssuanceSet { + currency_id: GetCurrencyId::get(), + amount: Self::total_issuance(), + }); + NegativeImbalance::new(amount) + } + + fn free_balance(who: &T::AccountId) -> Self::Balance { + as MultiCurrency<_>>::free_balance(GetCurrencyId::get(), who) + } + + fn ensure_can_withdraw( + who: &T::AccountId, + amount: Self::Balance, + _reasons: WithdrawReasons, + _new_balance: Self::Balance, + ) -> DispatchResult { + as MultiCurrency<_>>::ensure_can_withdraw(GetCurrencyId::get(), who, amount) + } + + fn transfer( + source: &T::AccountId, + dest: &T::AccountId, + value: Self::Balance, + existence_requirement: ExistenceRequirement, + ) -> DispatchResult { + Pallet::::do_transfer( + GetCurrencyId::get(), + source, + dest, + value, + existence_requirement, + ) + } + + fn slash(who: &T::AccountId, value: Self::Balance) -> (Self::NegativeImbalance, Self::Balance) { + if value.is_zero() { + return (Self::NegativeImbalance::zero(), value); + } + + let currency_id = GetCurrencyId::get(); + let account = Pallet::::accounts(who, currency_id); + let free_slashed_amount = account.free.min(value); + let mut remaining_slash = value.defensive_saturating_sub(free_slashed_amount); + + // slash free balance + if !free_slashed_amount.is_zero() { + Pallet::::set_free_balance( + currency_id, + who, + account.free.defensive_saturating_sub(free_slashed_amount), + ); + } + + // slash reserved balance + if !remaining_slash.is_zero() { + let reserved_slashed_amount = account.reserved.min(remaining_slash); + remaining_slash = remaining_slash.defensive_saturating_sub(reserved_slashed_amount); + Pallet::::set_reserved_balance( + currency_id, + who, + account + .reserved + .defensive_saturating_sub(reserved_slashed_amount), + ); + + Pallet::::deposit_event(Event::Slashed { + currency_id, + who: who.clone(), + free_amount: free_slashed_amount, + reserved_amount: reserved_slashed_amount, + }); + ( + Self::NegativeImbalance::new( + free_slashed_amount.saturating_add(reserved_slashed_amount), + ), + remaining_slash, + ) + } else { + Pallet::::deposit_event(Event::Slashed { + currency_id, + who: who.clone(), + free_amount: value, + reserved_amount: Zero::zero(), + }); + (Self::NegativeImbalance::new(value), remaining_slash) + } + } + + /// Deposit some `value` into the free balance of an existing target account + /// `who`. + fn deposit_into_existing( + who: &T::AccountId, + value: Self::Balance, + ) -> sp_std::result::Result { + // do not change total issuance + Pallet::::do_deposit(GetCurrencyId::get(), who, value, true, false) + .map(|_| PositiveImbalance::new(value)) + } + + /// Deposit some `value` into the free balance of `who`, possibly creating a + /// new account. + fn deposit_creating(who: &T::AccountId, value: Self::Balance) -> Self::PositiveImbalance { + // do not change total issuance + Pallet::::do_deposit(GetCurrencyId::get(), who, value, false, false).map_or_else( + |_| Self::PositiveImbalance::zero(), + |_| PositiveImbalance::new(value), + ) + } + + fn withdraw( + who: &T::AccountId, + value: Self::Balance, + _reasons: WithdrawReasons, + liveness: ExistenceRequirement, + ) -> sp_std::result::Result { + // do not change total issuance + Pallet::::do_withdraw(GetCurrencyId::get(), who, value, liveness, false) + .map(|_| Self::NegativeImbalance::new(value)) + } + + fn make_free_balance_be( + who: &T::AccountId, + value: Self::Balance, + ) -> SignedImbalance { + let currency_id = GetCurrencyId::get(); + Pallet::::try_mutate_account( + who, + currency_id, + |account, + existed| + -> Result, ()> { + // If we're attempting to set an existing account to less than ED, then + // bypass the entire operation. It's a no-op if you follow it through, but + // since this is an instance where we might account for a negative imbalance + // (in the dust cleaner of set_account) before we account for its actual + // equal and opposite cause (returned as an Imbalance), then in the + // instance that there's no other accounts on the system at all, we might + // underflow the issuance and our arithmetic will be off. + let ed = T::ExistentialDeposits::get(¤cy_id); + ensure!(value.saturating_add(account.reserved) >= ed || existed, ()); + + let imbalance = if account.free <= value { + SignedImbalance::Positive(PositiveImbalance::new( + value.saturating_sub(account.free), + )) + } else { + SignedImbalance::Negative(NegativeImbalance::new( + account.free.saturating_sub(value), + )) + }; + account.free = value; + + Pallet::::deposit_event(Event::BalanceSet { + currency_id, + who: who.clone(), + free: value, + reserved: account.reserved, + }); + Ok(imbalance) + }, + ) + .map(|(imbalance, _)| imbalance) + .unwrap_or_else(|_| SignedImbalance::Positive(Self::PositiveImbalance::zero())) + } +} + +impl PalletReservableCurrency for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + fn can_reserve(who: &T::AccountId, value: Self::Balance) -> bool { + as MultiReservableCurrency<_>>::can_reserve(GetCurrencyId::get(), who, value) + } + + fn slash_reserved( + who: &T::AccountId, + value: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { + let actual = as MultiReservableCurrency<_>>::slash_reserved( + GetCurrencyId::get(), + who, + value, + ); + (Self::NegativeImbalance::zero(), actual) + } + + fn reserved_balance(who: &T::AccountId) -> Self::Balance { + as MultiReservableCurrency<_>>::reserved_balance(GetCurrencyId::get(), who) + } + + fn reserve(who: &T::AccountId, value: Self::Balance) -> DispatchResult { + as MultiReservableCurrency<_>>::reserve(GetCurrencyId::get(), who, value) + } + + fn unreserve(who: &T::AccountId, value: Self::Balance) -> Self::Balance { + as MultiReservableCurrency<_>>::unreserve(GetCurrencyId::get(), who, value) + } + + fn repatriate_reserved( + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: Status, + ) -> sp_std::result::Result { + as MultiReservableCurrency<_>>::repatriate_reserved( + GetCurrencyId::get(), + slashed, + beneficiary, + value, + status, + ) + } +} + +impl PalletNamedReservableCurrency + for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + type ReserveIdentifier = T::ReserveIdentifier; + + fn reserved_balance_named(id: &Self::ReserveIdentifier, who: &T::AccountId) -> Self::Balance { + as NamedMultiReservableCurrency<_>>::reserved_balance_named( + id, + GetCurrencyId::get(), + who, + ) + } + + fn reserve_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> DispatchResult { + as NamedMultiReservableCurrency<_>>::reserve_named( + id, + GetCurrencyId::get(), + who, + value, + ) + } + + fn unreserve_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> Self::Balance { + as NamedMultiReservableCurrency<_>>::unreserve_named( + id, + GetCurrencyId::get(), + who, + value, + ) + } + + fn slash_reserved_named( + id: &Self::ReserveIdentifier, + who: &T::AccountId, + value: Self::Balance, + ) -> (Self::NegativeImbalance, Self::Balance) { + let actual = as NamedMultiReservableCurrency<_>>::slash_reserved_named( + id, + GetCurrencyId::get(), + who, + value, + ); + (Self::NegativeImbalance::zero(), actual) + } + + fn repatriate_reserved_named( + id: &Self::ReserveIdentifier, + slashed: &T::AccountId, + beneficiary: &T::AccountId, + value: Self::Balance, + status: Status, + ) -> sp_std::result::Result { + as NamedMultiReservableCurrency<_>>::repatriate_reserved_named( + id, + GetCurrencyId::get(), + slashed, + beneficiary, + value, + status, + ) + } +} + +impl PalletLockableCurrency for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + type Moment = T::BlockNumber; + type MaxLocks = (); + + fn set_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: Self::Balance, + _reasons: WithdrawReasons, + ) { + let _ = as MultiLockableCurrency<_>>::set_lock( + id, + GetCurrencyId::get(), + who, + amount, + ); + } + + fn extend_lock( + id: LockIdentifier, + who: &T::AccountId, + amount: Self::Balance, + _reasons: WithdrawReasons, + ) { + let _ = as MultiLockableCurrency<_>>::extend_lock( + id, + GetCurrencyId::get(), + who, + amount, + ); + } + + fn remove_lock(id: LockIdentifier, who: &T::AccountId) { + let _ = as MultiLockableCurrency<_>>::remove_lock(id, GetCurrencyId::get(), who); + } +} + +impl TransferAll for Pallet { + #[transactional] + fn transfer_all(source: &T::AccountId, dest: &T::AccountId) -> DispatchResult { + Accounts::::iter_prefix(source).try_for_each( + |(currency_id, account_data)| -> DispatchResult { + // allow death + Self::do_transfer( + currency_id, + source, + dest, + account_data.free, + ExistenceRequirement::AllowDeath, + ) + }, + ) + } +} + +impl fungible::Inspect for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + type Balance = T::Balance; + + fn total_issuance() -> Self::Balance { + as fungibles::Inspect<_>>::total_issuance(GetCurrencyId::get()) + } + fn minimum_balance() -> Self::Balance { + as fungibles::Inspect<_>>::minimum_balance(GetCurrencyId::get()) + } + fn balance(who: &T::AccountId) -> Self::Balance { + as fungibles::Inspect<_>>::balance(GetCurrencyId::get(), who) + } + fn total_balance(who: &T::AccountId) -> Self::Balance { + as fungibles::Inspect<_>>::total_balance(GetCurrencyId::get(), who) + } + fn reducible_balance( + who: &T::AccountId, + preservation: Preservation, + fortitude: Fortitude, + ) -> Self::Balance { + as fungibles::Inspect<_>>::reducible_balance( + GetCurrencyId::get(), + who, + preservation, + fortitude, + ) + } + fn can_deposit( + who: &T::AccountId, + amount: Self::Balance, + provenance: Provenance, + ) -> DepositConsequence { + as fungibles::Inspect<_>>::can_deposit( + GetCurrencyId::get(), + who, + amount, + provenance, + ) + } + fn can_withdraw( + who: &T::AccountId, + amount: Self::Balance, + ) -> WithdrawConsequence { + as fungibles::Inspect<_>>::can_withdraw(GetCurrencyId::get(), who, amount) + } +} + +impl fungible::Mutate for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + fn mint_into( + who: &T::AccountId, + amount: Self::Balance, + ) -> Result { + as fungibles::Mutate<_>>::mint_into(GetCurrencyId::get(), who, amount) + } + fn burn_from( + who: &T::AccountId, + amount: Self::Balance, + precision: Precision, + fortitude: Fortitude, + ) -> Result { + as fungibles::Mutate<_>>::burn_from( + GetCurrencyId::get(), + who, + amount, + precision, + fortitude, + ) + } + + fn transfer( + source: &T::AccountId, + dest: &T::AccountId, + amount: T::Balance, + preservation: Preservation, + ) -> Result { + as fungibles::Mutate<_>>::transfer( + GetCurrencyId::get(), + source, + dest, + amount, + preservation, + ) + } +} + +impl fungible::Unbalanced for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + fn handle_dust(_dust: fungible::Dust) { + // Dust is handled in account mutate method + } + + fn write_balance( + who: &T::AccountId, + amount: Self::Balance, + ) -> Result, DispatchError> { + as fungibles::Unbalanced<_>>::write_balance(GetCurrencyId::get(), who, amount) + } + fn set_total_issuance(amount: Self::Balance) { + as fungibles::Unbalanced<_>>::set_total_issuance(GetCurrencyId::get(), amount) + } +} + +type ReasonOfFungible = +

::AccountId>>::Reason; +impl fungible::InspectHold for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + type Reason = as fungibles::InspectHold>::Reason; + + fn balance_on_hold(reason: &Self::Reason, who: &T::AccountId) -> T::Balance { + as fungibles::InspectHold<_>>::balance_on_hold(GetCurrencyId::get(), reason, who) + } + fn total_balance_on_hold(who: &T::AccountId) -> Self::Balance { + as fungibles::InspectHold<_>>::total_balance_on_hold(GetCurrencyId::get(), who) + } + fn reducible_total_balance_on_hold(who: &T::AccountId, force: Fortitude) -> Self::Balance { + as fungibles::InspectHold<_>>::reducible_total_balance_on_hold( + GetCurrencyId::get(), + who, + force, + ) + } + fn hold_available(reason: &Self::Reason, who: &T::AccountId) -> bool { + as fungibles::InspectHold<_>>::hold_available(GetCurrencyId::get(), reason, who) + } + fn can_hold(reason: &Self::Reason, who: &T::AccountId, amount: T::Balance) -> bool { + as fungibles::InspectHold<_>>::can_hold( + GetCurrencyId::get(), + reason, + who, + amount, + ) + } +} + +impl fungible::MutateHold for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + fn hold( + reason: &ReasonOfFungible, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + as fungibles::MutateHold<_>>::hold(GetCurrencyId::get(), reason, who, amount) + } + fn release( + reason: &ReasonOfFungible, + who: &T::AccountId, + amount: Self::Balance, + precision: Precision, + ) -> Result { + as fungibles::MutateHold<_>>::release( + GetCurrencyId::get(), + reason, + who, + amount, + precision, + ) + } + fn transfer_on_hold( + reason: &ReasonOfFungible, + source: &T::AccountId, + dest: &T::AccountId, + amount: Self::Balance, + precision: Precision, + restriction: Restriction, + fortitude: Fortitude, + ) -> Result { + as fungibles::MutateHold<_>>::transfer_on_hold( + GetCurrencyId::get(), + reason, + source, + dest, + amount, + precision, + restriction, + fortitude, + ) + } +} + +impl fungible::UnbalancedHold for CurrencyAdapter +where + T: Config, + GetCurrencyId: Get, +{ + fn set_balance_on_hold( + reason: &Self::Reason, + who: &T::AccountId, + amount: Self::Balance, + ) -> DispatchResult { + as fungibles::UnbalancedHold<_>>::set_balance_on_hold( + GetCurrencyId::get(), + reason, + who, + amount, + ) + } +} diff --git a/pallet/ggx-tokens/src/weights.rs b/pallet/ggx-tokens/src/weights.rs new file mode 100644 index 00000000..8f563716 --- /dev/null +++ b/pallet/ggx-tokens/src/weights.rs @@ -0,0 +1,66 @@ +//! Autogenerated weights for orml_tokens +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2021-09-14, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 + +// Executed Command: +// /Users/ermal/Acala/target/release/acala +// benchmark +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=orml_tokens +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --heap-pages=4096 +// --template=../templates/orml-weight-template.hbs +// --output=./tokens/src/weights.rs + + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(clippy::unnecessary_cast)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for orml_tokens. +pub trait WeightInfo { + fn transfer() -> Weight; + fn transfer_all() -> Weight; + fn transfer_keep_alive() -> Weight; + fn force_transfer() -> Weight; + fn set_balance() -> Weight; +} + +/// Default weights. +impl WeightInfo for () { + fn transfer() -> Weight { + Weight::from_parts(69_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + } + fn transfer_all() -> Weight { + Weight::from_parts(69_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(5 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + } + fn transfer_keep_alive() -> Weight { + Weight::from_parts(38_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + fn force_transfer() -> Weight { + Weight::from_parts(45_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + fn set_balance() -> Weight { + Weight::from_parts(34_000_000, 0) + .saturating_add(RocksDbWeight::get().reads(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } +} diff --git a/runtime/brooklyn/Cargo.toml b/runtime/brooklyn/Cargo.toml index a4989b8c..4496bb6c 100644 --- a/runtime/brooklyn/Cargo.toml +++ b/runtime/brooklyn/Cargo.toml @@ -155,6 +155,7 @@ vault-registry-rpc-runtime-api.workspace = true pallet-currencies.workspace = true pallet-dex.workspace = true pallet-erc20.workspace = true +pallet-ggx-tokens.workspace = true ggx-primitives.workspace = true @@ -291,10 +292,11 @@ std = [ "vault-registry-rpc-runtime-api/std", #Dex + "ggx-primitives/std", "pallet-currencies/std", "pallet-dex/std", "pallet-erc20/std", - "ggx-primitives/std", + "pallet-ggx-tokens/std", ] aura = [] allowlist = [] diff --git a/runtime/brooklyn/src/btcbridge.rs b/runtime/brooklyn/src/btcbridge.rs index b1e24737..816200c7 100644 --- a/runtime/brooklyn/src/btcbridge.rs +++ b/runtime/brooklyn/src/btcbridge.rs @@ -33,7 +33,7 @@ impl Contains for DustRemovalWhitelist { parameter_type_with_key! { pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { - Zero::zero() + Zero::zero() }; } diff --git a/runtime/brooklyn/src/currencies.rs b/runtime/brooklyn/src/currencies.rs index 2ff191ee..d871a339 100644 --- a/runtime/brooklyn/src/currencies.rs +++ b/runtime/brooklyn/src/currencies.rs @@ -1,9 +1,34 @@ -use crate::{prelude::*, Assets, BlakeTwo256, BlockNumber, Erc20, Tokens, H160}; +use crate::{ + prelude::*, Assets, BlakeTwo256, BlockNumber, ConstU32, Erc20, GGXTokens, MaxLocks, H160, +}; +use orml_traits::parameter_type_with_key; +use scale_info::prelude::vec; +use sp_runtime::traits::Zero; use ggx_primitives::currency::{CurrencyId, TokenSymbol}; use pallet_currencies::BasicCurrencyAdapter; pub type Amount = i128; +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Zero::zero() + }; +} + +impl pallet_ggx_tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = primitives::SignedBalance; + type CurrencyId = CurrencyId; + type WeightInfo = runtime_common::weights::pallet_ggx_tokens::WeightInfo; + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = (); + type MaxLocks = MaxLocks; + type DustRemovalWhitelist = (); + type MaxReserves = ConstU32<0>; // we don't use named reserves + type ReserveIdentifier = (); // we don't use named reserves +} + ///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. pub struct HashedAccountMapping; impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { @@ -18,7 +43,7 @@ parameter_types! { } impl pallet_currencies::Config for Runtime { - type MultiCurrency = Tokens; + type MultiCurrency = GGXTokens; type NativeCurrency = BasicCurrencyAdapter; type GetNativeCurrencyId = NativeCurrencyId; type WeightInfo = (); diff --git a/runtime/brooklyn/src/lib.rs b/runtime/brooklyn/src/lib.rs index c18497e8..c103108f 100644 --- a/runtime/brooklyn/src/lib.rs +++ b/runtime/brooklyn/src/lib.rs @@ -672,7 +672,7 @@ construct_runtime!( // Dex Dex: pallet_dex, - + GGXTokens: pallet_ggx_tokens, Erc20: pallet_erc20, //GGXCurrencies: currencies, } diff --git a/runtime/runtime-common/Cargo.toml b/runtime/runtime-common/Cargo.toml index d524bc69..66a9a4d2 100644 --- a/runtime/runtime-common/Cargo.toml +++ b/runtime/runtime-common/Cargo.toml @@ -65,6 +65,9 @@ replace.workspace = true security.workspace = true vault-registry.workspace = true +# dex +pallet-ggx-tokens.workspace = true + [dev-dependencies] env_logger.workspace = true frame-election-provider-support = { workspace = true, features = ["std"] } @@ -148,4 +151,7 @@ std = [ "replace/std", "security/std", "vault-registry/std", + + # dex + "pallet-ggx-tokens/std", ] diff --git a/runtime/runtime-common/src/weights/mod.rs b/runtime/runtime-common/src/weights/mod.rs index 2841e9c7..94d8c23d 100644 --- a/runtime/runtime-common/src/weights/mod.rs +++ b/runtime/runtime-common/src/weights/mod.rs @@ -8,6 +8,7 @@ pub mod nomination; pub mod oracle; pub mod orml_asset_registry; pub mod orml_tokens; +pub mod pallet_ggx_tokens; pub mod redeem; pub mod replace; pub mod security; diff --git a/runtime/runtime-common/src/weights/pallet_ggx_tokens.rs b/runtime/runtime-common/src/weights/pallet_ggx_tokens.rs new file mode 100644 index 00000000..fca94a69 --- /dev/null +++ b/runtime/runtime-common/src/weights/pallet_ggx_tokens.rs @@ -0,0 +1,164 @@ + +//! Autogenerated weights for pallet_ggx_tokens +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `10`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `interlay-rust-runner-2mz2v-jrrg4`, CPU: `AMD EPYC 7502P 32-Core Processor` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("interlay-dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/interbtc-parachain +// benchmark +// pallet +// --pallet +// * +// --extrinsic +// * +// --chain +// interlay-dev +// --execution=wasm +// --wasm-execution=compiled +// --steps +// 50 +// --repeat +// 10 +// --output +// parachain/runtime/interlay/src/weights/ +// --template +// .deploy/runtime-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weights for pallet_ggx_tokens using the Substrate node and recommended hardware. +pub struct WeightInfo(PhantomData); + +impl pallet_ggx_tokens::WeightInfo for WeightInfo { + + /// Storage: Loans UnderlyingAssetId (r:1 w:0) + /// Proof: Loans UnderlyingAssetId (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplyState (r:1 w:1) + /// Proof: Loans RewardSupplyState (max_values: None, max_size: Some(47), added: 2522, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplySpeed (r:1 w:0) + /// Proof: Loans RewardSupplySpeed (max_values: None, max_size: Some(43), added: 2518, mode: MaxEncodedLen) + /// Storage: Loans Markets (r:2 w:0) + /// Proof: Loans Markets (max_values: None, max_size: Some(160), added: 2635, mode: MaxEncodedLen) + /// Storage: Tokens TotalIssuance (r:1 w:0) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(35), added: 2510, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplierIndex (r:2 w:2) + /// Proof: Loans RewardSupplierIndex (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Loans RewardAccrued (r:2 w:2) + /// Proof: Loans RewardAccrued (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(115), added: 2590, mode: MaxEncodedLen) + /// Storage: Loans AccountDeposits (r:1 w:1) + /// Proof: Loans AccountDeposits (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn transfer () -> Weight { + // Proof Size summary in bytes: + // Measured: `1743` + // Estimated: `6260` + // Minimum execution time: 209_179_000 picoseconds. + Weight::from_parts(211_704_000, 6260) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(115), added: 2590, mode: MaxEncodedLen) + /// Storage: Loans UnderlyingAssetId (r:1 w:0) + /// Proof: Loans UnderlyingAssetId (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplyState (r:1 w:1) + /// Proof: Loans RewardSupplyState (max_values: None, max_size: Some(47), added: 2522, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplySpeed (r:1 w:0) + /// Proof: Loans RewardSupplySpeed (max_values: None, max_size: Some(43), added: 2518, mode: MaxEncodedLen) + /// Storage: Loans Markets (r:2 w:0) + /// Proof: Loans Markets (max_values: None, max_size: Some(160), added: 2635, mode: MaxEncodedLen) + /// Storage: Tokens TotalIssuance (r:1 w:0) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(35), added: 2510, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplierIndex (r:2 w:2) + /// Proof: Loans RewardSupplierIndex (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Loans RewardAccrued (r:2 w:2) + /// Proof: Loans RewardAccrued (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Loans AccountDeposits (r:1 w:1) + /// Proof: Loans AccountDeposits (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn transfer_all () -> Weight { + // Proof Size summary in bytes: + // Measured: `1743` + // Estimated: `6260` + // Minimum execution time: 215_902_000 picoseconds. + Weight::from_parts(219_470_000, 6260) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Loans UnderlyingAssetId (r:1 w:0) + /// Proof: Loans UnderlyingAssetId (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplyState (r:1 w:1) + /// Proof: Loans RewardSupplyState (max_values: None, max_size: Some(47), added: 2522, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplySpeed (r:1 w:0) + /// Proof: Loans RewardSupplySpeed (max_values: None, max_size: Some(43), added: 2518, mode: MaxEncodedLen) + /// Storage: Loans Markets (r:2 w:0) + /// Proof: Loans Markets (max_values: None, max_size: Some(160), added: 2635, mode: MaxEncodedLen) + /// Storage: Tokens TotalIssuance (r:1 w:0) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(35), added: 2510, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplierIndex (r:2 w:2) + /// Proof: Loans RewardSupplierIndex (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Loans RewardAccrued (r:2 w:2) + /// Proof: Loans RewardAccrued (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(115), added: 2590, mode: MaxEncodedLen) + /// Storage: Loans AccountDeposits (r:1 w:1) + /// Proof: Loans AccountDeposits (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn transfer_keep_alive () -> Weight { + // Proof Size summary in bytes: + // Measured: `1743` + // Estimated: `6260` + // Minimum execution time: 205_602_000 picoseconds. + Weight::from_parts(207_255_000, 6260) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Loans UnderlyingAssetId (r:1 w:0) + /// Proof: Loans UnderlyingAssetId (max_values: None, max_size: Some(38), added: 2513, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplyState (r:1 w:1) + /// Proof: Loans RewardSupplyState (max_values: None, max_size: Some(47), added: 2522, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplySpeed (r:1 w:0) + /// Proof: Loans RewardSupplySpeed (max_values: None, max_size: Some(43), added: 2518, mode: MaxEncodedLen) + /// Storage: Loans Markets (r:2 w:0) + /// Proof: Loans Markets (max_values: None, max_size: Some(160), added: 2635, mode: MaxEncodedLen) + /// Storage: Tokens TotalIssuance (r:1 w:0) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(35), added: 2510, mode: MaxEncodedLen) + /// Storage: Loans RewardSupplierIndex (r:2 w:2) + /// Proof: Loans RewardSupplierIndex (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: Loans RewardAccrued (r:2 w:2) + /// Proof: Loans RewardAccrued (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) + /// Storage: Tokens Accounts (r:2 w:2) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(115), added: 2590, mode: MaxEncodedLen) + /// Storage: Loans AccountDeposits (r:1 w:1) + /// Proof: Loans AccountDeposits (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + fn force_transfer () -> Weight { + // Proof Size summary in bytes: + // Measured: `1743` + // Estimated: `6260` + // Minimum execution time: 209_379_000 picoseconds. + Weight::from_parts(211_293_000, 6260) + .saturating_add(T::DbWeight::get().reads(13_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: Tokens Accounts (r:1 w:1) + /// Proof: Tokens Accounts (max_values: None, max_size: Some(115), added: 2590, mode: MaxEncodedLen) + /// Storage: Tokens TotalIssuance (r:1 w:1) + /// Proof: Tokens TotalIssuance (max_values: None, max_size: Some(35), added: 2510, mode: MaxEncodedLen) + fn set_balance () -> Weight { + // Proof Size summary in bytes: + // Measured: `435` + // Estimated: `3580` + // Minimum execution time: 52_415_000 picoseconds. + Weight::from_parts(53_918_000, 3580) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } +} \ No newline at end of file From 15db345c250bd8e9da173bf8a8ac3325ab1b8540 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Mon, 20 May 2024 20:30:38 +0800 Subject: [PATCH 07/27] export GGXCurrencies pallet --- pallet/currencies/Cargo.toml | 2 ++ pallet/currencies/src/lib.rs | 3 +++ pallet/erc-20/src/lib.rs | 16 +++++++++++----- primitives/src/currency.rs | 8 ++++---- primitives/src/evm.rs | 8 +++++++- runtime/brooklyn/src/lib.rs | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/pallet/currencies/Cargo.toml b/pallet/currencies/Cargo.toml index 0bc4c8f4..7d38f501 100644 --- a/pallet/currencies/Cargo.toml +++ b/pallet/currencies/Cargo.toml @@ -14,6 +14,7 @@ serde = { workspace = true, optional = true } frame-support = { workspace = true } frame-system = { workspace = true } +sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -42,6 +43,7 @@ std = [ "orml-utilities/std", "scale-codec/std", "scale-info/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 18a5016d..07e29ac6 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -61,6 +61,7 @@ use orml_traits::{ }; use orml_utilities::with_transaction_result; use scale_codec::Codec; +use sp_core::H160; use sp_runtime::{ traits::{CheckedSub, MaybeSerializeDeserialize, StaticLookup, Zero}, DispatchError, DispatchResult, @@ -305,6 +306,8 @@ impl MultiCurrency for Pallet { source_vm_id: VmId::Wasm, weight_limit: Weight::from_parts(1_000_000, 1_000_000), }, + contract, + from.clone(), address, amount, )?; diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 8ef8a346..c55c424d 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -262,7 +262,13 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { } // Calls the transfer method on an ERC20 contract using the given context. - fn transfer(context: Context, to: H160, value: BalanceOf) -> DispatchResult { + fn transfer( + context: Context, + contract: H160, + from: AccountIdOf, + to: H160, + value: BalanceOf, + ) -> DispatchResult { // // ERC20.transfer method hash // let mut input = Into::::into(Action::Transfer).to_be_bytes().to_vec(); // // append receiver address @@ -311,7 +317,7 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { weight_limit: Weight::from_parts(1_000_000, 1_000_000), }; - const TRANSFER_SELECTOR: [u8; 4] = hex!["6057361d"]; + const TRANSFER_SELECTOR: [u8; 4] = hex!["a9059cbb"]; // ERC20.transfer method hash let mut input = TRANSFER_SELECTOR.to_vec(); // append receiver address @@ -327,10 +333,10 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { let call_result = T::XvmCallApi::call( context, VmId::Evm, - ::PalletId::get().into_account_truncating(), - to.as_bytes().to_vec(), + from, + contract.as_bytes().to_vec(), input, - value.saturated_into::(), + 0, Some(storage_limit), ); diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index f70635d4..4bbbea33 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -32,7 +32,7 @@ impl TryFrom for EvmAddress { CurrencyId::Erc20(erc20) => { address[..].copy_from_slice(erc20.as_bytes()); } - CurrencyId::Erc1155(erc1155) => { + CurrencyId::Erc1155(erc1155, _) => { address[..].copy_from_slice(erc1155.as_bytes()); } @@ -169,7 +169,7 @@ pub trait TokenInfo { pub enum CurrencyId { Token(TokenSymbol), Erc20(EvmAddress), - Erc1155(EvmAddress), + Erc1155(EvmAddress, u128), ForeignAsset(ForeignAssetId), } @@ -183,7 +183,7 @@ impl CurrencyId { } pub fn is_erc1155_currency_id(&self) -> bool { - matches!(self, CurrencyId::Erc1155(_)) + matches!(self, CurrencyId::Erc1155(_, _)) } pub fn is_foreign_asset_currency_id(&self) -> bool { @@ -193,7 +193,7 @@ impl CurrencyId { pub fn erc20_address(&self) -> Option { match self { CurrencyId::Erc20(address) => Some(*address), - CurrencyId::Erc1155(address) => Some(*address), + CurrencyId::Erc1155(address, _) => Some(*address), CurrencyId::Token(_) => EvmAddress::try_from(*self).ok(), _ => None, } diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index df6ca6a6..2bffa150 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -19,7 +19,13 @@ pub trait EVMBridgeTrait { /// contract fn balance_of(context: Context, address: EvmAddress) -> Result; /// Execute ERC20.transfer(address, uint256) to transfer value to `to` - fn transfer(context: Context, to: EvmAddress, value: Balance) -> DispatchResult; + fn transfer( + context: Context, + contract: EvmAddress, + from: AccountId, + to: EvmAddress, + value: Balance, + ) -> DispatchResult; // /// Get the real origin account and charge storage rent from the origin. // fn get_origin() -> Option; // /// Set the EVM origin diff --git a/runtime/brooklyn/src/lib.rs b/runtime/brooklyn/src/lib.rs index c103108f..2d9a4bc8 100644 --- a/runtime/brooklyn/src/lib.rs +++ b/runtime/brooklyn/src/lib.rs @@ -674,7 +674,7 @@ construct_runtime!( Dex: pallet_dex, GGXTokens: pallet_ggx_tokens, Erc20: pallet_erc20, - //GGXCurrencies: currencies, + GGXCurrencies: pallet_currencies, } ); From 8483f9733207dace1dd6db31704961cd10f0fd1b Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 21 May 2024 18:07:23 +0800 Subject: [PATCH 08/27] update MAXIMUM_BLOCK_WEIGHT --- Cargo.lock | 1 + Cargo.toml | 2 ++ pallet/currencies/src/lib.rs | 2 +- pallet/erc-20/src/lib.rs | 5 ----- runtime/brooklyn/Cargo.toml | 3 +++ runtime/brooklyn/src/lib.rs | 8 ++++++-- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93370d37..513a99f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4892,6 +4892,7 @@ dependencies = [ "pallet-xvm", "parity-scale-codec", "paste", + "polkadot-primitives", "prost", "redeem", "redeem-rpc-runtime-api", diff --git a/Cargo.toml b/Cargo.toml index 6578b1b7..eb73ff36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -162,6 +162,8 @@ substrate-build-script-utils = { version = "3.0.0", git = "https://github.com/pa substrate-frame-rpc-system = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } substrate-test-utils = { version = "4.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } substrate-wasm-builder = { version = "5.0.0-dev", git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.43" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false } + # Frontier Client fc-cli = { version = "1.0.0-dev", git = "https://github.com/AstarNetwork/frontier.git", branch = "polkadot-v0.9.43" } diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 07e29ac6..9770b291 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -304,7 +304,7 @@ impl MultiCurrency for Pallet { T::EVMBridge::transfer( Context { source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000, 1_000_000), + weight_limit: Weight::from_parts(1_000_000_000, 1_000_000_000), }, contract, from.clone(), diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index c55c424d..c3f83800 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -312,11 +312,6 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { // @param value The amount to be transferred. // function transfer(address to, uint256 value) external returns (bool); - let context = Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000, 1_000_000), - }; - const TRANSFER_SELECTOR: [u8; 4] = hex!["a9059cbb"]; // ERC20.transfer method hash let mut input = TRANSFER_SELECTOR.to_vec(); diff --git a/runtime/brooklyn/Cargo.toml b/runtime/brooklyn/Cargo.toml index 4496bb6c..667c25e6 100644 --- a/runtime/brooklyn/Cargo.toml +++ b/runtime/brooklyn/Cargo.toml @@ -76,6 +76,7 @@ pallet-treasury.workspace = true pallet-utility.workspace = true pallet-vesting.workspace = true pallet-whitelist.workspace = true +polkadot-primitives.workspace = true # Frontier fp-evm.workspace = true @@ -232,6 +233,8 @@ std = [ "pallet-utility/std", "pallet-vesting/std", "pallet-whitelist/std", + "polkadot-primitives/std", + # Frontier "fp-evm/std", "fp-rpc/std", diff --git a/runtime/brooklyn/src/lib.rs b/runtime/brooklyn/src/lib.rs index 2d9a4bc8..294b5fe1 100644 --- a/runtime/brooklyn/src/lib.rs +++ b/runtime/brooklyn/src/lib.rs @@ -243,8 +243,12 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); /// We assume that ~10% of the block weight is consumed by `on_initalize` handlers. /// This is used to limit the maximal weight of a single extrinsic. const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); -const MAXIMUM_BLOCK_WEIGHT: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND, 5 * WEIGHT_PROOF_SIZE_PER_MB); +const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_REF_TIME_PER_SECOND, + // TODO: drop `* 10` after https://github.com/paritytech/substrate/issues/13501 + // and the benchmarked size is not 10x of the measured size + polkadot_primitives::MAX_POV_SIZE as u64 * 10, +); parameter_types! { pub const Version: RuntimeVersion = VERSION; From 75cbbb3137997d26b09a5bd62be7af4d1544c974 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 21 May 2024 20:17:49 +0800 Subject: [PATCH 09/27] add CurrencyId to pallet dex --- Cargo.lock | 6 ++ node/src/runtime/testnet.rs | 14 ++- pallet/dex/Cargo.toml | 4 + pallet/dex/src/lib.rs | 103 ++++++++++++------- primitives/src/currency.rs | 6 ++ runtime/brooklyn/src/dex.rs | 8 +- runtime/brooklyn/src/dex_chain_extensions.rs | 16 +-- runtime/sydney/Cargo.toml | 10 ++ runtime/sydney/src/currencies.rs | 53 ++++++++++ runtime/sydney/src/dex.rs | 11 +- runtime/sydney/src/dex_chain_extensions.rs | 16 +-- runtime/sydney/src/erc20.rs | 13 +++ runtime/sydney/src/lib.rs | 5 + 13 files changed, 210 insertions(+), 55 deletions(-) create mode 100644 runtime/sydney/src/currencies.rs create mode 100644 runtime/sydney/src/erc20.rs diff --git a/Cargo.lock b/Cargo.lock index 513a99f1..61d4aff8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4952,6 +4952,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", + "ggx-primitives", "ibc 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", "ibc-proto 0.25.0 (git+https://github.com/octopus-network/ibc-proto-rs?branch=ibc)", "interbtc-primitives", @@ -4978,14 +4979,17 @@ dependencies = [ "pallet-contracts", "pallet-contracts-primitives", "pallet-conviction-voting", + "pallet-currencies", "pallet-dex", "pallet-dynamic-fee", "pallet-election-provider-multi-phase", + "pallet-erc20", "pallet-eth2-light-client", "pallet-ethereum", "pallet-ethereum-checked", "pallet-evm", "pallet-evm-chain-id", + "pallet-ggx-tokens", "pallet-grandpa", "pallet-hotfix-sufficients", "pallet-ibc", @@ -8661,7 +8665,9 @@ version = "0.1.0" dependencies = [ "frame-support", "frame-system", + "ggx-primitives", "log 0.4.20", + "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "pallet-assets", "pallet-balances", "pallet-timestamp", diff --git a/node/src/runtime/testnet.rs b/node/src/runtime/testnet.rs index ca3e216d..43c682f7 100644 --- a/node/src/runtime/testnet.rs +++ b/node/src/runtime/testnet.rs @@ -5,6 +5,7 @@ use std::{collections::BTreeMap, str::FromStr}; pub use ggxchain_runtime_brooklyn::{opaque::SessionKeys, *}; +use ggx_primitives::currency::CurrencyId::ForeignAsset; use ggxchain_runtime_brooklyn::btcbridge::CurrencyId::Token; use primitives::{CurrencyId, Rate, TokenSymbol::GGXT, VaultCurrencyPair}; use rand::SeedableRng; @@ -378,8 +379,17 @@ pub fn testnet_genesis( min_exchange_rate: Rate::from_inner(loans::DEFAULT_MIN_EXCHANGE_RATE), }, dex: DexConfig { - asset_ids: vec![8888, 999, 888, 777, 666, 667], - native_asset_id: 8888, + asset_ids: vec![ + ForeignAsset(8888), + ForeignAsset(999), + ForeignAsset(888), + ForeignAsset(777), + ForeignAsset(666), + ForeignAsset(667), + ], + native_asset_id: ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), }, } } diff --git a/pallet/dex/Cargo.toml b/pallet/dex/Cargo.toml index b9e8dfde..f4aeb42a 100644 --- a/pallet/dex/Cargo.toml +++ b/pallet/dex/Cargo.toml @@ -11,7 +11,9 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] frame-support.workspace = true frame-system.workspace = true +ggx-primitives.workspace = true log.workspace = true +orml-traits = { workspace = true } scale-codec = { package = "parity-scale-codec", workspace = true, features = ["max-encoded-len"] } scale-info.workspace = true sp-runtime.workspace = true @@ -28,6 +30,8 @@ default = ["std"] std = [ "frame-support/std", "frame-system/std", + "ggx-primitives/std", + "orml-traits/std", "pallet-assets/std", "pallet-balances/std", "pallet-timestamp/std", diff --git a/pallet/dex/src/lib.rs b/pallet/dex/src/lib.rs index 5176c1e2..cb975818 100644 --- a/pallet/dex/src/lib.rs +++ b/pallet/dex/src/lib.rs @@ -10,6 +10,7 @@ use frame_support::{ }; use frame_system::offchain::SendTransactionTypes; +use ggx_primitives::currency::CurrencyId; use sp_runtime::{ offchain::{ storage::StorageValueRef, @@ -19,6 +20,14 @@ use sp_runtime::{ traits::{BlockNumberProvider, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub}, }; +use orml_traits::{ + arithmetic::{Signed, SimpleArithmetic}, + currency::TransferAll, + BalanceStatus, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, + BasicReservableCurrency, LockIdentifier, MultiCurrency, MultiCurrencyExtended, + MultiLockableCurrency, MultiReservableCurrency, NamedMultiReservableCurrency, +}; + use core::cmp::Ordering; use frame_system::pallet_prelude::*; @@ -78,9 +87,9 @@ pub enum OrderStatus { #[derive(Encode, Decode, Default, Eq, PartialEq, Clone, RuntimeDebug, TypeInfo)] pub struct Order { - counter: u64, //order index - address: AccountId, // - pair: (u32, u32), //AssetId_1 is base, AssetId_2 is quote token + counter: u64, //order index + address: AccountId, // + pair: (CurrencyId, CurrencyId), //AssetId_1 is base, AssetId_2 is quote token expiration_block: BlockNumber, order_type: OrderType, amount_offered: Balance, @@ -190,30 +199,39 @@ pub mod pallet { use frame_support::{ dispatch::DispatchResultWithPostInfo, pallet_prelude::{ValueQuery, *}, + traits::{fungible, fungibles}, Blake2_128Concat, }; use frame_system::offchain::SubmitTransaction; - pub type BalanceOf = - <::Currency as Currency<::AccountId>>::Balance; + pub type BalanceOf = <::MultiCurrency as MultiCurrency< + ::AccountId, + >>::Balance; type OrderOf = Order<::AccountId, BalanceOf, BlockNumberFor>; - type MapMatchEnginesOf = - BoundedBTreeMap<(u32, u32), MatchEngine, BalanceOf>, ConstU32<{ u32::MAX }>>; + pub(crate) type AmountOf = <::MultiCurrency as MultiCurrencyExtended< + ::AccountId, + >>::Amount; + + type MapMatchEnginesOf = BoundedBTreeMap< + (CurrencyId, CurrencyId), + MatchEngine, BalanceOf>, + ConstU32<{ u32::MAX }>, + >; #[pallet::genesis_config] #[derive(Default)] pub struct GenesisConfig { - pub asset_ids: Vec, - pub native_asset_id: u32, + pub asset_ids: Vec, + pub native_asset_id: CurrencyId, } #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - let bounded_token_infoes: BoundedVec> = self + let bounded_token_infoes: BoundedVec> = self .asset_ids .clone() .try_into() @@ -245,8 +263,22 @@ pub mod pallet { type PalletId: Get; /// Expose customizable associated type of asset transfer, lock and unlock - type Fungibles: Balanced - + Mutate>; + type MultiCurrency: TransferAll + + MultiCurrencyExtended + + MultiLockableCurrency + + MultiReservableCurrency + + NamedMultiReservableCurrency + + fungibles::Inspect> + + fungibles::Mutate>; + + type NativeCurrency: BasicCurrencyExtended< + Self::AccountId, + Balance = BalanceOf, + Amount = AmountOf, + > + BasicLockableCurrency> + + BasicReservableCurrency> + + fungible::Inspect> + + fungible::Mutate>; type PrivilegedOrigin: EnsureOrigin<::RuntimeOrigin>; @@ -265,7 +297,7 @@ pub mod pallet { Blake2_128Concat, T::AccountId, //address Blake2_128Concat, - u32, //asset id + CurrencyId, //asset id TokenInfo>, ValueQuery, >; @@ -273,15 +305,15 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn token_infoes)] pub type TokenInfoes = - StorageValue<_, BoundedVec>, ValueQuery>; + StorageValue<_, BoundedVec>, ValueQuery>; #[pallet::storage] #[pallet::getter(fn token_index)] pub type TokenIndex = StorageMap< _, Blake2_128Concat, - u32, - u64, //token index + CurrencyId, + u64, //token sub index in TokenInfoes ValueQuery, >; @@ -308,7 +340,7 @@ pub mod pallet { pub type PairOrders = StorageMap< _, Blake2_128Concat, - (u32, u32), + (CurrencyId, CurrencyId), BoundedVec>, ValueQuery, >; @@ -337,7 +369,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn native_asset_id)] - pub type NativeAssetId = StorageValue<_, u32, ValueQuery>; + pub type NativeAssetId = StorageValue<_, CurrencyId, ValueQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] @@ -364,11 +396,11 @@ pub mod pallet { maker_order: OrderOf, }, Deposited { - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, }, Withdrawed { - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, }, NativeDeposited { @@ -428,7 +460,7 @@ pub mod pallet { let mut map_match_engines: MapMatchEnginesOf; if let Ok(Some(engines)) = store_hashmap_match_engines.get::, BalanceOf>, ConstU32<{ u32::MAX }>, >>() { @@ -554,7 +586,7 @@ pub mod pallet { #[pallet::call_index(0)] pub fn deposit( origin: OriginFor, - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -564,12 +596,11 @@ pub mod pallet { Error::::AssetIdNotInTokenIndex ); - >::transfer( + >::transfer( asset_id, &who, &Self::account_id(), amount, - Preservation::Expendable, )?; let mut info = TokenInfo::default(); @@ -594,7 +625,7 @@ pub mod pallet { #[pallet::call_index(1)] pub fn withdraw( origin: OriginFor, - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -615,12 +646,11 @@ pub mod pallet { .checked_sub(&amount) .ok_or(Error::::NotEnoughBalance)?; - >::transfer( + >::transfer( asset_id, &Self::account_id(), &who, amount, - Preservation::Expendable, )?; UserTokenInfoes::::insert(who, asset_id, info); @@ -634,8 +664,8 @@ pub mod pallet { #[allow(clippy::too_many_arguments)] pub fn make_order( origin: OriginFor, - asset_id_1: u32, - asset_id_2: u32, + asset_id_1: CurrencyId, + asset_id_2: CurrencyId, offered_amount: BalanceOf, requested_amount: BalanceOf, price: BalanceOf, @@ -826,7 +856,7 @@ pub mod pallet { Error::::AssetIdNotInTokenIndex ); - T::Currency::transfer(&who, &Self::account_id(), amount, AllowDeath)?; + T::NativeCurrency::transfer(&who, &Self::account_id(), amount)?; let mut info = TokenInfo::default(); if UserTokenInfoes::::contains_key(who.clone(), asset_id) { @@ -872,7 +902,7 @@ pub mod pallet { .checked_sub(&amount) .ok_or(Error::::NotEnoughBalance)?; - T::Currency::transfer(&Self::account_id(), &who, amount, AllowDeath)?; + T::NativeCurrency::transfer(&Self::account_id(), &who, amount)?; UserTokenInfoes::::insert(who, asset_id, info); @@ -882,7 +912,10 @@ pub mod pallet { #[pallet::weight({7})] #[pallet::call_index(7)] - pub fn allowlist_asset(origin: OriginFor, asset_id: u32) -> DispatchResultWithPostInfo { + pub fn allowlist_asset( + origin: OriginFor, + asset_id: CurrencyId, + ) -> DispatchResultWithPostInfo { T::PrivilegedOrigin::ensure_origin(origin)?; TokenInfoes::::mutate(|token_infoes| { @@ -988,7 +1021,7 @@ pub mod pallet { pub fn add_assert( account: &T::AccountId, - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, ) -> Result<(), DispatchError> { let mut info = TokenInfo::default(); @@ -1008,7 +1041,7 @@ pub mod pallet { pub fn sub_assert( account: &T::AccountId, - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, ) -> Result<(), DispatchError> { ensure!( @@ -1029,7 +1062,7 @@ pub mod pallet { pub fn sub_reserved_assert( account: &T::AccountId, - asset_id: u32, + asset_id: CurrencyId, amount: BalanceOf, ) -> Result<(), DispatchError> { ensure!( diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index 4bbbea33..55d3d196 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -173,6 +173,12 @@ pub enum CurrencyId { ForeignAsset(ForeignAssetId), } +impl Default for CurrencyId { + fn default() -> Self { + Self::Token(Default::default()) + } +} + impl CurrencyId { pub fn is_token_currency_id(&self) -> bool { matches!(self, CurrencyId::Token(_)) diff --git a/runtime/brooklyn/src/dex.rs b/runtime/brooklyn/src/dex.rs index b01cdee4..60bbecd4 100644 --- a/runtime/brooklyn/src/dex.rs +++ b/runtime/brooklyn/src/dex.rs @@ -1,6 +1,9 @@ +use crate::currencies::Amount; use frame_support::PalletId; +use orml_traits::MultiCurrency; +use pallet_currencies::BasicCurrencyAdapter; -use crate::{prelude::*, Assets, BlockNumber}; +use crate::{currencies::NativeCurrencyId, prelude::*, Assets, BlockNumber, GGXTokens}; parameter_types! { pub const DexPalletId: PalletId = PalletId(*b"py/sudex"); @@ -10,7 +13,8 @@ parameter_types! { impl pallet_dex::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = DexPalletId; - type Fungibles = Assets; + type MultiCurrency = GGXTokens; + type NativeCurrency = BasicCurrencyAdapter; type PrivilegedOrigin = frame_system::EnsureRoot; type Currency = Balances; type UnsignedPriority = UnsignedPriority; diff --git a/runtime/brooklyn/src/dex_chain_extensions.rs b/runtime/brooklyn/src/dex_chain_extensions.rs index 404da6c3..f785166b 100644 --- a/runtime/brooklyn/src/dex_chain_extensions.rs +++ b/runtime/brooklyn/src/dex_chain_extensions.rs @@ -3,6 +3,8 @@ use sp_runtime::{DispatchError, ModuleError}; use frame_support::traits::Currency; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use ggx_primitives::currency::CurrencyId; +use orml_traits::MultiCurrency; use pallet_contracts::chain_extension::{ ChainExtension, Environment, Ext, InitState, RetVal, SysConfig, }; @@ -14,7 +16,7 @@ use crate::chain_extensions::get_address_from_caller; use sp_std::{vec, vec::Vec}; -type BalanceOf = <::Currency as Currency< +type BalanceOf = <::MultiCurrency as MultiCurrency< ::AccountId, >>::Balance; @@ -199,7 +201,7 @@ where match func_id { DexFunc::Deposit => { - let input: DexDepositInput> = env.read_as()?; + let input: DexDepositInput> = env.read_as()?; let sender = get_address_from_caller(env.ext().caller().clone())?; let call_result = pallet_dex::Pallet::::deposit( @@ -217,14 +219,14 @@ where }; } DexFunc::BalanceOf => { - let input: DexBalanceOfInput = env.read_as()?; + let input: DexBalanceOfInput = env.read_as()?; let token_info = pallet_dex::UserTokenInfoes::::get(&input.owner, input.asset_id); env.write(&token_info.amount.encode(), false, None)?; } DexFunc::Withdraw => { - let input: DexWithdrawInput> = env.read_as()?; + let input: DexWithdrawInput> = env.read_as()?; let sender = get_address_from_caller(env.ext().caller().clone())?; let call_result = pallet_dex::Pallet::::withdraw( @@ -293,7 +295,7 @@ where env.write(&order.unwrap().encode(), false, None)?; } DexFunc::PairOrders => { - let input: DexPairOrdersInput = env.read_as()?; + let input: DexPairOrdersInput = env.read_as()?; let order_index_array = pallet_dex::PairOrders::::get((input.asset_id_1, input.asset_id_2)); @@ -319,7 +321,7 @@ where } DexFunc::MakeOrder => { let input: DexMakeOrderInput< - u32, + CurrencyId, BalanceOf, pallet_dex::OrderType, BlockNumberFor, @@ -388,7 +390,7 @@ where env.write(&token_id_array[input.index as usize].encode(), false, None)?; } DexFunc::PairOrderByIndex => { - let input: DexPairOrderByIndexInput = env.read_as()?; + let input: DexPairOrderByIndexInput = env.read_as()?; let order_index_array = pallet_dex::PairOrders::::get((input.asset_id_1, input.asset_id_2)); diff --git a/runtime/sydney/Cargo.toml b/runtime/sydney/Cargo.toml index 04f76984..03128b69 100644 --- a/runtime/sydney/Cargo.toml +++ b/runtime/sydney/Cargo.toml @@ -152,7 +152,12 @@ reward-rpc-runtime-api.workspace = true vault-registry-rpc-runtime-api.workspace = true # Dex +pallet-currencies.workspace = true pallet-dex.workspace = true +pallet-erc20.workspace = true +pallet-ggx-tokens.workspace = true + +ggx-primitives.workspace = true [build-dependencies] substrate-wasm-builder.workspace = true @@ -284,8 +289,13 @@ std = [ "replace-rpc-runtime-api/std", "reward-rpc-runtime-api/std", "vault-registry-rpc-runtime-api/std", + #Dex + "ggx-primitives/std", + "pallet-currencies/std", "pallet-dex/std", + "pallet-erc20/std", + "pallet-ggx-tokens/std", ] aura = [] allowlist = [] diff --git a/runtime/sydney/src/currencies.rs b/runtime/sydney/src/currencies.rs new file mode 100644 index 00000000..d871a339 --- /dev/null +++ b/runtime/sydney/src/currencies.rs @@ -0,0 +1,53 @@ +use crate::{ + prelude::*, Assets, BlakeTwo256, BlockNumber, ConstU32, Erc20, GGXTokens, MaxLocks, H160, +}; +use orml_traits::parameter_type_with_key; +use scale_info::prelude::vec; +use sp_runtime::traits::Zero; + +use ggx_primitives::currency::{CurrencyId, TokenSymbol}; +use pallet_currencies::BasicCurrencyAdapter; +pub type Amount = i128; + +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Zero::zero() + }; +} + +impl pallet_ggx_tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = primitives::SignedBalance; + type CurrencyId = CurrencyId; + type WeightInfo = runtime_common::weights::pallet_ggx_tokens::WeightInfo; + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = (); + type MaxLocks = MaxLocks; + type DustRemovalWhitelist = (); + type MaxReserves = ConstU32<0>; // we don't use named reserves + type ReserveIdentifier = (); // we don't use named reserves +} + +///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +parameter_types! { + pub const NativeCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::GGX); +} + +impl pallet_currencies::Config for Runtime { + type MultiCurrency = GGXTokens; + type NativeCurrency = BasicCurrencyAdapter; + type GetNativeCurrencyId = NativeCurrencyId; + type WeightInfo = (); + //type Erc20HoldingAccount = ; + type AddressMapping = HashedAccountMapping; + type EVMBridge = pallet_erc20::EVMBridge; +} diff --git a/runtime/sydney/src/dex.rs b/runtime/sydney/src/dex.rs index d24526eb..3f961948 100644 --- a/runtime/sydney/src/dex.rs +++ b/runtime/sydney/src/dex.rs @@ -1,6 +1,12 @@ use frame_support::PalletId; +use orml_traits::MultiCurrency; +use pallet_currencies::BasicCurrencyAdapter; -use crate::{prelude::*, Assets, BlockNumber}; +use crate::{ + currencies::{Amount, NativeCurrencyId}, + prelude::*, + Assets, BlockNumber, GGXTokens, +}; parameter_types! { pub const UnsignedPriority: BlockNumber = 1; @@ -10,7 +16,8 @@ parameter_types! { impl pallet_dex::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = DexPalletId; - type Fungibles = Assets; + type MultiCurrency = GGXTokens; + type NativeCurrency = BasicCurrencyAdapter; type PrivilegedOrigin = frame_system::EnsureRoot; type UnsignedPriority = UnsignedPriority; type Currency = Balances; diff --git a/runtime/sydney/src/dex_chain_extensions.rs b/runtime/sydney/src/dex_chain_extensions.rs index 404da6c3..f785166b 100644 --- a/runtime/sydney/src/dex_chain_extensions.rs +++ b/runtime/sydney/src/dex_chain_extensions.rs @@ -3,6 +3,8 @@ use sp_runtime::{DispatchError, ModuleError}; use frame_support::traits::Currency; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; +use ggx_primitives::currency::CurrencyId; +use orml_traits::MultiCurrency; use pallet_contracts::chain_extension::{ ChainExtension, Environment, Ext, InitState, RetVal, SysConfig, }; @@ -14,7 +16,7 @@ use crate::chain_extensions::get_address_from_caller; use sp_std::{vec, vec::Vec}; -type BalanceOf = <::Currency as Currency< +type BalanceOf = <::MultiCurrency as MultiCurrency< ::AccountId, >>::Balance; @@ -199,7 +201,7 @@ where match func_id { DexFunc::Deposit => { - let input: DexDepositInput> = env.read_as()?; + let input: DexDepositInput> = env.read_as()?; let sender = get_address_from_caller(env.ext().caller().clone())?; let call_result = pallet_dex::Pallet::::deposit( @@ -217,14 +219,14 @@ where }; } DexFunc::BalanceOf => { - let input: DexBalanceOfInput = env.read_as()?; + let input: DexBalanceOfInput = env.read_as()?; let token_info = pallet_dex::UserTokenInfoes::::get(&input.owner, input.asset_id); env.write(&token_info.amount.encode(), false, None)?; } DexFunc::Withdraw => { - let input: DexWithdrawInput> = env.read_as()?; + let input: DexWithdrawInput> = env.read_as()?; let sender = get_address_from_caller(env.ext().caller().clone())?; let call_result = pallet_dex::Pallet::::withdraw( @@ -293,7 +295,7 @@ where env.write(&order.unwrap().encode(), false, None)?; } DexFunc::PairOrders => { - let input: DexPairOrdersInput = env.read_as()?; + let input: DexPairOrdersInput = env.read_as()?; let order_index_array = pallet_dex::PairOrders::::get((input.asset_id_1, input.asset_id_2)); @@ -319,7 +321,7 @@ where } DexFunc::MakeOrder => { let input: DexMakeOrderInput< - u32, + CurrencyId, BalanceOf, pallet_dex::OrderType, BlockNumberFor, @@ -388,7 +390,7 @@ where env.write(&token_id_array[input.index as usize].encode(), false, None)?; } DexFunc::PairOrderByIndex => { - let input: DexPairOrderByIndexInput = env.read_as()?; + let input: DexPairOrderByIndexInput = env.read_as()?; let order_index_array = pallet_dex::PairOrders::::get((input.asset_id_1, input.asset_id_2)); diff --git a/runtime/sydney/src/erc20.rs b/runtime/sydney/src/erc20.rs new file mode 100644 index 00000000..87c4487b --- /dev/null +++ b/runtime/sydney/src/erc20.rs @@ -0,0 +1,13 @@ +use frame_support::PalletId; + +use crate::{prelude::*, Assets, BlockNumber, Xvm}; + +parameter_types! { + pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); +} + +impl pallet_erc20::Config for Runtime { + type Currency = Balances; + type PalletId = ERC20PalletId; + type XvmCallApi = Xvm; +} diff --git a/runtime/sydney/src/lib.rs b/runtime/sydney/src/lib.rs index ec2b96ab..f008a777 100644 --- a/runtime/sydney/src/lib.rs +++ b/runtime/sydney/src/lib.rs @@ -16,8 +16,10 @@ pub const CALL_PARAMS_MAX_SIZE: usize = 304; pub mod btcbridge; pub mod chain_extensions; +pub mod currencies; pub mod dex; mod dex_chain_extensions; +pub mod erc20; pub mod ethereum; pub mod governance; pub mod ibc; @@ -666,6 +668,9 @@ construct_runtime!( // Dex Dex: pallet_dex, + GGXTokens: pallet_ggx_tokens, + Erc20: pallet_erc20, + GGXCurrencies: pallet_currencies, } ); From 51c3ce8c851cccab3d36c458b5339765899bed36 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 22 May 2024 19:28:13 +0800 Subject: [PATCH 10/27] update tranfer ref_time to 100_000_000_000 --- pallet/currencies/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 9770b291..efaa271f 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -304,7 +304,7 @@ impl MultiCurrency for Pallet { T::EVMBridge::transfer( Context { source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(1_000_000_000, 1_000_000_000), + weight_limit: Weight::from_parts(100_000_000_000, 1_000_000_000), }, contract, from.clone(), From df36ae9adb2dc1a70a056ba4bba099ceab1151df Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 22 May 2024 21:17:02 +0800 Subject: [PATCH 11/27] update dex mock --- Cargo.lock | 3 + pallet/dex/Cargo.toml | 6 ++ pallet/dex/src/mock.rs | 135 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 135 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61d4aff8..47f2e9fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8667,15 +8667,18 @@ dependencies = [ "frame-system", "ggx-primitives", "log 0.4.20", + "orml-tokens", "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "pallet-assets", "pallet-balances", + "pallet-currencies", "pallet-timestamp", "parity-scale-codec", "scale-info", "sp-core 7.0.0", "sp-io 7.0.0", "sp-runtime 7.0.0", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.43)", ] [[package]] diff --git a/pallet/dex/Cargo.toml b/pallet/dex/Cargo.toml index f4aeb42a..39bdd579 100644 --- a/pallet/dex/Cargo.toml +++ b/pallet/dex/Cargo.toml @@ -22,8 +22,11 @@ sp-io.workspace = true [dev-dependencies] pallet-assets.workspace = true pallet-balances.workspace = true +pallet-currencies.workspace = true pallet-timestamp.workspace = true sp-core.workspace = true +sp-std.workspace = true +orml-tokens = { workspace = true } [features] default = ["std"] @@ -31,13 +34,16 @@ std = [ "frame-support/std", "frame-system/std", "ggx-primitives/std", + "orml-tokens/std", "orml-traits/std", "pallet-assets/std", "pallet-balances/std", + "pallet-currencies/std", "pallet-timestamp/std", "scale-codec/std", "scale-info/std", "sp-core/std", + "sp-std/std", "sp-runtime/std", ] diff --git a/pallet/dex/src/mock.rs b/pallet/dex/src/mock.rs index 57757d14..8ddd40fa 100644 --- a/pallet/dex/src/mock.rs +++ b/pallet/dex/src/mock.rs @@ -1,16 +1,28 @@ use crate as pallet_dex; +use super::*; + use frame_support::{ pallet_prelude::Weight, parameter_types, sp_io, - traits::{AsEnsureOriginWithArg, GenesisBuild, Hooks}, + traits::{AsEnsureOriginWithArg, GenesisBuild, Hooks, Nothing}, weights::constants::RocksDbWeight, PalletId, }; -use sp_core::{ConstU128, ConstU32, ConstU64, H256}; -use sp_runtime::{testing::Header, traits::IdentityLookup}; +use ggx_primitives::currency::{CurrencyId, TokenSymbol}; +use orml_tokens::TransferDust; +use orml_traits::{currency::MutationHooks, parameter_type_with_key}; +use sp_core::{ConstU128, ConstU32, ConstU64, H160, H256}; +use sp_runtime::{ + testing::Header, + traits::{AccountIdConversion, IdentityLookup}, + AccountId32, +}; +use sp_std::marker; + +use pallet_currencies::{BasicCurrencyAdapter, NativeCurrencyOf}; -pub type AccountId = u128; +pub type AccountId = AccountId32; pub type Balance = u128; pub type AssetId = u32; pub type BlockNumber = u64; @@ -27,8 +39,10 @@ frame_support::construct_runtime!( System: frame_system, Balances: pallet_balances, Timestamp: pallet_timestamp, - Assets: pallet_assets, - Dex: pallet_dex, + Currencies: pallet_currencies, + Tokens: orml_tokens, + Assets: pallet_assets, + Dex: pallet_dex, } ); @@ -132,6 +146,104 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } +parameter_type_with_key! { + pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { + Default::default() + }; +} + +parameter_types! { + pub DustAccount: AccountId = PalletId(*b"orml/dst").into_account_truncating(); +} + +pub struct CurrencyHooks(marker::PhantomData); +impl MutationHooks + for CurrencyHooks +where + T::AccountId: From, +{ + type OnDust = orml_tokens::TransferDust; + type OnSlash = (); + type PreDeposit = (); + type PostDeposit = (); + type PreTransfer = (); + type PostTransfer = (); + type OnNewTokenAccount = (); + type OnKilledTokenAccount = (); +} + +pub type ReserveIdentifier = [u8; 8]; + +impl orml_tokens::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type Amount = i64; + type CurrencyId = CurrencyId; + type WeightInfo = (); + type ExistentialDeposits = ExistentialDeposits; + type CurrencyHooks = CurrencyHooks; + type MaxLocks = ConstU32<100_000>; + type MaxReserves = ConstU32<100_000>; + type ReserveIdentifier = ReserveIdentifier; + type DustRemovalWhitelist = Nothing; +} + +pub type NativeCurrency = NativeCurrencyOf; +pub type AdaptedBasicCurrency = BasicCurrencyAdapter; + +/// A mapping between `AccountId` and `EvmAddress`. +pub trait AddressMapping { + /// Returns the AccountId used go generate the given EvmAddress. + fn get_account_id(evm: &EvmAddress) -> AccountId; + /// Returns the EvmAddress associated with a given AccountId or the + /// underlying EvmAddress of the AccountId. + /// Returns None if there is no EvmAddress associated with the AccountId + /// and there is no underlying EvmAddress in the AccountId. + fn get_evm_address(account_id: &AccountId) -> Option; + /// Returns the EVM address associated with an account ID and generates an + /// account mapping if no association exists. + fn get_or_create_evm_address(account_id: &AccountId) -> EvmAddress; + /// Returns the default EVM address associated with an account ID. + fn get_default_evm_address(account_id: &AccountId) -> EvmAddress; + /// Returns true if a given AccountId is associated with a given EvmAddress + /// and false if is not. + fn is_linked(account_id: &AccountId, evm: &EvmAddress) -> bool; +} + +pub struct MockAddressMapping; + +impl AddressMapping for MockAddressMapping { + fn get_account_id(address: &H160) -> AccountId32 { + let mut data = [0u8; 32]; + data[0..4].copy_from_slice(b"evm:"); + data[4..24].copy_from_slice(&address[..]); + AccountId32::from(data) + } + + fn get_evm_address(account_id: &AccountId32) -> Option { + let data: [u8; 32] = account_id.clone().into(); + if data.starts_with(b"evm:") && data.ends_with(&[0u8; 8]) { + Some(H160::from_slice(&data[4..24])) + } else { + None + } + } + + fn get_default_evm_address(account_id: &AccountId32) -> H160 { + let slice: &[u8] = account_id.as_ref(); + H160::from_slice(&slice[0..20]) + } +} + +impl pallet_currencies::Config for Test { + type MultiCurrency = Tokens; + type NativeCurrency = AdaptedBasicCurrency; + type GetNativeCurrencyId = NativeCurrency; + type WeightInfo = (); + type AddressMapping = MockAddressMapping; + type EVMBridge = (); +} + parameter_types! { pub const DexPalletId: PalletId = PalletId(*b"py/sudex"); pub const UnsignedPriority: BlockNumber = 1; @@ -139,8 +251,9 @@ parameter_types! { impl pallet_dex::Config for Test { type RuntimeEvent = RuntimeEvent; + type MultiCurrency = Tokens; + type NativeCurrency = AdaptedBasicCurrency; type PalletId = DexPalletId; - type Fungibles = Assets; type PrivilegedOrigin = frame_system::EnsureRoot; type Currency = Balances; type UnsignedPriority = UnsignedPriority; @@ -195,8 +308,12 @@ impl ExtBuilder { >::assimilate_storage( &pallet_dex::GenesisConfig { - asset_ids: vec![8888, 999, 888, 777], - native_asset_id: 8888, + asset_ids: vec![ + CurrencyId::ForeignAsset(8888), + CurrencyId::ForeignAsset(999), + CurrencyId::ForeignAsset(888), + CurrencyId::ForeignAsset(777),], + native_asset_id: CurrencyId::Token(TokenSymbol::GGX), }, &mut storage, ) From eafd352fe49d43862e01a6c2168c6ef6e26cbeba Mon Sep 17 00:00:00 2001 From: Li Smith Date: Thu, 23 May 2024 19:43:11 +0800 Subject: [PATCH 12/27] fix dex mock.rs --- Cargo.lock | 7 ++ pallet/dex/Cargo.toml | 14 ++++ pallet/dex/src/mock.rs | 178 +++++++++++++++++++++++++++++------------ 3 files changed, 147 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47f2e9fe..dc874f40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8663,6 +8663,8 @@ dependencies = [ name = "pallet-dex" version = "0.1.0" dependencies = [ + "astar-primitives", + "fp-evm", "frame-support", "frame-system", "ggx-primitives", @@ -8671,8 +8673,13 @@ dependencies = [ "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "pallet-assets", "pallet-balances", + "pallet-contracts", "pallet-currencies", + "pallet-erc20", + "pallet-evm", + "pallet-insecure-randomness-collective-flip", "pallet-timestamp", + "pallet-xvm", "parity-scale-codec", "scale-info", "sp-core 7.0.0", diff --git a/pallet/dex/Cargo.toml b/pallet/dex/Cargo.toml index 39bdd579..46c6708f 100644 --- a/pallet/dex/Cargo.toml +++ b/pallet/dex/Cargo.toml @@ -20,10 +20,17 @@ sp-runtime.workspace = true sp-io.workspace = true [dev-dependencies] +astar-primitives.workspace = true +fp-evm.workspace = true pallet-assets.workspace = true pallet-balances.workspace = true +pallet-contracts.workspace = true pallet-currencies.workspace = true +pallet-erc20.workspace = true +pallet-evm.workspace = true +pallet-randomness-collective-flip.workspace = true pallet-timestamp.workspace = true +pallet-xvm.workspace = true sp-core.workspace = true sp-std.workspace = true orml-tokens = { workspace = true } @@ -31,15 +38,22 @@ orml-tokens = { workspace = true } [features] default = ["std"] std = [ + "astar-primitives/std", "frame-support/std", "frame-system/std", + "fp-evm/std", "ggx-primitives/std", "orml-tokens/std", "orml-traits/std", "pallet-assets/std", "pallet-balances/std", + "pallet-contracts/std", "pallet-currencies/std", + "pallet-erc20/std", + "pallet-evm/std", + "pallet-randomness-collective-flip/std", "pallet-timestamp/std", + "pallet-xvm/std", "scale-codec/std", "scale-info/std", "sp-core/std", diff --git a/pallet/dex/src/mock.rs b/pallet/dex/src/mock.rs index 8ddd40fa..fe52aae3 100644 --- a/pallet/dex/src/mock.rs +++ b/pallet/dex/src/mock.rs @@ -2,23 +2,30 @@ use crate as pallet_dex; use super::*; +use astar_primitives::ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}; +use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, pallet_prelude::Weight, parameter_types, sp_io, - traits::{AsEnsureOriginWithArg, GenesisBuild, Hooks, Nothing}, + traits::{AsEnsureOriginWithArg, ConstBool, GenesisBuild, Hooks, Nothing}, weights::constants::RocksDbWeight, PalletId, }; -use ggx_primitives::currency::{CurrencyId, TokenSymbol}; +use ggx_primitives::{ + currency::{CurrencyId, TokenSymbol}, + evm::EvmAddress, +}; use orml_tokens::TransferDust; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; +use pallet_evm::GasWeightMapping; use sp_core::{ConstU128, ConstU32, ConstU64, H160, H256}; use sp_runtime::{ testing::Header, traits::{AccountIdConversion, IdentityLookup}, AccountId32, }; -use sp_std::marker; +use sp_std::{cell::RefCell, marker}; use pallet_currencies::{BasicCurrencyAdapter, NativeCurrencyOf}; @@ -39,6 +46,9 @@ frame_support::construct_runtime!( System: frame_system, Balances: pallet_balances, Timestamp: pallet_timestamp, + RandomnessCollectiveFlip: pallet_randomness_collective_flip, + Contracts: pallet_contracts, + Xvm: pallet_xvm, Currencies: pallet_currencies, Tokens: orml_tokens, Assets: pallet_assets, @@ -146,6 +156,8 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } +impl pallet_randomness_collective_flip::Config for Test {} + parameter_type_with_key! { pub ExistentialDeposits: |_currency_id: CurrencyId| -> Balance { Default::default() @@ -188,60 +200,119 @@ impl orml_tokens::Config for Test { type DustRemovalWhitelist = Nothing; } -pub type NativeCurrency = NativeCurrencyOf; -pub type AdaptedBasicCurrency = BasicCurrencyAdapter; +parameter_types! { + pub const DepositPerItem: Balance = 1_000; + pub const DepositPerByte: Balance = 1_000; + pub const DefaultDepositLimit: Balance = 1_000; + pub Schedule: pallet_contracts::Schedule = Default::default(); +} -/// A mapping between `AccountId` and `EvmAddress`. -pub trait AddressMapping { - /// Returns the AccountId used go generate the given EvmAddress. - fn get_account_id(evm: &EvmAddress) -> AccountId; - /// Returns the EvmAddress associated with a given AccountId or the - /// underlying EvmAddress of the AccountId. - /// Returns None if there is no EvmAddress associated with the AccountId - /// and there is no underlying EvmAddress in the AccountId. - fn get_evm_address(account_id: &AccountId) -> Option; - /// Returns the EVM address associated with an account ID and generates an - /// account mapping if no association exists. - fn get_or_create_evm_address(account_id: &AccountId) -> EvmAddress; - /// Returns the default EVM address associated with an account ID. - fn get_default_evm_address(account_id: &AccountId) -> EvmAddress; - /// Returns true if a given AccountId is associated with a given EvmAddress - /// and false if is not. - fn is_linked(account_id: &AccountId, evm: &EvmAddress) -> bool; +impl pallet_contracts::Config for Test { + type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type DefaultDepositLimit = DefaultDepositLimit; + type CallStack = [pallet_contracts::Frame; 5]; + type WeightPrice = (); + type WeightInfo = pallet_contracts::weights::SubstrateWeight; + type ChainExtension = (); + type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; } -pub struct MockAddressMapping; +thread_local! { + static TRANSACTED: RefCell> = RefCell::new(None); +} -impl AddressMapping for MockAddressMapping { - fn get_account_id(address: &H160) -> AccountId32 { - let mut data = [0u8; 32]; - data[0..4].copy_from_slice(b"evm:"); - data[4..24].copy_from_slice(&address[..]); - AccountId32::from(data) +pub struct MockEthereumTransact; +impl MockEthereumTransact { + pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) { + let transacted = TRANSACTED.with(|v| v.borrow().clone()); + assert_eq!(transacted, Some((source, checked_tx))); + } +} +impl CheckedEthereumTransact for MockEthereumTransact { + fn xvm_transact( + source: H160, + checked_tx: CheckedEthereumTx, + ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { + TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx))); + Ok(( + PostDispatchInfo { + actual_weight: Default::default(), + pays_fee: Default::default(), + }, + EvmCallInfo { + exit_reason: ExitReason::Succeed(ExitSucceed::Returned), + value: Default::default(), + used_gas: UsedGas { + standard: Default::default(), + effective: Default::default(), + }, + logs: Default::default(), + weight_info: None, + }, + )) } +} - fn get_evm_address(account_id: &AccountId32) -> Option { - let data: [u8; 32] = account_id.clone().into(); - if data.starts_with(b"evm:") && data.ends_with(&[0u8; 8]) { - Some(H160::from_slice(&data[4..24])) - } else { - None - } +pub struct MockGasWeightMapping; +impl GasWeightMapping for MockGasWeightMapping { + fn gas_to_weight(gas: u64, _without_base_weight: bool) -> Weight { + Weight::from_parts(gas, 0) + } + fn weight_to_gas(weight: Weight) -> u64 { + weight.ref_time() } +} - fn get_default_evm_address(account_id: &AccountId32) -> H160 { - let slice: &[u8] = account_id.as_ref(); - H160::from_slice(&slice[0..20]) +impl pallet_xvm::Config for Test { + type GasWeightMapping = MockGasWeightMapping; + type AccountMapping = HashedAccountMapping; + type EthereumTransact = MockEthereumTransact; + type WeightInfo = (); +} + +parameter_types! { + pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); +} + +impl pallet_erc20::Config for Test { + type Currency = Balances; + type PalletId = ERC20PalletId; + type XvmCallApi = Xvm; +} + +///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); } } +pub type AdaptedBasicCurrency = BasicCurrencyAdapter; +parameter_types! { + pub const NativeCurrencyId: CurrencyId = CurrencyId::Token(TokenSymbol::GGX); +} + impl pallet_currencies::Config for Test { type MultiCurrency = Tokens; type NativeCurrency = AdaptedBasicCurrency; - type GetNativeCurrencyId = NativeCurrency; + type GetNativeCurrencyId = NativeCurrencyId; type WeightInfo = (); - type AddressMapping = MockAddressMapping; - type EVMBridge = (); + type AddressMapping = HashedAccountMapping; + type EVMBridge = pallet_erc20::EVMBridge; } parameter_types! { @@ -275,7 +346,10 @@ impl ExtBuilder { // This will cause some initial issuance pallet_balances::GenesisConfig:: { - balances: vec![(1, 9000), (2, 800)], + balances: vec![ + (AccountId32::from([1u8; 32]), 9000), + (AccountId32::from([2u8; 32]), 800), + ], } .assimilate_storage(&mut storage) .ok(); @@ -283,9 +357,9 @@ impl ExtBuilder { pallet_assets::GenesisConfig:: { assets: vec![ // id, owner, is_sufficient, min_balance - (999, 0, true, 1), - (888, 0, true, 1), - (777, 0, true, 1), + (999, AccountId32::from([0u8; 32]), true, 1), + (888, AccountId32::from([0u8; 32]), true, 1), + (777, AccountId32::from([0u8; 32]), true, 1), ], metadata: vec![ // id, name, symbol, decimals @@ -295,12 +369,12 @@ impl ExtBuilder { ], accounts: vec![ // id, account_id, balance - (999, 1, 1_000_000_000), - (888, 1, 1_000_000_000), - (777, 1, 1_000_000_000), - (999, 2, 1_000_000_000), - (888, 2, 1_000_000_000), - (777, 2, 1_000_000_000), + (999, AccountId32::from([1u8; 32]), 1_000_000_000), + (888, AccountId32::from([1u8; 32]), 1_000_000_000), + (777, AccountId32::from([1u8; 32]), 1_000_000_000), + (999, AccountId32::from([2u8; 32]), 1_000_000_000), + (888, AccountId32::from([2u8; 32]), 1_000_000_000), + (777, AccountId32::from([2u8; 32]), 1_000_000_000), ], } .assimilate_storage(&mut storage) From bfd6b1f04fbf261be67a7adc1715e85f32df18bd Mon Sep 17 00:00:00 2001 From: Li Smith Date: Thu, 23 May 2024 19:59:47 +0800 Subject: [PATCH 13/27] clean code for pallet-erc20 --- pallet/erc-20/src/lib.rs | 82 +--------------------------------------- 1 file changed, 1 insertion(+), 81 deletions(-) diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index c3f83800..c2c624d2 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -81,9 +81,6 @@ pub mod module { /// EvmBridge module trait #[pallet::config] pub trait Config: frame_system::Config { - //+ pallet_evm::Config - //type EVM: EVM>; - /// The currency mechanism. //todo need replace to EVM> type Currency: ReservableCurrency; @@ -269,42 +266,6 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { to: H160, value: BalanceOf, ) -> DispatchResult { - // // ERC20.transfer method hash - // let mut input = Into::::into(Action::Transfer).to_be_bytes().to_vec(); - // // append receiver address - // input.extend_from_slice(H256::from(to).as_bytes()); - // // append amount to be transferred - // input.extend_from_slice( - // H256::from_uint(&U256::from(value.saturated_into::())).as_bytes(), - // ); - - // let storage_limit = if context.origin == Default::default() { - // 0 - // } else { - // erc20::TRANSFER.storage - // }; - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::TRANSFER.gas, - // storage_limit, - // ExecutionMode::Execute, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - - // // return value is true. - // let mut bytes = [0u8; 32]; - // U256::from(1).to_big_endian(&mut bytes); - - // // Check return value to make sure not calling on empty contracts. - // ensure!( - // !info.value.is_empty() && info.value == bytes, - // Error::::InvalidReturnValue - // ); - // ############# // @dev Transfer token for a specified address // @custom:selector a9059cbb @@ -344,45 +305,4 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { } } -impl Pallet { - pub fn account_id() -> ::AccountId { - ::PalletId::get().into_account_truncating() - } - // fn handle_exit_reason(exit_reason: ExitReason) -> Result<(), DispatchError> { - // match exit_reason { - // ExitReason::Succeed(ExitSucceed::Returned) => Ok(()), - // ExitReason::Succeed(ExitSucceed::Stopped) => Ok(()), - // ExitReason::Succeed(_) => Err(Error::::ExecutionFail.into()), - // ExitReason::Revert(_) => Err(Error::::ExecutionRevert.into()), - // ExitReason::Fatal(_) => Err(Error::::ExecutionFatal.into()), - // ExitReason::Error(_) => Err(Error::::ExecutionError.into()), - // } - // } - - // fn decode_string(output: Vec) -> Result, DispatchError> { - // // output is 32-byte aligned and consists of 3 parts: - // // - part 1: 32 byte, the offset of its description is passed in the position of - // // the corresponding parameter or return value. - // // - part 2: 32 byte, string length - // // - part 3: string data - // ensure!( - // output.len() >= 64 && output.len() % 32 == 0, - // Error::::InvalidReturnValue - // ); - - // let offset = U256::from_big_endian(&output[0..32]); - // let length = U256::from_big_endian(&output[offset.as_usize()..offset.as_usize() + 32]); - // ensure!( - // // output is 32-byte aligned. ensure total_length >= offset + string length + string data length. - // output.len() >= offset.as_usize() + 32 + length.as_usize(), - // Error::::InvalidReturnValue - // ); - - // let mut data = Vec::new(); - // data.extend_from_slice( - // &output[offset.as_usize() + 32..offset.as_usize() + 32 + length.as_usize()], - // ); - - // Ok(data.to_vec()) - // } -} +impl Pallet {} From fabb133c6f3f3a5e98e48e730cc03200c71feec1 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Fri, 24 May 2024 16:30:09 +0800 Subject: [PATCH 14/27] fix currencies testcase --- Cargo.lock | 7 + pallet/currencies/Cargo.toml | 15 +++ pallet/currencies/src/mock.rs | 227 ++++++++++++++++++++++++++++----- pallet/currencies/src/tests.rs | 181 ++++---------------------- pallet/erc-20/src/lib.rs | 110 ---------------- 5 files changed, 239 insertions(+), 301 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc874f40..546d0757 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8643,6 +8643,7 @@ name = "pallet-currencies" version = "0.4.1-dev" dependencies = [ "astar-primitives", + "fp-evm", "frame-support", "frame-system", "ggx-primitives", @@ -8650,6 +8651,12 @@ dependencies = [ "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "orml-utilities 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "pallet-balances", + "pallet-contracts", + "pallet-erc20", + "pallet-evm", + "pallet-insecure-randomness-collective-flip", + "pallet-timestamp", + "pallet-xvm", "parity-scale-codec", "scale-info", "serde", diff --git a/pallet/currencies/Cargo.toml b/pallet/currencies/Cargo.toml index 7d38f501..e56f265b 100644 --- a/pallet/currencies/Cargo.toml +++ b/pallet/currencies/Cargo.toml @@ -26,7 +26,14 @@ astar-primitives = { workspace = true } ggx-primitives = { workspace = true } [dev-dependencies] +fp-evm.workspace = true pallet-balances = { workspace = true } +pallet-contracts.workspace = true +pallet-erc20.workspace = true +pallet-evm.workspace = true +pallet-randomness-collective-flip.workspace = true +pallet-timestamp.workspace = true +pallet-xvm.workspace = true sp-core = { workspace = true } orml-tokens = { workspace = true } @@ -36,11 +43,19 @@ default = ["std"] std = [ "astar-primitives/std", "serde", + "fp-evm/std", "frame-support/std", "frame-system/std", "ggx-primitives/std", + "orml-tokens/std", "orml-traits/std", "orml-utilities/std", + "pallet-contracts/std", + "pallet-erc20/std", + "pallet-evm/std", + "pallet-randomness-collective-flip/std", + "pallet-timestamp/std", + "pallet-xvm/std", "scale-codec/std", "scale-info/std", "sp-core/std", diff --git a/pallet/currencies/src/mock.rs b/pallet/currencies/src/mock.rs index 210e99cc..ec0035e9 100644 --- a/pallet/currencies/src/mock.rs +++ b/pallet/currencies/src/mock.rs @@ -3,16 +3,29 @@ #![cfg(test)] use super::*; +use astar_primitives::ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}; +use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ - construct_runtime, derive_impl, parameter_types, - traits::{ConstU32, ConstU64, Nothing}, + construct_runtime, + dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + parameter_types, + traits::{ConstBool, ConstU32, ConstU64, Nothing}, + weights::constants::RocksDbWeight, PalletId, }; +use ggx_primitives::{ + currency::{CurrencyId, TokenSymbol}, + evm::EvmAddress, +}; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; +use pallet_evm::GasWeightMapping; +use sp_core::{ConstU128, H256}; use sp_runtime::{ + testing::Header, traits::{AccountIdConversion, IdentityLookup}, AccountId32, BuildStorage, }; +use sp_std::cell::RefCell; use crate as currencies; @@ -20,32 +33,67 @@ pub type ReserveIdentifier = [u8; 8]; pub type AccountId = AccountId32; -#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] -impl frame_system::Config for Runtime { - type Block = Block; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max( + Weight::from_parts(2_000_000_000_000, u64::MAX), + ); +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = RocksDbWeight; + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type RuntimeCall = RuntimeCall; + type Hash = H256; + type Version = (); + type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; - type AccountData = pallet_balances::AccountData; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +type Balance = u128; + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<2>; + type WeightInfo = (); } -type CurrencyId = u32; -type Balance = u64; +impl pallet_randomness_collective_flip::Config for Test {} -impl pallet_balances::Config for Runtime { +impl pallet_balances::Config for Test { type Balance = Balance; type DustRemoval = (); type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU64<2>; - type AccountStore = frame_system::Pallet; - type MaxLocks = (); + type ExistentialDeposit = ConstU128<2>; + type AccountStore = System; + type WeightInfo = pallet_balances::weights::SubstrateWeight; + type MaxLocks = ConstU32<50>; type MaxReserves = ConstU32<2>; - type ReserveIdentifier = ReserveIdentifier; - type WeightInfo = (); - type FreezeIdentifier = [u8; 8]; - type MaxHolds = (); - type MaxFreezes = (); - type RuntimeHoldReason = RuntimeHoldReason; - type RuntimeFreezeReason = RuntimeFreezeReason; + type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; } parameter_type_with_key! { @@ -74,44 +122,155 @@ where type OnKilledTokenAccount = (); } -impl orml_tokens::Config for Runtime { +impl orml_tokens::Config for Test { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type Amount = i64; type CurrencyId = CurrencyId; type WeightInfo = (); type ExistentialDeposits = ExistentialDeposits; - type CurrencyHooks = CurrencyHooks; + type CurrencyHooks = CurrencyHooks; type MaxLocks = ConstU32<100_000>; type MaxReserves = ConstU32<100_000>; type ReserveIdentifier = ReserveIdentifier; type DustRemovalWhitelist = Nothing; } -pub const NATIVE_CURRENCY_ID: CurrencyId = 1; -pub const X_TOKEN_ID: CurrencyId = 2; +parameter_types! { + pub const DepositPerItem: Balance = 1_000; + pub const DepositPerByte: Balance = 1_000; + pub const DefaultDepositLimit: Balance = 1_000; + pub Schedule: pallet_contracts::Schedule = Default::default(); +} + +impl pallet_contracts::Config for Test { + type Time = Timestamp; + type Randomness = RandomnessCollectiveFlip; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type DefaultDepositLimit = DefaultDepositLimit; + type CallStack = [pallet_contracts::Frame; 5]; + type WeightPrice = (); + type WeightInfo = pallet_contracts::weights::SubstrateWeight; + type ChainExtension = (); + type Schedule = Schedule; + type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type MaxCodeLen = ConstU32<{ 123 * 1024 }>; + type MaxStorageKeyLen = ConstU32<128>; + type UnsafeUnstableInterface = ConstBool; + type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; +} + +thread_local! { + static TRANSACTED: RefCell> = RefCell::new(None); +} + +pub struct MockEthereumTransact; +impl MockEthereumTransact { + pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) { + let transacted = TRANSACTED.with(|v| v.borrow().clone()); + assert_eq!(transacted, Some((source, checked_tx))); + } +} +impl CheckedEthereumTransact for MockEthereumTransact { + fn xvm_transact( + source: H160, + checked_tx: CheckedEthereumTx, + ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { + TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx))); + Ok(( + PostDispatchInfo { + actual_weight: Default::default(), + pays_fee: Default::default(), + }, + EvmCallInfo { + exit_reason: ExitReason::Succeed(ExitSucceed::Returned), + value: Default::default(), + used_gas: UsedGas { + standard: Default::default(), + effective: Default::default(), + }, + logs: Default::default(), + weight_info: None, + }, + )) + } +} + +pub struct MockGasWeightMapping; +impl GasWeightMapping for MockGasWeightMapping { + fn gas_to_weight(gas: u64, _without_base_weight: bool) -> Weight { + Weight::from_parts(gas, 0) + } + fn weight_to_gas(weight: Weight) -> u64 { + weight.ref_time() + } +} + +impl pallet_xvm::Config for Test { + type GasWeightMapping = MockGasWeightMapping; + type AccountMapping = HashedAccountMapping; + type EthereumTransact = MockEthereumTransact; + type WeightInfo = (); +} + +parameter_types! { + pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); +} + +impl pallet_erc20::Config for Test { + type Currency = Balances; + type PalletId = ERC20PalletId; + type XvmCallApi = Xvm; +} + +///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. +pub struct HashedAccountMapping; +impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + } +} + +pub const NATIVE_CURRENCY_ID: CurrencyId = ggx_primitives::currency::CurrencyId::ForeignAsset(1); +pub const X_TOKEN_ID: CurrencyId = ggx_primitives::currency::CurrencyId::ForeignAsset(2); parameter_types! { pub const GetNativeCurrencyId: CurrencyId = NATIVE_CURRENCY_ID; } -impl Config for Runtime { +impl Config for Test { type MultiCurrency = Tokens; type NativeCurrency = AdaptedBasicCurrency; type GetNativeCurrencyId = GetNativeCurrencyId; type WeightInfo = (); + type AddressMapping = HashedAccountMapping; + type EVMBridge = pallet_erc20::EVMBridge; } -pub type NativeCurrency = NativeCurrencyOf; -pub type AdaptedBasicCurrency = BasicCurrencyAdapter; +pub type NativeCurrency = NativeCurrencyOf; +pub type AdaptedBasicCurrency = BasicCurrencyAdapter; -type Block = frame_system::mocking::MockBlock; +type Block = frame_system::mocking::MockBlock; -construct_runtime!( - pub enum Runtime { +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { System: frame_system, + Timestamp: pallet_timestamp, Currencies: currencies, Tokens: orml_tokens, - PalletBalances: pallet_balances, + Balances: pallet_balances, + RandomnessCollectiveFlip: pallet_randomness_collective_flip, + Contracts: pallet_contracts, + Xvm: pallet_xvm, } ); @@ -143,11 +302,11 @@ impl ExtBuilder { } pub fn build(self) -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default() - .build_storage() + let mut t = frame_system::GenesisConfig::default() + .build_storage::() .unwrap(); - pallet_balances::GenesisConfig:: { + pallet_balances::GenesisConfig:: { balances: self .balances .clone() @@ -159,7 +318,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - orml_tokens::GenesisConfig:: { + orml_tokens::GenesisConfig:: { balances: self .balances .into_iter() diff --git a/pallet/currencies/src/tests.rs b/pallet/currencies/src/tests.rs index 88bc4981..56e448b2 100644 --- a/pallet/currencies/src/tests.rs +++ b/pallet/currencies/src/tests.rs @@ -16,7 +16,7 @@ fn multi_lockable_currency_should_work() { assert_ok!(Currencies::set_lock(ID_1, X_TOKEN_ID, &ALICE, 50)); assert_eq!(Tokens::locks(&ALICE, X_TOKEN_ID).len(), 1); assert_ok!(Currencies::set_lock(ID_1, NATIVE_CURRENCY_ID, &ALICE, 50)); - assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + assert_eq!(Balances::locks(&ALICE).len(), 1); }); } @@ -38,104 +38,6 @@ fn multi_reservable_currency_should_work() { }); } -#[test] -fn named_multi_reservable_currency_should_work() { - ExtBuilder::default() - .one_hundred_for_alice_n_bob() - .build() - .execute_with(|| { - assert_eq!(Currencies::total_issuance(NATIVE_CURRENCY_ID), 200); - assert_eq!(Currencies::total_issuance(X_TOKEN_ID), 200); - assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), 100); - assert_eq!(NativeCurrency::free_balance(&ALICE), 100); - - assert_ok!(Currencies::reserve_named(&RID_1, X_TOKEN_ID, &ALICE, 30)); - assert_ok!(Currencies::reserve_named(&RID_2, X_TOKEN_ID, &ALICE, 50)); - assert_ok!(Currencies::reserve_named( - &RID_1, - NATIVE_CURRENCY_ID, - &ALICE, - 20 - )); - assert_ok!(Currencies::reserve_named( - &RID_2, - NATIVE_CURRENCY_ID, - &ALICE, - 60 - )); - let r1x_before = 30; - assert_eq!( - Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), - r1x_before - ); - let r2x_before = 50; - assert_eq!( - Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), - r2x_before - ); - let r1n_before = 20; - assert_eq!( - Currencies::reserved_balance_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE), - r1n_before - ); - let r2n_before = 60; - assert_eq!( - Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), - r2n_before - ); - - let n_free_before = 20; - assert_eq!(NativeCurrency::free_balance(&ALICE), n_free_before); - let x_free_before = 20; - assert_eq!(Currencies::free_balance(X_TOKEN_ID, &ALICE), x_free_before); - - assert_eq!( - Currencies::unreserve_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE, 100), - 80 - ); - assert_eq!(NativeCurrency::free_balance(&ALICE), n_free_before + 20); - assert_eq!( - Currencies::reserved_balance_named(&RID_1, NATIVE_CURRENCY_ID, &ALICE), - 0 - ); - - assert_eq!( - Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), - r2n_before - ); - assert_eq!( - Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), - r1x_before - ); - assert_eq!( - Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), - r2x_before - ); - - assert_eq!( - Currencies::unreserve_named(&RID_1, X_TOKEN_ID, &ALICE, 100), - 70 - ); - assert_eq!( - Currencies::free_balance(X_TOKEN_ID, &ALICE), - x_free_before + 30 - ); - assert_eq!( - Currencies::reserved_balance_named(&RID_1, X_TOKEN_ID, &ALICE), - 0 - ); - - assert_eq!( - Currencies::reserved_balance_named(&RID_2, X_TOKEN_ID, &ALICE), - r2x_before - ); - assert_eq!( - Currencies::reserved_balance_named(&RID_2, NATIVE_CURRENCY_ID, &ALICE), - r2n_before - ); - }); -} - #[test] fn native_currency_lockable_should_work() { ExtBuilder::default() @@ -143,9 +45,9 @@ fn native_currency_lockable_should_work() { .build() .execute_with(|| { assert_ok!(NativeCurrency::set_lock(ID_1, &ALICE, 10)); - assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + assert_eq!(Balances::locks(&ALICE).len(), 1); assert_ok!(NativeCurrency::remove_lock(ID_1, &ALICE)); - assert_eq!(PalletBalances::locks(&ALICE).len(), 0); + assert_eq!(Balances::locks(&ALICE).len(), 0); }); } @@ -167,9 +69,9 @@ fn basic_currency_adapting_pallet_balances_lockable() { .build() .execute_with(|| { assert_ok!(AdaptedBasicCurrency::set_lock(ID_1, &ALICE, 10)); - assert_eq!(PalletBalances::locks(&ALICE).len(), 1); + assert_eq!(Balances::locks(&ALICE).len(), 1); assert_ok!(AdaptedBasicCurrency::remove_lock(ID_1, &ALICE)); - assert_eq!(PalletBalances::locks(&ALICE).len(), 0); + assert_eq!(Balances::locks(&ALICE).len(), 0); }); } @@ -184,41 +86,6 @@ fn basic_currency_adapting_pallet_balances_reservable() { }); } -#[test] -fn named_basic_currency_adapting_pallet_balances_reservable() { - ExtBuilder::default() - .one_hundred_for_alice_n_bob() - .build() - .execute_with(|| { - assert_ok!(AdaptedBasicCurrency::reserve_named(&RID_1, &ALICE, 50)); - assert_ok!(AdaptedBasicCurrency::reserve_named(&RID_2, &ALICE, 30)); - assert_eq!( - AdaptedBasicCurrency::reserved_balance_named(&RID_1, &ALICE), - 50 - ); - assert_eq!( - AdaptedBasicCurrency::reserved_balance_named(&RID_2, &ALICE), - 30 - ); - assert_eq!(AdaptedBasicCurrency::free_balance(&ALICE), 20); - - assert_eq!( - AdaptedBasicCurrency::unreserve_named(&RID_1, &ALICE, 80), - 30 - ); - assert_eq!(AdaptedBasicCurrency::free_balance(&ALICE), 70); - assert_eq!( - AdaptedBasicCurrency::reserved_balance_named(&RID_1, &ALICE), - 0 - ); - - assert_eq!( - AdaptedBasicCurrency::reserved_balance_named(&RID_2, &ALICE), - 30 - ); - }); -} - #[test] fn multi_currency_should_work() { ExtBuilder::default() @@ -302,13 +169,13 @@ fn basic_currency_adapting_pallet_balances_transfer() { .build() .execute_with(|| { assert_ok!(AdaptedBasicCurrency::transfer(&ALICE, &BOB, 50)); - assert_eq!(PalletBalances::total_balance(&ALICE), 50); - assert_eq!(PalletBalances::total_balance(&BOB), 150); + assert_eq!(Balances::total_balance(&ALICE), 50); + assert_eq!(Balances::total_balance(&BOB), 150); // creation fee assert_ok!(AdaptedBasicCurrency::transfer(&ALICE, &EVA, 10)); - assert_eq!(PalletBalances::total_balance(&ALICE), 40); - assert_eq!(PalletBalances::total_balance(&EVA), 10); + assert_eq!(Balances::total_balance(&ALICE), 40); + assert_eq!(Balances::total_balance(&EVA), 10); }); } @@ -319,8 +186,8 @@ fn basic_currency_adapting_pallet_balances_deposit() { .build() .execute_with(|| { assert_ok!(AdaptedBasicCurrency::deposit(&EVA, 50)); - assert_eq!(PalletBalances::total_balance(&EVA), 50); - assert_eq!(PalletBalances::total_issuance(), 250); + assert_eq!(Balances::total_balance(&EVA), 50); + assert_eq!(Balances::total_issuance(), 250); }); } @@ -331,17 +198,17 @@ fn basic_currency_adapting_pallet_balances_deposit_throw_error_when_actual_depos .one_hundred_for_alice_n_bob() .build() .execute_with(|| { - assert_eq!(PalletBalances::total_balance(&EVA), 0); - assert_eq!(PalletBalances::total_issuance(), 200); + assert_eq!(Balances::total_balance(&EVA), 0); + assert_eq!(Balances::total_issuance(), 200); assert_noop!( AdaptedBasicCurrency::deposit(&EVA, 1), - Error::::DepositFailed + Error::::DepositFailed ); - assert_eq!(PalletBalances::total_balance(&EVA), 0); - assert_eq!(PalletBalances::total_issuance(), 200); + assert_eq!(Balances::total_balance(&EVA), 0); + assert_eq!(Balances::total_issuance(), 200); assert_ok!(AdaptedBasicCurrency::deposit(&EVA, 2)); - assert_eq!(PalletBalances::total_balance(&EVA), 2); - assert_eq!(PalletBalances::total_issuance(), 202); + assert_eq!(Balances::total_balance(&EVA), 2); + assert_eq!(Balances::total_issuance(), 202); }); } @@ -352,8 +219,8 @@ fn basic_currency_adapting_pallet_balances_withdraw() { .build() .execute_with(|| { assert_ok!(AdaptedBasicCurrency::withdraw(&ALICE, 100)); - assert_eq!(PalletBalances::total_balance(&ALICE), 0); - assert_eq!(PalletBalances::total_issuance(), 100); + assert_eq!(Balances::total_balance(&ALICE), 0); + assert_eq!(Balances::total_issuance(), 100); }); } @@ -364,8 +231,8 @@ fn basic_currency_adapting_pallet_balances_slash() { .build() .execute_with(|| { assert_eq!(AdaptedBasicCurrency::slash(&ALICE, 101), 1); - assert_eq!(PalletBalances::total_balance(&ALICE), 0); - assert_eq!(PalletBalances::total_issuance(), 100); + assert_eq!(Balances::total_balance(&ALICE), 0); + assert_eq!(Balances::total_issuance(), 100); }); } @@ -376,8 +243,8 @@ fn basic_currency_adapting_pallet_balances_update_balance() { .build() .execute_with(|| { assert_ok!(AdaptedBasicCurrency::update_balance(&ALICE, -10)); - assert_eq!(PalletBalances::total_balance(&ALICE), 90); - assert_eq!(PalletBalances::total_issuance(), 190); + assert_eq!(Balances::total_balance(&ALICE), 90); + assert_eq!(Balances::total_issuance(), 190); }); } diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index c2c624d2..5a95a910 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -121,140 +121,30 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { // Calls the name method on an ERC20 contract using the given context // and returns the token name. fn name(context: Context) -> Result, DispatchError> { - // // ERC20.name method hash - // let input = Into::::into(Action::Name).to_be_bytes().to_vec(); - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::NAME.gas, - // erc20::NAME.storage, - // ExecutionMode::View, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - // Pallet::::decode_string(info.value.as_slice().to_vec()) - - // let context = Context { - // source_vm_id: VmId::Wasm, - // weight_limit: Weight::from_parts(1_000_000, 1_000_000), - // }; - // let vm_id = VmId::Evm; - // let target = H160::repeat_byte(0xFF); - // let input = vec![1; 65_536]; - // let value = 1_000_000u128; - - // T::XvmCallApi::call( - // context, - // vm_id, - // T::account_id(), //ALICE, - // target.encode(), - // input.clone(), - // value, - // None, - // ); - Ok(vec![]) } // Calls the symbol method on an ERC20 contract using the given context // and returns the token symbol. fn symbol(context: Context) -> Result, DispatchError> { - // ERC20.symbol method hash - // let input = Into::::into(Action::Symbol).to_be_bytes().to_vec(); - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::SYMBOL.gas, - // erc20::SYMBOL.storage, - // ExecutionMode::View, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - // Pallet::::decode_string(info.value.as_slice().to_vec()) Ok(vec![]) } // Calls the decimals method on an ERC20 contract using the given context // and returns the decimals. fn decimals(context: Context) -> Result { - // ERC20.decimals method hash - // let input = Into::::into(Action::Decimals).to_be_bytes().to_vec(); - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::DECIMALS.gas, - // erc20::DECIMALS.storage, - // ExecutionMode::View, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - - // ensure!(info.value.len() == 32, Error::::InvalidReturnValue); - // let value: u8 = U256::from(info.value.as_slice()) - // .try_into() - // .map_err(|_| ArithmeticError::Overflow)?; - // Ok(value) Ok(0) } // Calls the totalSupply method on an ERC20 contract using the given context // and returns the total supply. fn total_supply(context: Context) -> Result, DispatchError> { - // ERC20.totalSupply method hash - // let input = Into::::into(Action::TotalSupply) - // .to_be_bytes() - // .to_vec(); - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::TOTAL_SUPPLY.gas, - // erc20::TOTAL_SUPPLY.storage, - // ExecutionMode::View, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - - // ensure!(info.value.len() == 32, Error::::InvalidReturnValue); - // let value: u128 = U256::from(info.value.as_slice()) - // .try_into() - // .map_err(|_| ArithmeticError::Overflow)?; - // let supply = value.try_into().map_err(|_| ArithmeticError::Overflow)?; - // Ok(supply) Ok(Default::default()) } // Calls the balanceOf method on an ERC20 contract using the given context // and returns the address's balance. fn balance_of(context: Context, address: H160) -> Result, DispatchError> { - // // ERC20.balanceOf method hash - // let mut input = Into::::into(Action::BalanceOf).to_be_bytes().to_vec(); - // // append address - // input.extend_from_slice(H256::from(address).as_bytes()); - - // let info = T::EVM::execute( - // context, - // input, - // Default::default(), - // erc20::BALANCE_OF.gas, - // erc20::BALANCE_OF.storage, - // ExecutionMode::View, - // )?; - - // Pallet::::handle_exit_reason(info.exit_reason)?; - - // let value: u128 = U256::from(info.value.as_slice()) - // .try_into() - // .map_err(|_| ArithmeticError::Overflow)?; - // let balance = value.try_into().map_err(|_| ArithmeticError::Overflow)?; - // Ok(balance) Ok(Default::default()) } From 5722aa01b2eccd62d7805b5aaabfb41480d07466 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Fri, 24 May 2024 18:51:33 +0800 Subject: [PATCH 15/27] fix dex testcase --- pallet/dex/src/mock.rs | 54 ++++-- pallet/dex/src/tests.rs | 384 +++++++++++++++++++------------------ pallet/erc-20/src/lib.rs | 7 +- primitives/src/currency.rs | 5 +- 4 files changed, 243 insertions(+), 207 deletions(-) diff --git a/pallet/dex/src/mock.rs b/pallet/dex/src/mock.rs index fe52aae3..c13ef6c1 100644 --- a/pallet/dex/src/mock.rs +++ b/pallet/dex/src/mock.rs @@ -27,7 +27,7 @@ use sp_runtime::{ }; use sp_std::{cell::RefCell, marker}; -use pallet_currencies::{BasicCurrencyAdapter, NativeCurrencyOf}; +use pallet_currencies::BasicCurrencyAdapter; pub type AccountId = AccountId32; pub type Balance = u128; @@ -330,6 +330,15 @@ impl pallet_dex::Config for Test { type UnsignedPriority = UnsignedPriority; } +pub const ALICE: AccountId = AccountId32::new([1u8; 32]); +pub const BOB: AccountId = AccountId32::new([2u8; 32]); + +pub const NATIVE_CURRENCY_ID: CurrencyId = CurrencyId::Token(TokenSymbol::GGX); +pub const USDT: CurrencyId = CurrencyId::Token(TokenSymbol::USDT); +pub const GGXT: CurrencyId = CurrencyId::Token(TokenSymbol::GGXT); +pub const BTC: CurrencyId = CurrencyId::Token(TokenSymbol::BTC); +pub const DOT: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); + pub struct ExtBuilder; impl Default for ExtBuilder { @@ -346,10 +355,7 @@ impl ExtBuilder { // This will cause some initial issuance pallet_balances::GenesisConfig:: { - balances: vec![ - (AccountId32::from([1u8; 32]), 9000), - (AccountId32::from([2u8; 32]), 800), - ], + balances: vec![(ALICE, 9000), (BOB, 800)], } .assimilate_storage(&mut storage) .ok(); @@ -369,25 +375,49 @@ impl ExtBuilder { ], accounts: vec![ // id, account_id, balance - (999, AccountId32::from([1u8; 32]), 1_000_000_000), - (888, AccountId32::from([1u8; 32]), 1_000_000_000), - (777, AccountId32::from([1u8; 32]), 1_000_000_000), - (999, AccountId32::from([2u8; 32]), 1_000_000_000), - (888, AccountId32::from([2u8; 32]), 1_000_000_000), - (777, AccountId32::from([2u8; 32]), 1_000_000_000), + (999, ALICE, 1_000_000_000), + (888, ALICE, 1_000_000_000), + (777, ALICE, 1_000_000_000), + (999, BOB, 1_000_000_000), + (888, BOB, 1_000_000_000), + (777, BOB, 1_000_000_000), ], } .assimilate_storage(&mut storage) .ok(); + let tokens = vec![ + (ALICE, NATIVE_CURRENCY_ID, 1_000_000_000), + (BOB, NATIVE_CURRENCY_ID, 1_000_000_000), + (ALICE, USDT, 1_000_000_000), + (BOB, USDT, 1_000_000_000), + (ALICE, GGXT, 1_000_000_000), + (BOB, GGXT, 1_000_000_000), + (ALICE, BTC, 1_000_000_000), + (BOB, BTC, 1_000_000_000), + ]; + + orml_tokens::GenesisConfig:: { + balances: tokens + .into_iter() + .filter(|(_, currency_id, _)| *currency_id != NATIVE_CURRENCY_ID) + .collect::>(), + } + .assimilate_storage(&mut storage) + .unwrap(); + >::assimilate_storage( &pallet_dex::GenesisConfig { asset_ids: vec![ + BTC, + GGXT, + USDT, + NATIVE_CURRENCY_ID, CurrencyId::ForeignAsset(8888), CurrencyId::ForeignAsset(999), CurrencyId::ForeignAsset(888), CurrencyId::ForeignAsset(777),], - native_asset_id: CurrencyId::Token(TokenSymbol::GGX), + native_asset_id: NATIVE_CURRENCY_ID, }, &mut storage, ) diff --git a/pallet/dex/src/tests.rs b/pallet/dex/src/tests.rs index a3a252a9..3876be59 100644 --- a/pallet/dex/src/tests.rs +++ b/pallet/dex/src/tests.rs @@ -11,13 +11,13 @@ use sp_core::offchain::{ fn test_deposit() { new_test_ext().execute_with(|| { assert_noop!( - Dex::deposit(RuntimeOrigin::signed(1), 666, 10), + Dex::deposit(RuntimeOrigin::signed(ALICE), DOT, 10), Error::::AssetIdNotInTokenIndex ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 10)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 10)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 10, reserved: 0 @@ -30,13 +30,13 @@ fn test_deposit() { fn test_withdraw() { new_test_ext().execute_with(|| { assert_noop!( - Dex::withdraw(RuntimeOrigin::signed(1), 777, 10), + Dex::withdraw(RuntimeOrigin::signed(ALICE), USDT, 10), Error::::AssetIdNotInTokenInfoes ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 10)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 10)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 10, reserved: 0 @@ -44,13 +44,13 @@ fn test_withdraw() { ); assert_noop!( - Dex::withdraw(RuntimeOrigin::signed(1), 777, 11), + Dex::withdraw(RuntimeOrigin::signed(ALICE), USDT, 11), Error::::NotEnoughBalance ); - assert_ok!(Dex::withdraw(RuntimeOrigin::signed(1), 777, 10)); + assert_ok!(Dex::withdraw(RuntimeOrigin::signed(ALICE), USDT, 10)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 0, reserved: 0 @@ -62,20 +62,20 @@ fn test_withdraw() { #[test] fn test_deposit_native() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(1), 9000); + assert_eq!(Balances::free_balance(ALICE), 9000); - assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(1), 10)); + assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(ALICE), 10)); assert_eq!( - UserTokenInfoes::::get(1, NativeAssetId::::get()), + UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { amount: 10, reserved: 0 } ); - assert_eq!(Balances::free_balance(1), 8990); + assert_eq!(Balances::free_balance(ALICE), 8990); assert_eq!( - UserTokenInfoes::::get(1, NativeAssetId::::get()), + UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { amount: 10, reserved: 0 @@ -87,18 +87,18 @@ fn test_deposit_native() { #[test] fn test_withdraw_native() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(1), 9000); + assert_eq!(Balances::free_balance(ALICE), 9000); assert_noop!( - Dex::withdraw_native(RuntimeOrigin::signed(1), 10), + Dex::withdraw_native(RuntimeOrigin::signed(ALICE), 10), Error::::AssetIdNotInTokenInfoes ); - assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(1), 10)); + assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(ALICE), 10)); - assert_eq!(Balances::free_balance(1), 8990); + assert_eq!(Balances::free_balance(ALICE), 8990); assert_eq!( - UserTokenInfoes::::get(1, NativeAssetId::::get()), + UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { amount: 10, reserved: 0 @@ -106,15 +106,15 @@ fn test_withdraw_native() { ); assert_noop!( - Dex::withdraw_native(RuntimeOrigin::signed(1), 11), + Dex::withdraw_native(RuntimeOrigin::signed(ALICE), 11), Error::::NotEnoughBalance ); - assert_ok!(Dex::withdraw_native(RuntimeOrigin::signed(1), 10)); + assert_ok!(Dex::withdraw_native(RuntimeOrigin::signed(ALICE), 10)); - assert_eq!(Balances::free_balance(1), 9000); + assert_eq!(Balances::free_balance(ALICE), 9000); assert_eq!( - UserTokenInfoes::::get(1, NativeAssetId::::get()), + UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { amount: 0, reserved: 0 @@ -126,13 +126,13 @@ fn test_withdraw_native() { #[test] fn test_make_order() { new_test_ext().execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 100)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 100)); assert_noop!( Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 777, + RuntimeOrigin::signed(ALICE), + USDT, + USDT, 1, 200, 200, @@ -144,9 +144,9 @@ fn test_make_order() { assert_noop!( Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1, 200, 1, @@ -158,9 +158,9 @@ fn test_make_order() { assert_noop!( Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1, 200, 1, @@ -171,7 +171,7 @@ fn test_make_order() { ); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 100, reserved: 0, @@ -179,9 +179,9 @@ fn test_make_order() { ); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1, 200, 200, @@ -193,8 +193,8 @@ fn test_make_order() { Orders::::get(0), Some(Order { counter: 0, - address: 1, - pair: (777, 888), + address: ALICE, + pair: (USDT, GGXT), expiration_block: 1000, amount_offered: 1, amout_requested: 200, @@ -206,12 +206,12 @@ fn test_make_order() { }) ); - assert_eq!(UserOrders::::get(1, 0), ()); + assert_eq!(UserOrders::::get(ALICE, 0), ()); - assert_eq!(PairOrders::::get((777, 888)), vec![0]); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![0]); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 99, reserved: 1, @@ -223,11 +223,11 @@ fn test_make_order() { #[test] fn test_make_order_asset_id_1_gt_asset_id_2() { new_test_ext().execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 100)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 100)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), GGXT, 200)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 100, reserved: 0, @@ -235,7 +235,7 @@ fn test_make_order_asset_id_1_gt_asset_id_2() { ); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 200, reserved: 0, @@ -243,9 +243,9 @@ fn test_make_order_asset_id_1_gt_asset_id_2() { ); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 888, - 777, + RuntimeOrigin::signed(ALICE), + GGXT, + USDT, 200, 1, 200, @@ -257,8 +257,8 @@ fn test_make_order_asset_id_1_gt_asset_id_2() { Orders::::get(0), Some(Order { counter: 0, - address: 1, - pair: (777, 888), + address: ALICE, + pair: (USDT, GGXT), expiration_block: 1000, amount_offered: 200, amout_requested: 1, @@ -270,12 +270,12 @@ fn test_make_order_asset_id_1_gt_asset_id_2() { }) ); - assert_eq!(UserOrders::::get(1, 0), ()); + assert_eq!(UserOrders::::get(ALICE, 0), ()); - assert_eq!(PairOrders::::get((777, 888)), vec![0]); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![0]); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 0, reserved: 200, @@ -288,15 +288,15 @@ fn test_make_order_asset_id_1_gt_asset_id_2() { fn test_cancel_order() { new_test_ext().execute_with(|| { assert_noop!( - Dex::cancel_order(RuntimeOrigin::signed(1), 0), + Dex::cancel_order(RuntimeOrigin::signed(ALICE), 0), Error::::InvalidOrderIndex ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 100)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 100)); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1, 200, 200, @@ -308,8 +308,8 @@ fn test_cancel_order() { Orders::::get(0), Some(Order { counter: 0, - address: 1, - pair: (777, 888), + address: ALICE, + pair: (USDT, GGXT), expiration_block: 1000, amount_offered: 1, amout_requested: 200, @@ -320,30 +320,30 @@ fn test_cancel_order() { order_status: OrderStatus::Pending, }) ); - assert_eq!(UserOrders::::contains_key(1, 0), true); - assert_eq!(PairOrders::::get((777, 888)), vec![0]); + assert_eq!(UserOrders::::contains_key(ALICE, 0), true); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![0]); assert_noop!( - Dex::cancel_order(RuntimeOrigin::signed(2), 0), + Dex::cancel_order(RuntimeOrigin::signed(BOB), 0), Error::::NotOwner ); - assert_ok!(Dex::cancel_order(RuntimeOrigin::signed(1), 0)); + assert_ok!(Dex::cancel_order(RuntimeOrigin::signed(ALICE), 0)); assert_eq!(Orders::::get(0), None); - assert_eq!(UserOrders::::contains_key(1, 1), false); - assert_eq!(PairOrders::::get((777, 888)), vec![]); + assert_eq!(UserOrders::::contains_key(ALICE, 1), false); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![]); }) } #[test] fn test_take_order_sell() { new_test_ext().execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 100)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 100)); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1, 200, 200, @@ -352,72 +352,72 @@ fn test_take_order_sell() { )); assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::UserAssetNotExist ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 888, 100)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), GGXT, 100)); assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::NotEnoughBalance ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 888, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), GGXT, 200)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 99, reserved: 1, } ); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 0, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 777), + UserTokenInfoes::::get(BOB, USDT), TokenInfo { amount: 0, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 888), + UserTokenInfoes::::get(BOB, GGXT), TokenInfo { amount: 300, reserved: 0, } ); - assert_ok!(Dex::take_order(RuntimeOrigin::signed(2), 0)); + assert_ok!(Dex::take_order(RuntimeOrigin::signed(BOB), 0)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 99, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 200, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 777), + UserTokenInfoes::::get(BOB, USDT), TokenInfo { amount: 1, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 888), + UserTokenInfoes::::get(BOB, GGXT), TokenInfo { amount: 100, reserved: 0, @@ -430,15 +430,15 @@ fn test_take_order_sell() { fn test_take_order_buy() { new_test_ext().execute_with(|| { assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::InvalidOrderIndex ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), GGXT, 200)); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 200, 200, 1, @@ -447,72 +447,72 @@ fn test_take_order_buy() { )); assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::UserAssetNotExist ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 777, 1)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), USDT, 1)); assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::NotEnoughBalance ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 777, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), USDT, 200)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 0, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 0, reserved: 200, } ); assert_eq!( - UserTokenInfoes::::get(2, 777), + UserTokenInfoes::::get(BOB, USDT), TokenInfo { amount: 201, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 888), + UserTokenInfoes::::get(BOB, GGXT), TokenInfo { amount: 0, reserved: 0, } ); - assert_ok!(Dex::take_order(RuntimeOrigin::signed(2), 0)); + assert_ok!(Dex::take_order(RuntimeOrigin::signed(BOB), 0)); assert_eq!( - UserTokenInfoes::::get(1, 777), + UserTokenInfoes::::get(ALICE, USDT), TokenInfo { amount: 200, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(1, 888), + UserTokenInfoes::::get(ALICE, GGXT), TokenInfo { amount: 0, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 777), + UserTokenInfoes::::get(BOB, USDT), TokenInfo { amount: 1, reserved: 0, } ); assert_eq!( - UserTokenInfoes::::get(2, 888), + UserTokenInfoes::::get(BOB, GGXT), TokenInfo { amount: 200, reserved: 0, @@ -525,17 +525,17 @@ fn test_take_order_buy() { fn test_make_cancel_take_order_buy() { new_test_ext().execute_with(|| { assert_noop!( - Dex::take_order(RuntimeOrigin::signed(2), 0), + Dex::take_order(RuntimeOrigin::signed(BOB), 0), Error::::InvalidOrderIndex ); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 999, 200)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 500)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), BTC, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), GGXT, 500)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), USDT, 200)); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 100, 1, 100, @@ -544,9 +544,9 @@ fn test_make_cancel_take_order_buy() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 200, 2, 100, @@ -555,9 +555,9 @@ fn test_make_cancel_take_order_buy() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 888, - 999, + RuntimeOrigin::signed(ALICE), + GGXT, + BTC, 2, 200, 100, @@ -565,42 +565,42 @@ fn test_make_cancel_take_order_buy() { 1000 )); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 999, 300)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 888, 300)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(2), 777, 300)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), BTC, 300)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), GGXT, 300)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(BOB), USDT, 300)); assert_eq!(Orders::::contains_key(0), true); assert_eq!(Orders::::contains_key(1), true); assert_eq!(Orders::::contains_key(2), true); - assert_eq!(UserOrders::::contains_key(1, 0), true); - assert_eq!(UserOrders::::contains_key(1, 1), true); - assert_eq!(UserOrders::::contains_key(1, 2), true); - assert_eq!(PairOrders::::get((777, 888)), vec![0, 1]); - assert_eq!(PairOrders::::get((888, 999)), vec![2]); + assert_eq!(UserOrders::::contains_key(ALICE, 0), true); + assert_eq!(UserOrders::::contains_key(ALICE, 1), true); + assert_eq!(UserOrders::::contains_key(ALICE, 2), true); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![0, 1]); + assert_eq!(PairOrders::::get((GGXT, BTC)), vec![2]); - assert_ok!(Dex::cancel_order(RuntimeOrigin::signed(1), 1)); - assert_ok!(Dex::take_order(RuntimeOrigin::signed(2), 0)); + assert_ok!(Dex::cancel_order(RuntimeOrigin::signed(ALICE), 1)); + assert_ok!(Dex::take_order(RuntimeOrigin::signed(BOB), 0)); assert_eq!(Orders::::contains_key(0), false); assert_eq!(Orders::::contains_key(1), false); assert_eq!(Orders::::contains_key(2), true); - assert_eq!(UserOrders::::contains_key(1, 0), false); - assert_eq!(UserOrders::::contains_key(1, 1), false); - assert_eq!(UserOrders::::contains_key(1, 2), true); - assert_eq!(PairOrders::::get((777, 888)), vec![]); - assert_eq!(PairOrders::::get((888, 999)), vec![2]); + assert_eq!(UserOrders::::contains_key(ALICE, 0), false); + assert_eq!(UserOrders::::contains_key(ALICE, 1), false); + assert_eq!(UserOrders::::contains_key(ALICE, 2), true); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![]); + assert_eq!(PairOrders::::get((GGXT, BTC)), vec![2]); }) } #[test] fn test_expiration_works_as_expected() { new_test_ext().execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), GGXT, 200)); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 100, 1, 100, @@ -609,14 +609,14 @@ fn test_expiration_works_as_expected() { )); assert_eq!(Orders::::contains_key(0), true); - assert_eq!(UserOrders::::contains_key(1, 0), true); - assert_eq!(PairOrders::::get((777, 888)), vec![0]); + assert_eq!(UserOrders::::contains_key(ALICE, 0), true); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![0]); assert_eq!( Orders::::get(0), Some(Order { counter: 0, - address: 1, - pair: (777, 888), + address: ALICE, + pair: (USDT, GGXT), expiration_block: 10, amount_offered: 100, amout_requested: 1, @@ -632,8 +632,8 @@ fn test_expiration_works_as_expected() { run_to_block(11); assert!(!Orders::::contains_key(0)); - assert!(!UserOrders::::contains_key(1, 0)); - assert_eq!(PairOrders::::get((777, 888)), vec![]); + assert!(!UserOrders::::contains_key(ALICE, 0)); + assert_eq!(PairOrders::::get((USDT, GGXT)), vec![]); assert_eq!(OrderExpiration::::get(10), vec![]); }); } @@ -641,14 +641,14 @@ fn test_expiration_works_as_expected() { #[test] fn fail_on_invalid_expiry() { new_test_ext().execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 200)); + assert_ok!(Dex::deposit(RuntimeOrigin::signed(ALICE), GGXT, 200)); run_to_block(5); assert_noop!( Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 100, 1, 100, @@ -659,9 +659,9 @@ fn fail_on_invalid_expiry() { ); assert_noop!( Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 100, 1, 100, @@ -672,9 +672,9 @@ fn fail_on_invalid_expiry() { ); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 100, 1, 100, @@ -733,16 +733,24 @@ fn test_offchain_worker_order_matching() { ext.register_extension(TransactionPoolExt::new(pool)); ext.execute_with(|| { - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 777, 1_000_000_000)); - assert_ok!(Dex::deposit(RuntimeOrigin::signed(1), 888, 1_000_000_000)); + assert_ok!(Dex::deposit( + RuntimeOrigin::signed(ALICE), + USDT, + 1_000_000_000 + )); + assert_ok!(Dex::deposit( + RuntimeOrigin::signed(ALICE), + GGXT, + 1_000_000_000 + )); let block = 1; System::set_block_number(block); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 208234, 1, 208234, @@ -751,9 +759,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 2, 417520, 208760, @@ -764,9 +772,9 @@ fn test_offchain_worker_order_matching() { Dex::offchain_worker(block); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 208780, 1, 208780, @@ -775,9 +783,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1042505, 5, 208501, @@ -786,9 +794,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 3, 626406, 208802, @@ -799,9 +807,9 @@ fn test_offchain_worker_order_matching() { Dex::offchain_worker(block); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 6, 1252560, 208760, @@ -810,9 +818,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 1456777, 7, 208111, @@ -821,9 +829,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 625800, 3, 208600, @@ -833,9 +841,9 @@ fn test_offchain_worker_order_matching() { Dex::offchain_worker(block); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 208833, 1, 208833, @@ -844,9 +852,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 2, 417308, 208654, @@ -855,9 +863,9 @@ fn test_offchain_worker_order_matching() { )); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 5, 1043275, 208655, @@ -867,9 +875,9 @@ fn test_offchain_worker_order_matching() { Dex::offchain_worker(block); assert_ok!(Dex::make_order( - RuntimeOrigin::signed(1), - 777, - 888, + RuntimeOrigin::signed(ALICE), + USDT, + GGXT, 625965, 3, 208655, diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 5a95a910..218cf74f 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -21,10 +21,7 @@ use ethereum_types::BigEndianHash; use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::*, - traits::{OriginTrait, ReservableCurrency}, - PalletId, + dispatch::DispatchResult, pallet_prelude::*, traits::ReservableCurrency, PalletId, }; use frame_system::pallet_prelude::*; // use module_evm::{ExitReason, ExitSucceed}; @@ -32,7 +29,7 @@ use frame_system::pallet_prelude::*; // evm::limits::{erc20, liquidation}, // EVMBridge as EVMBridgeTrait, ExecutionMode, Context, LiquidationEvmBridge as LiquidationEvmBridgeT, EVM, // }; -use frame_support::{sp_runtime::traits::AccountIdConversion, traits::Currency}; +use frame_support::traits::Currency; use ggx_primitives::evm::{EVMBridgeTrait, EvmAddress}; use hex_literal::hex; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index 55d3d196..365bd076 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -130,10 +130,11 @@ create_currency_id! { #[derive(Encode, Decode, Eq, PartialEq, Copy, Clone, RuntimeDebug, PartialOrd, Ord, TypeInfo, MaxEncodedLen, Serialize, Deserialize)] #[repr(u8)] pub enum TokenSymbol { - // 0 - 19: Acala & Polkadot native tokens GGX("GoldenGate", 12) = 0, DOT("Polkadot", 10) = 1, - KSM("Kusama", 12) = 2, + USDT("USDT", 12) = 2, + GGXT("GGxchain", 12) = 3, + BTC("Bitcoin", 12) = 4, } } From 0afa8f4bb9d70906205ee4d25966eda33bdfd879 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Fri, 24 May 2024 19:13:01 +0800 Subject: [PATCH 16/27] remove unused import --- pallet/currencies/src/lib.rs | 17 +++--------- pallet/dex/src/lib.rs | 18 ++++--------- pallet/dex/src/mock.rs | 6 +---- pallet/erc-20/src/lib.rs | 28 +++++++------------- runtime/brooklyn/src/currencies.rs | 5 +--- runtime/brooklyn/src/dex.rs | 4 +-- runtime/brooklyn/src/dex_chain_extensions.rs | 1 - runtime/brooklyn/src/erc20.rs | 2 +- runtime/brooklyn/src/lib.rs | 5 +--- runtime/sydney/src/currencies.rs | 6 ++--- runtime/sydney/src/dex.rs | 7 +---- runtime/sydney/src/dex_chain_extensions.rs | 1 - runtime/sydney/src/erc20.rs | 2 +- 13 files changed, 28 insertions(+), 74 deletions(-) diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index efaa271f..5c38c026 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -46,9 +46,8 @@ use frame_support::{ Provenance, WithdrawConsequence, }, Currency as PalletCurrency, ExistenceRequirement, Get, Imbalance, - LockableCurrency as PalletLockableCurrency, - NamedReservableCurrency as PalletNamedReservableCurrency, - ReservableCurrency as PalletReservableCurrency, WithdrawReasons, + LockableCurrency as PalletLockableCurrency, ReservableCurrency as PalletReservableCurrency, + WithdrawReasons, }, }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; @@ -61,7 +60,6 @@ use orml_traits::{ }; use orml_utilities::with_transaction_result; use scale_codec::Codec; -use sp_core::H160; use sp_runtime::{ traits::{CheckedSub, MaybeSerializeDeserialize, StaticLookup, Zero}, DispatchError, DispatchResult, @@ -72,10 +70,7 @@ use astar_primitives::{ ethereum_checked::AccountMapping, xvm::{Context, VmId}, }; -use ggx_primitives::{ - currency::CurrencyId, - evm::{EVMBridgeTrait, EvmAddress}, -}; +use ggx_primitives::{currency::CurrencyId, evm::EVMBridgeTrait}; mod mock; mod tests; @@ -94,10 +89,6 @@ pub mod module { pub(crate) type AmountOf = <::MultiCurrency as MultiCurrencyExtended< ::AccountId, >>::Amount; - pub(crate) type ReserveIdentifierOf = - <::MultiCurrency as NamedMultiReservableCurrency< - ::AccountId, - >>::ReserveIdentifier; #[pallet::config] pub trait Config: frame_system::Config { @@ -299,7 +290,7 @@ impl MultiCurrency for Pallet { } match currency_id { CurrencyId::Erc20(contract) => { - let sender = T::AddressMapping::into_h160(from.clone()); + let _sender = T::AddressMapping::into_h160(from.clone()); let address = T::AddressMapping::into_h160(to.clone()); T::EVMBridge::transfer( Context { diff --git a/pallet/dex/src/lib.rs b/pallet/dex/src/lib.rs index cb975818..f920ce86 100644 --- a/pallet/dex/src/lib.rs +++ b/pallet/dex/src/lib.rs @@ -5,7 +5,7 @@ use frame_support::{ ensure, pallet_prelude::{ConstU32, DispatchResult}, sp_std::{convert::TryInto, prelude::*}, - traits::{Currency, ExistenceRequirement::AllowDeath, Get, ReservableCurrency}, + traits::{Get, ReservableCurrency}, BoundedBTreeMap, PalletId, RuntimeDebug, }; @@ -21,11 +21,9 @@ use sp_runtime::{ }; use orml_traits::{ - arithmetic::{Signed, SimpleArithmetic}, - currency::TransferAll, - BalanceStatus, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, - BasicReservableCurrency, LockIdentifier, MultiCurrency, MultiCurrencyExtended, - MultiLockableCurrency, MultiReservableCurrency, NamedMultiReservableCurrency, + currency::TransferAll, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, + BasicReservableCurrency, MultiCurrency, MultiCurrencyExtended, MultiLockableCurrency, + MultiReservableCurrency, NamedMultiReservableCurrency, }; use core::cmp::Ordering; @@ -36,13 +34,7 @@ use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::{prelude::cmp, TypeInfo}; use sp_runtime::{traits::One, DispatchError}; -use frame_support::{ - sp_runtime::traits::AccountIdConversion, - traits::{ - fungibles::{Balanced, Mutate}, - tokens::Preservation, - }, -}; +use frame_support::sp_runtime::traits::AccountIdConversion; #[cfg(test)] mod mock; diff --git a/pallet/dex/src/mock.rs b/pallet/dex/src/mock.rs index c13ef6c1..9b8ed87a 100644 --- a/pallet/dex/src/mock.rs +++ b/pallet/dex/src/mock.rs @@ -12,11 +12,7 @@ use frame_support::{ weights::constants::RocksDbWeight, PalletId, }; -use ggx_primitives::{ - currency::{CurrencyId, TokenSymbol}, - evm::EvmAddress, -}; -use orml_tokens::TransferDust; +use ggx_primitives::currency::{CurrencyId, TokenSymbol}; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; use pallet_evm::GasWeightMapping; use sp_core::{ConstU128, ConstU32, ConstU64, H160, H256}; diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 218cf74f..e1a66b2e 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -30,22 +30,13 @@ use frame_system::pallet_prelude::*; // EVMBridge as EVMBridgeTrait, ExecutionMode, Context, LiquidationEvmBridge as LiquidationEvmBridgeT, EVM, // }; use frame_support::traits::Currency; -use ggx_primitives::evm::{EVMBridgeTrait, EvmAddress}; +use ggx_primitives::evm::EVMBridgeTrait; use hex_literal::hex; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use pallet_evm::AddressMapping; use sp_core::{H160, H256, U256}; -use sp_runtime::{ArithmeticError, DispatchError, SaturatedConversion}; +use sp_runtime::{DispatchError, SaturatedConversion}; use sp_std::{vec, vec::Vec}; -use astar_primitives::{ - ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx, EthereumTxInput}, - xvm::{ - CallFailure, CallOutput, CallResult, Context, FailureError::*, FailureRevert::*, VmId, - XvmCall, - }, - Balance, -}; +use astar_primitives::xvm::{Context, VmId, XvmCall}; type AccountIdOf = ::AccountId; //type BalanceOf = <::EVM as EVM>>::Balance; @@ -117,31 +108,31 @@ pub struct EVMBridge(sp_std::marker::PhantomData); impl EVMBridgeTrait, BalanceOf> for EVMBridge { // Calls the name method on an ERC20 contract using the given context // and returns the token name. - fn name(context: Context) -> Result, DispatchError> { + fn name(_context: Context) -> Result, DispatchError> { Ok(vec![]) } // Calls the symbol method on an ERC20 contract using the given context // and returns the token symbol. - fn symbol(context: Context) -> Result, DispatchError> { + fn symbol(_context: Context) -> Result, DispatchError> { Ok(vec![]) } // Calls the decimals method on an ERC20 contract using the given context // and returns the decimals. - fn decimals(context: Context) -> Result { + fn decimals(_context: Context) -> Result { Ok(0) } // Calls the totalSupply method on an ERC20 contract using the given context // and returns the total supply. - fn total_supply(context: Context) -> Result, DispatchError> { + fn total_supply(_context: Context) -> Result, DispatchError> { Ok(Default::default()) } // Calls the balanceOf method on an ERC20 contract using the given context // and returns the address's balance. - fn balance_of(context: Context, address: H160) -> Result, DispatchError> { + fn balance_of(_context: Context, _address: H160) -> Result, DispatchError> { Ok(Default::default()) } @@ -170,7 +161,6 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { H256::from_uint(&U256::from(value.saturated_into::())).as_bytes(), ); - let gas = 200_000; let storage_limit = 960; let call_result = T::XvmCallApi::call( @@ -183,7 +173,7 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { Some(storage_limit), ); - let used_weight = match &call_result { + let _used_weight = match &call_result { Ok(s) => s.used_weight, Err(f) => f.used_weight, }; diff --git a/runtime/brooklyn/src/currencies.rs b/runtime/brooklyn/src/currencies.rs index d871a339..7bde0391 100644 --- a/runtime/brooklyn/src/currencies.rs +++ b/runtime/brooklyn/src/currencies.rs @@ -1,8 +1,5 @@ -use crate::{ - prelude::*, Assets, BlakeTwo256, BlockNumber, ConstU32, Erc20, GGXTokens, MaxLocks, H160, -}; +use crate::{prelude::*, BlockNumber, ConstU32, GGXTokens, MaxLocks, H160}; use orml_traits::parameter_type_with_key; -use scale_info::prelude::vec; use sp_runtime::traits::Zero; use ggx_primitives::currency::{CurrencyId, TokenSymbol}; diff --git a/runtime/brooklyn/src/dex.rs b/runtime/brooklyn/src/dex.rs index 60bbecd4..d6f1d755 100644 --- a/runtime/brooklyn/src/dex.rs +++ b/runtime/brooklyn/src/dex.rs @@ -1,9 +1,9 @@ use crate::currencies::Amount; use frame_support::PalletId; -use orml_traits::MultiCurrency; + use pallet_currencies::BasicCurrencyAdapter; -use crate::{currencies::NativeCurrencyId, prelude::*, Assets, BlockNumber, GGXTokens}; +use crate::{prelude::*, BlockNumber, GGXTokens}; parameter_types! { pub const DexPalletId: PalletId = PalletId(*b"py/sudex"); diff --git a/runtime/brooklyn/src/dex_chain_extensions.rs b/runtime/brooklyn/src/dex_chain_extensions.rs index f785166b..10708ff0 100644 --- a/runtime/brooklyn/src/dex_chain_extensions.rs +++ b/runtime/brooklyn/src/dex_chain_extensions.rs @@ -1,7 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_runtime::{DispatchError, ModuleError}; -use frame_support::traits::Currency; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use ggx_primitives::currency::CurrencyId; use orml_traits::MultiCurrency; diff --git a/runtime/brooklyn/src/erc20.rs b/runtime/brooklyn/src/erc20.rs index 87c4487b..1aeeb609 100644 --- a/runtime/brooklyn/src/erc20.rs +++ b/runtime/brooklyn/src/erc20.rs @@ -1,6 +1,6 @@ use frame_support::PalletId; -use crate::{prelude::*, Assets, BlockNumber, Xvm}; +use crate::{prelude::*, Xvm}; parameter_types! { pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); diff --git a/runtime/brooklyn/src/lib.rs b/runtime/brooklyn/src/lib.rs index 294b5fe1..a448d8a7 100644 --- a/runtime/brooklyn/src/lib.rs +++ b/runtime/brooklyn/src/lib.rs @@ -35,10 +35,7 @@ use core::cmp::Ordering; #[cfg(feature = "std")] pub use fp_evm::GenesisAccount; -use frame_support::{ - pallet_prelude::{DispatchError, TransactionPriority}, - weights::constants::WEIGHT_PROOF_SIZE_PER_MB, -}; +use frame_support::pallet_prelude::{DispatchError, TransactionPriority}; use scale_codec::{Decode, Encode}; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; diff --git a/runtime/sydney/src/currencies.rs b/runtime/sydney/src/currencies.rs index d871a339..c37da33d 100644 --- a/runtime/sydney/src/currencies.rs +++ b/runtime/sydney/src/currencies.rs @@ -1,8 +1,6 @@ -use crate::{ - prelude::*, Assets, BlakeTwo256, BlockNumber, ConstU32, Erc20, GGXTokens, MaxLocks, H160, -}; +use crate::{prelude::*, BlockNumber, ConstU32, GGXTokens, MaxLocks, H160}; use orml_traits::parameter_type_with_key; -use scale_info::prelude::vec; + use sp_runtime::traits::Zero; use ggx_primitives::currency::{CurrencyId, TokenSymbol}; diff --git a/runtime/sydney/src/dex.rs b/runtime/sydney/src/dex.rs index 3f961948..44589a55 100644 --- a/runtime/sydney/src/dex.rs +++ b/runtime/sydney/src/dex.rs @@ -1,12 +1,7 @@ use frame_support::PalletId; -use orml_traits::MultiCurrency; use pallet_currencies::BasicCurrencyAdapter; -use crate::{ - currencies::{Amount, NativeCurrencyId}, - prelude::*, - Assets, BlockNumber, GGXTokens, -}; +use crate::{currencies::Amount, prelude::*, BlockNumber, GGXTokens}; parameter_types! { pub const UnsignedPriority: BlockNumber = 1; diff --git a/runtime/sydney/src/dex_chain_extensions.rs b/runtime/sydney/src/dex_chain_extensions.rs index f785166b..10708ff0 100644 --- a/runtime/sydney/src/dex_chain_extensions.rs +++ b/runtime/sydney/src/dex_chain_extensions.rs @@ -1,7 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] use sp_runtime::{DispatchError, ModuleError}; -use frame_support::traits::Currency; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use ggx_primitives::currency::CurrencyId; use orml_traits::MultiCurrency; diff --git a/runtime/sydney/src/erc20.rs b/runtime/sydney/src/erc20.rs index 87c4487b..1aeeb609 100644 --- a/runtime/sydney/src/erc20.rs +++ b/runtime/sydney/src/erc20.rs @@ -1,6 +1,6 @@ use frame_support::PalletId; -use crate::{prelude::*, Assets, BlockNumber, Xvm}; +use crate::{prelude::*, Xvm}; parameter_types! { pub const ERC20PalletId: PalletId = PalletId(*b"py/erc20"); From dc191016a2f8152d437f3b8de12de6b1445fffcd Mon Sep 17 00:00:00 2001 From: Li Smith Date: Mon, 27 May 2024 21:11:26 +0800 Subject: [PATCH 17/27] add deploy erc20 in currencies mock.rs --- Cargo.lock | 5 + pallet/currencies/Cargo.toml | 7 ++ pallet/currencies/src/lib.rs | 17 ++- pallet/currencies/src/mock.rs | 184 ++++++++++++++++++++++++++------- pallet/currencies/src/tests.rs | 20 ++++ pallet/erc-20/src/lib.rs | 33 +++++- primitives/src/evm.rs | 7 +- 7 files changed, 231 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 546d0757..57c79909 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8647,12 +8647,16 @@ dependencies = [ "frame-support", "frame-system", "ggx-primitives", + "hex", + "hex-literal 0.3.4", "orml-tokens", "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "orml-utilities 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", "pallet-balances", "pallet-contracts", "pallet-erc20", + "pallet-ethereum", + "pallet-ethereum-checked", "pallet-evm", "pallet-insecure-randomness-collective-flip", "pallet-timestamp", @@ -8660,6 +8664,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", + "serde_json", "sp-core 7.0.0", "sp-io 7.0.0", "sp-runtime 7.0.0", diff --git a/pallet/currencies/Cargo.toml b/pallet/currencies/Cargo.toml index e56f265b..1dbdaffe 100644 --- a/pallet/currencies/Cargo.toml +++ b/pallet/currencies/Cargo.toml @@ -27,13 +27,18 @@ ggx-primitives = { workspace = true } [dev-dependencies] fp-evm.workspace = true +hex = { workspace = true, features = ["std"] } +hex-literal = { workspace = true } pallet-balances = { workspace = true } pallet-contracts.workspace = true pallet-erc20.workspace = true +pallet-ethereum.workspace = true +pallet-ethereum-checked.workspace = true pallet-evm.workspace = true pallet-randomness-collective-flip.workspace = true pallet-timestamp.workspace = true pallet-xvm.workspace = true +serde_json = { workspace = true, features = ["std"] } sp-core = { workspace = true } orml-tokens = { workspace = true } @@ -52,6 +57,8 @@ std = [ "orml-utilities/std", "pallet-contracts/std", "pallet-erc20/std", + "pallet-ethereum/std", + "pallet-ethereum-checked/std", "pallet-evm/std", "pallet-randomness-collective-flip/std", "pallet-timestamp/std", diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 5c38c026..976f51af 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -260,10 +260,19 @@ impl MultiCurrency for Pallet { } fn free_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { - if currency_id == T::GetNativeCurrencyId::get() { - T::NativeCurrency::free_balance(who) - } else { - T::MultiCurrency::free_balance(currency_id, who) + match currency_id { + CurrencyId::Erc20(contract) => { + if let Some(address) = T::AddressMapping::get_evm_address(who) { + let context = Context { + source_vm_id: VmId::Wasm, + weight_limit: Weight::from_parts(100_000_000_000, 1_000_000_000), + }; + return T::EVMBridge::balance_of(context, address).unwrap_or_default(); + } + Default::default() + } + id if id == T::GetNativeCurrencyId::get() => T::NativeCurrency::free_balance(who), + _ => T::MultiCurrency::free_balance(currency_id, who), } } diff --git a/pallet/currencies/src/mock.rs b/pallet/currencies/src/mock.rs index ec0035e9..267486f7 100644 --- a/pallet/currencies/src/mock.rs +++ b/pallet/currencies/src/mock.rs @@ -6,26 +6,30 @@ use super::*; use astar_primitives::ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}; use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ - construct_runtime, + assert_ok, construct_runtime, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, Nothing}, + traits::{ConstBool, ConstU32, ConstU64, FindAuthor, Nothing}, weights::constants::RocksDbWeight, - PalletId, + ConsensusEngineId, PalletId, }; use ggx_primitives::{ currency::{CurrencyId, TokenSymbol}, evm::EvmAddress, }; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; -use pallet_evm::GasWeightMapping; -use sp_core::{ConstU128, H256}; +use pallet_ethereum::PostLogContent; +use pallet_ethereum_checked::EnsureXcmEthereumTx; +use pallet_evm::{AddressMapping, FeeCalculator, GasWeightMapping}; +use sp_core::{blake2_256, ConstU128, H160, H256, U256}; +use sp_io::TestExternalities; use sp_runtime::{ testing::Header, - traits::{AccountIdConversion, IdentityLookup}, + traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, AccountId32, BuildStorage, }; use sp_std::cell::RefCell; +use std::str::FromStr; use crate as currencies; @@ -165,39 +169,55 @@ impl pallet_contracts::Config for Test { type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; } -thread_local! { - static TRANSACTED: RefCell> = RefCell::new(None); +pub struct MockFeeCalculator; +impl FeeCalculator for MockFeeCalculator { + fn min_gas_price() -> (U256, Weight) { + (U256::one(), Weight::zero()) + } +} + +pub struct MockFindAuthor; +impl FindAuthor for MockFindAuthor { + fn find_author<'a, I>(_digests: I) -> Option + where + I: 'a + IntoIterator, + { + Some(H160::from_low_u64_be(1)) + } } -pub struct MockEthereumTransact; -impl MockEthereumTransact { - pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) { - let transacted = TRANSACTED.with(|v| v.borrow().clone()); - assert_eq!(transacted, Some((source, checked_tx))); +pub struct MockAddressMapping; +impl AddressMapping for MockAddressMapping { + fn into_account_id(address: H160) -> AccountId32 { + if address == ALICE_H160 { + return ALICE; + } + if address == BOB_H160 { + return BOB; + } + if address == CHARLIE_H160 { + return CHARLIE; + } + + return pallet_evm::HashedAddressMapping::::into_account_id(address); } } -impl CheckedEthereumTransact for MockEthereumTransact { - fn xvm_transact( - source: H160, - checked_tx: CheckedEthereumTx, - ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { - TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx))); - Ok(( - PostDispatchInfo { - actual_weight: Default::default(), - pays_fee: Default::default(), - }, - EvmCallInfo { - exit_reason: ExitReason::Succeed(ExitSucceed::Returned), - value: Default::default(), - used_gas: UsedGas { - standard: Default::default(), - effective: Default::default(), - }, - logs: Default::default(), - weight_info: None, - }, - )) + +pub struct MockAccountMapping; +impl AccountMapping for MockAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + if account_id == ALICE { + return ALICE_H160; + } + if account_id == BOB { + return BOB_H160; + } + if account_id == CHARLIE { + return CHARLIE_H160; + } + + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(blake2_256)[0..20]); } } @@ -211,10 +231,63 @@ impl GasWeightMapping for MockGasWeightMapping { } } +parameter_types! { + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub const BlockGasLimit: U256 = U256::MAX; +} + +impl pallet_evm::Config for Test { + type FeeCalculator = MockFeeCalculator; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; + type AddressMapping = MockAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = ConstU64<1024>; + type OnChargeTransaction = (); + type BlockGasLimit = BlockGasLimit; + type OnCreate = (); + type FindAuthor = MockFindAuthor; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; + type GasLimitPovSizeRatio = ConstU64<4>; +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Test { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub TxWeightLimit: Weight = Weight::from_parts(u64::max_value(), 0); +} + +impl pallet_ethereum_checked::Config for Test { + type ReservedXcmpWeight = TxWeightLimit; + type XvmTxWeightLimit = TxWeightLimit; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type AccountMapping = MockAccountMapping; + type XcmTransactOrigin = EnsureXcmEthereumTx; + type WeightInfo = (); +} + impl pallet_xvm::Config for Test { type GasWeightMapping = MockGasWeightMapping; type AccountMapping = HashedAccountMapping; - type EthereumTransact = MockEthereumTransact; + type EthereumTransact = EthereumChecked; type WeightInfo = (); } @@ -270,17 +343,56 @@ frame_support::construct_runtime!( Balances: pallet_balances, RandomnessCollectiveFlip: pallet_randomness_collective_flip, Contracts: pallet_contracts, + Evm: pallet_evm, + Ethereum: pallet_ethereum, + EthereumChecked: pallet_ethereum_checked, Xvm: pallet_xvm, } ); pub const ALICE: AccountId = AccountId32::new([1u8; 32]); pub const BOB: AccountId = AccountId32::new([2u8; 32]); +pub const CHARLIE: AccountId = AccountId32::new([3u8; 32]); pub const EVA: AccountId = AccountId32::new([5u8; 32]); pub const ID_1: LockIdentifier = *b"1 "; pub const RID_1: ReserveIdentifier = [1u8; 8]; pub const RID_2: ReserveIdentifier = [2u8; 8]; +pub const ALICE_H160: H160 = H160::repeat_byte(1); +pub const BOB_H160: H160 = H160::repeat_byte(2); +pub const CHARLIE_H160: H160 = H160::repeat_byte(3); + +pub fn erc20_address() -> EvmAddress { + EvmAddress::from_str("0x65935dd23110976ca3d335851f736c939ddc819e").unwrap() +} + +pub fn deploy_contracts() { + System::set_block_number(1); + + let json: serde_json::Value = serde_json::from_str(include_str!( + "../../../node/tests/data/Erc20DemoContract2.json" + )) + .unwrap(); + + let code = hex::decode(json.get("bytecode").unwrap().as_str().unwrap()).unwrap(); + + assert_ok!(Evm::create2( + RuntimeOrigin::root(), + ALICE_H160, + code, + H256::zero(), + U256::zero(), + 1_000_000_000, + U256::one(), + None, + Some(U256::zero()), + vec![], + )); + + System::assert_last_event(RuntimeEvent::Evm(pallet_evm::Event::Created { + address: erc20_address(), + })); +} #[derive(Default)] pub struct ExtBuilder { balances: Vec<(AccountId, CurrencyId, Balance)>, diff --git a/pallet/currencies/src/tests.rs b/pallet/currencies/src/tests.rs index 56e448b2..55c5c468 100644 --- a/pallet/currencies/src/tests.rs +++ b/pallet/currencies/src/tests.rs @@ -338,3 +338,23 @@ fn call_event_should_work() { })); }); } + +#[test] +fn erc20_transfer_should_work() { + ExtBuilder::default() + .balances(vec![ + (ALICE, NATIVE_CURRENCY_ID, 200_000_000_000), + (BOB, NATIVE_CURRENCY_ID, 100000), + ]) + .build() + .execute_with(|| { + deploy_contracts(); + + assert_ok!(Currencies::transfer( + RuntimeOrigin::signed(ALICE), + BOB, + CurrencyId::Erc20(erc20_address()), + 100 + )); + }); +} diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index e1a66b2e..15238bdd 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -132,7 +132,38 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { // Calls the balanceOf method on an ERC20 contract using the given context // and returns the address's balance. - fn balance_of(_context: Context, _address: H160) -> Result, DispatchError> { + fn balance_of( + context: Context, + contract: H160, + from: AccountIdOf, + address: H160, + ) -> Result, DispatchError> { + const BALANCEOF_SELECTOR: [u8; 4] = hex!["70a08231"]; + // ERC20.balance_of method hash + let mut input = BALANCEOF_SELECTOR.to_vec(); + + // append address + input.extend_from_slice(H256::from(address).as_bytes()); + + let storage_limit = 960; + + let call_result = T::XvmCallApi::call( + context, + VmId::Evm, + from, + contract.as_bytes().to_vec(), + input, + 0, + Some(storage_limit), + ); + + let _used_weight = match &call_result { + Ok(s) => s.used_weight, + Err(f) => f.used_weight, + }; + + print!("#### call_result", call_result); + Ok(Default::default()) } diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index 2bffa150..6b19f32e 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -17,7 +17,12 @@ pub trait EVMBridgeTrait { fn total_supply(context: Context) -> Result; /// Execute ERC20.balanceOf(address) to read balance of address from ERC20 /// contract - fn balance_of(context: Context, address: EvmAddress) -> Result; + fn balance_of( + context: Context, + contract: H160, + from: AccountIdOf, + address: EvmAddress, + ) -> Result; /// Execute ERC20.transfer(address, uint256) to transfer value to `to` fn transfer( context: Context, From 609f7a3c20190da180afb52772771ec1259e735c Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 28 May 2024 19:08:05 +0800 Subject: [PATCH 18/27] 1 fix balance_of 2 fix tranfer testcase --- pallet/currencies/src/lib.rs | 15 ++++---- pallet/currencies/src/mock.rs | 66 ++++++++++++++++++---------------- pallet/currencies/src/tests.rs | 7 +++- pallet/erc-20/src/lib.rs | 50 ++++++++++++++------------ primitives/src/evm.rs | 4 +-- 5 files changed, 78 insertions(+), 64 deletions(-) diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index 976f51af..e8343581 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -262,14 +262,13 @@ impl MultiCurrency for Pallet { fn free_balance(currency_id: Self::CurrencyId, who: &T::AccountId) -> Self::Balance { match currency_id { CurrencyId::Erc20(contract) => { - if let Some(address) = T::AddressMapping::get_evm_address(who) { - let context = Context { - source_vm_id: VmId::Wasm, - weight_limit: Weight::from_parts(100_000_000_000, 1_000_000_000), - }; - return T::EVMBridge::balance_of(context, address).unwrap_or_default(); - } - Default::default() + let address = T::AddressMapping::into_h160(who.clone()); + let context = Context { + source_vm_id: VmId::Wasm, + weight_limit: Weight::from_parts(100_000_000_000, 1_000_000_000), + }; + return T::EVMBridge::balance_of(context, contract, who.clone(), address) + .unwrap_or_default(); } id if id == T::GetNativeCurrencyId::get() => T::NativeCurrency::free_balance(who), _ => T::MultiCurrency::free_balance(currency_id, who), diff --git a/pallet/currencies/src/mock.rs b/pallet/currencies/src/mock.rs index 267486f7..bd3ed97d 100644 --- a/pallet/currencies/src/mock.rs +++ b/pallet/currencies/src/mock.rs @@ -3,32 +3,24 @@ #![cfg(test)] use super::*; -use astar_primitives::ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}; -use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; use frame_support::{ - assert_ok, construct_runtime, - dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, - parameter_types, + assert_ok, parameter_types, traits::{ConstBool, ConstU32, ConstU64, FindAuthor, Nothing}, weights::constants::RocksDbWeight, ConsensusEngineId, PalletId, }; -use ggx_primitives::{ - currency::{CurrencyId, TokenSymbol}, - evm::EvmAddress, -}; +use ggx_primitives::{currency::CurrencyId, evm::EvmAddress}; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; use pallet_ethereum::PostLogContent; use pallet_ethereum_checked::EnsureXcmEthereumTx; use pallet_evm::{AddressMapping, FeeCalculator, GasWeightMapping}; use sp_core::{blake2_256, ConstU128, H160, H256, U256}; -use sp_io::TestExternalities; + use sp_runtime::{ testing::Header, traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, - AccountId32, BuildStorage, + AccountId32, }; -use sp_std::cell::RefCell; use std::str::FromStr; use crate as currencies; @@ -189,13 +181,13 @@ impl FindAuthor for MockFindAuthor { pub struct MockAddressMapping; impl AddressMapping for MockAddressMapping { fn into_account_id(address: H160) -> AccountId32 { - if address == ALICE_H160 { + if address == alice_evm_addr() { return ALICE; } - if address == BOB_H160 { + if address == bob_evm_addr() { return BOB; } - if address == CHARLIE_H160 { + if address == charlie_evm_addr() { return CHARLIE; } @@ -207,13 +199,13 @@ pub struct MockAccountMapping; impl AccountMapping for MockAccountMapping { fn into_h160(account_id: AccountId) -> H160 { if account_id == ALICE { - return ALICE_H160; + return alice_evm_addr(); } if account_id == BOB { - return BOB_H160; + return bob_evm_addr(); } if account_id == CHARLIE { - return CHARLIE_H160; + return charlie_evm_addr(); } let data = (b"evm:", account_id); @@ -286,7 +278,7 @@ impl pallet_ethereum_checked::Config for Test { impl pallet_xvm::Config for Test { type GasWeightMapping = MockGasWeightMapping; - type AccountMapping = HashedAccountMapping; + type AccountMapping = MockAddressMapping; type EthereumTransact = EthereumChecked; type WeightInfo = (); } @@ -301,10 +293,18 @@ impl pallet_erc20::Config for Test { type XvmCallApi = Xvm; } -///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { +impl astar_primitives::ethereum_checked::AccountMapping for MockAddressMapping { fn into_h160(account_id: AccountId) -> H160 { + if account_id == ALICE { + return alice_evm_addr(); + } + if account_id == BOB { + return bob_evm_addr(); + } + if account_id == CHARLIE { + return charlie_evm_addr(); + } + let data = (b"evm:", account_id); return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); } @@ -322,7 +322,7 @@ impl Config for Test { type NativeCurrency = AdaptedBasicCurrency; type GetNativeCurrencyId = GetNativeCurrencyId; type WeightInfo = (); - type AddressMapping = HashedAccountMapping; + type AddressMapping = MockAddressMapping; type EVMBridge = pallet_erc20::EVMBridge; } pub type NativeCurrency = NativeCurrencyOf; @@ -355,15 +355,21 @@ pub const BOB: AccountId = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId = AccountId32::new([3u8; 32]); pub const EVA: AccountId = AccountId32::new([5u8; 32]); pub const ID_1: LockIdentifier = *b"1 "; -pub const RID_1: ReserveIdentifier = [1u8; 8]; -pub const RID_2: ReserveIdentifier = [2u8; 8]; -pub const ALICE_H160: H160 = H160::repeat_byte(1); -pub const BOB_H160: H160 = H160::repeat_byte(2); -pub const CHARLIE_H160: H160 = H160::repeat_byte(3); +pub fn alice_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn bob_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000002").unwrap() +} + +pub fn charlie_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000003").unwrap() +} pub fn erc20_address() -> EvmAddress { - EvmAddress::from_str("0x65935dd23110976ca3d335851f736c939ddc819e").unwrap() + EvmAddress::from_str("0x85728369a08dfe6660c7ff2c4f8f011fc1300973").unwrap() } pub fn deploy_contracts() { @@ -378,7 +384,7 @@ pub fn deploy_contracts() { assert_ok!(Evm::create2( RuntimeOrigin::root(), - ALICE_H160, + alice_evm_addr(), code, H256::zero(), U256::zero(), diff --git a/pallet/currencies/src/tests.rs b/pallet/currencies/src/tests.rs index 55c5c468..172ea260 100644 --- a/pallet/currencies/src/tests.rs +++ b/pallet/currencies/src/tests.rs @@ -343,7 +343,7 @@ fn call_event_should_work() { fn erc20_transfer_should_work() { ExtBuilder::default() .balances(vec![ - (ALICE, NATIVE_CURRENCY_ID, 200_000_000_000), + (ALICE, NATIVE_CURRENCY_ID, 100_000_000_000), (BOB, NATIVE_CURRENCY_ID, 100000), ]) .build() @@ -356,5 +356,10 @@ fn erc20_transfer_should_work() { CurrencyId::Erc20(erc20_address()), 100 )); + + assert_eq!( + Currencies::free_balance(CurrencyId::Erc20(erc20_address()), &BOB,), + 100 + ); }); } diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 15238bdd..81f8548b 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::unused_unit)] +use astar_primitives::xvm::{CallResult, FailureReason}; use ethereum_types::BigEndianHash; use frame_support::{ dispatch::DispatchResult, pallet_prelude::*, traits::ReservableCurrency, PalletId, @@ -29,34 +30,19 @@ use frame_system::pallet_prelude::*; // evm::limits::{erc20, liquidation}, // EVMBridge as EVMBridgeTrait, ExecutionMode, Context, LiquidationEvmBridge as LiquidationEvmBridgeT, EVM, // }; +use astar_primitives::xvm::{Context, VmId, XvmCall}; use frame_support::traits::Currency; use ggx_primitives::evm::EVMBridgeTrait; use hex_literal::hex; use sp_core::{H160, H256, U256}; -use sp_runtime::{DispatchError, SaturatedConversion}; +use sp_runtime::{ArithmeticError, DispatchError, SaturatedConversion}; use sp_std::{vec, vec::Vec}; -use astar_primitives::xvm::{Context, VmId, XvmCall}; - type AccountIdOf = ::AccountId; //type BalanceOf = <::EVM as EVM>>::Balance; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -// #[module_evm_utility_macro::generate_function_selector] -// #[derive(RuntimeDebug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] -// #[repr(u32)] -// pub enum Action { -// Name = "name()", -// Symbol = "symbol()", -// Decimals = "decimals()", -// TotalSupply = "totalSupply()", -// BalanceOf = "balanceOf(address)", -// Transfer = "transfer(address,uint256)", -// OnCollateralTransfer = "onCollateralTransfer(address,uint256)", -// OnRepaymentRefund = "onRepaymentRefund(address,uint256)", -// } - // mod mock; // mod tests; @@ -162,7 +148,18 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { Err(f) => f.used_weight, }; - print!("#### call_result", call_result); + Pallet::::handle_exit_reason(call_result.clone())?; + + match call_result { + Ok(call_output) => { + let value: u128 = U256::from(call_output.output.as_slice()) + .try_into() + .map_err(|_| ArithmeticError::Overflow)?; + let balance = value.try_into().map_err(|_| ArithmeticError::Overflow)?; + return Ok(balance); + } + _ => {} + } Ok(Default::default()) } @@ -204,13 +201,20 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { Some(storage_limit), ); - let _used_weight = match &call_result { - Ok(s) => s.used_weight, - Err(f) => f.used_weight, - }; + Pallet::::handle_exit_reason(call_result)?; Ok(()) } } -impl Pallet {} +impl Pallet { + fn handle_exit_reason(rt: CallResult) -> Result<(), DispatchError> { + match rt { + Ok(_) => Ok(()), + Err(call_failure) => match call_failure.reason { + FailureReason::Revert(_) => Err(Error::::ExecutionRevert.into()), + FailureReason::Error(_) => Err(Error::::ExecutionError.into()), + }, + } + } +} diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index 6b19f32e..5ccde676 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -19,8 +19,8 @@ pub trait EVMBridgeTrait { /// contract fn balance_of( context: Context, - contract: H160, - from: AccountIdOf, + contract: EvmAddress, + from: AccountId, address: EvmAddress, ) -> Result; /// Execute ERC20.transfer(address, uint256) to transfer value to `to` From 8cda2a412d92936eaf32771b2225bd18954bfd82 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 28 May 2024 20:27:00 +0800 Subject: [PATCH 19/27] add deposit_erc20/withdraw_erc20 testcase for dex --- Cargo.lock | 5 + pallet/dex/Cargo.toml | 7 ++ pallet/dex/src/lib.rs | 3 +- pallet/dex/src/mock.rs | 231 +++++++++++++++++++++++++++++++--------- pallet/dex/src/tests.rs | 80 +++++++++++++- 5 files changed, 269 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f60bd87a..a49285c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8680,6 +8680,8 @@ dependencies = [ "frame-support", "frame-system", "ggx-primitives", + "hex", + "hex-literal 0.3.4", "log 0.4.20", "orml-tokens", "orml-traits 0.4.1-dev (git+https://github.com/open-web3-stack/open-runtime-module-library?rev=28a2e6f0df9540d91db4018c7ecebb8bfc217a2a)", @@ -8688,12 +8690,15 @@ dependencies = [ "pallet-contracts", "pallet-currencies", "pallet-erc20", + "pallet-ethereum", + "pallet-ethereum-checked", "pallet-evm", "pallet-insecure-randomness-collective-flip", "pallet-timestamp", "pallet-xvm", "parity-scale-codec", "scale-info", + "serde_json", "sp-core 7.0.0", "sp-io 7.0.0", "sp-runtime 7.0.0", diff --git a/pallet/dex/Cargo.toml b/pallet/dex/Cargo.toml index 46c6708f..4f8a84d9 100644 --- a/pallet/dex/Cargo.toml +++ b/pallet/dex/Cargo.toml @@ -22,15 +22,20 @@ sp-io.workspace = true [dev-dependencies] astar-primitives.workspace = true fp-evm.workspace = true +hex = { workspace = true, features = ["std"] } +hex-literal = { workspace = true } pallet-assets.workspace = true pallet-balances.workspace = true pallet-contracts.workspace = true pallet-currencies.workspace = true pallet-erc20.workspace = true +pallet-ethereum.workspace = true +pallet-ethereum-checked.workspace = true pallet-evm.workspace = true pallet-randomness-collective-flip.workspace = true pallet-timestamp.workspace = true pallet-xvm.workspace = true +serde_json = { workspace = true, features = ["std"] } sp-core.workspace = true sp-std.workspace = true orml-tokens = { workspace = true } @@ -50,6 +55,8 @@ std = [ "pallet-contracts/std", "pallet-currencies/std", "pallet-erc20/std", + "pallet-ethereum/std", + "pallet-ethereum-checked/std", "pallet-evm/std", "pallet-randomness-collective-flip/std", "pallet-timestamp/std", diff --git a/pallet/dex/src/lib.rs b/pallet/dex/src/lib.rs index 7b58fd21..2c640918 100644 --- a/pallet/dex/src/lib.rs +++ b/pallet/dex/src/lib.rs @@ -23,7 +23,7 @@ use sp_runtime::{ use orml_traits::{ currency::TransferAll, BasicCurrency, BasicCurrencyExtended, BasicLockableCurrency, BasicReservableCurrency, MultiCurrency, MultiCurrencyExtended, MultiLockableCurrency, - MultiReservableCurrency, NamedMultiReservableCurrency, + MultiReservableCurrency, }; use core::cmp::Ordering; @@ -259,7 +259,6 @@ pub mod pallet { + MultiCurrencyExtended + MultiLockableCurrency + MultiReservableCurrency - + NamedMultiReservableCurrency + fungibles::Inspect> + fungibles::Mutate>; diff --git a/pallet/dex/src/mock.rs b/pallet/dex/src/mock.rs index 9b8ed87a..09277816 100644 --- a/pallet/dex/src/mock.rs +++ b/pallet/dex/src/mock.rs @@ -2,28 +2,32 @@ use crate as pallet_dex; use super::*; -use astar_primitives::ethereum_checked::{CheckedEthereumTransact, CheckedEthereumTx}; -use fp_evm::{CallInfo as EvmCallInfo, ExitReason, ExitSucceed, UsedGas}; +use astar_primitives::ethereum_checked::AccountMapping; use frame_support::{ - dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, + assert_ok, pallet_prelude::Weight, parameter_types, sp_io, - traits::{AsEnsureOriginWithArg, ConstBool, GenesisBuild, Hooks, Nothing}, + traits::{AsEnsureOriginWithArg, ConstBool, FindAuthor, GenesisBuild, Hooks, Nothing}, weights::constants::RocksDbWeight, - PalletId, + ConsensusEngineId, PalletId, +}; +use ggx_primitives::{ + currency::{CurrencyId, TokenSymbol}, + evm::EvmAddress, }; -use ggx_primitives::currency::{CurrencyId, TokenSymbol}; use orml_traits::{currency::MutationHooks, parameter_type_with_key}; -use pallet_evm::GasWeightMapping; -use sp_core::{ConstU128, ConstU32, ConstU64, H160, H256}; +use pallet_currencies::BasicCurrencyAdapter; +use pallet_ethereum::PostLogContent; +use pallet_ethereum_checked::EnsureXcmEthereumTx; +use pallet_evm::{AddressMapping, FeeCalculator, GasWeightMapping}; +use sp_core::{blake2_256, ConstU128, ConstU32, ConstU64, H160, H256, U256}; use sp_runtime::{ testing::Header, - traits::{AccountIdConversion, IdentityLookup}, + traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, AccountId32, }; -use sp_std::{cell::RefCell, marker}; - -use pallet_currencies::BasicCurrencyAdapter; +use sp_std::marker; +use std::str::FromStr; pub type AccountId = AccountId32; pub type Balance = u128; @@ -44,6 +48,9 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp, RandomnessCollectiveFlip: pallet_randomness_collective_flip, Contracts: pallet_contracts, + Evm: pallet_evm, + Ethereum: pallet_ethereum, + EthereumChecked: pallet_ethereum_checked, Xvm: pallet_xvm, Currencies: pallet_currencies, Tokens: orml_tokens, @@ -225,39 +232,55 @@ impl pallet_contracts::Config for Test { type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; } -thread_local! { - static TRANSACTED: RefCell> = RefCell::new(None); +pub struct MockFeeCalculator; +impl FeeCalculator for MockFeeCalculator { + fn min_gas_price() -> (U256, Weight) { + (U256::one(), Weight::zero()) + } } -pub struct MockEthereumTransact; -impl MockEthereumTransact { - pub(crate) fn assert_transacted(source: H160, checked_tx: CheckedEthereumTx) { - let transacted = TRANSACTED.with(|v| v.borrow().clone()); - assert_eq!(transacted, Some((source, checked_tx))); +pub struct MockFindAuthor; +impl FindAuthor for MockFindAuthor { + fn find_author<'a, I>(_digests: I) -> Option + where + I: 'a + IntoIterator, + { + Some(H160::from_low_u64_be(1)) } } -impl CheckedEthereumTransact for MockEthereumTransact { - fn xvm_transact( - source: H160, - checked_tx: CheckedEthereumTx, - ) -> Result<(PostDispatchInfo, EvmCallInfo), DispatchErrorWithPostInfo> { - TRANSACTED.with(|v| *v.borrow_mut() = Some((source, checked_tx))); - Ok(( - PostDispatchInfo { - actual_weight: Default::default(), - pays_fee: Default::default(), - }, - EvmCallInfo { - exit_reason: ExitReason::Succeed(ExitSucceed::Returned), - value: Default::default(), - used_gas: UsedGas { - standard: Default::default(), - effective: Default::default(), - }, - logs: Default::default(), - weight_info: None, - }, - )) + +pub struct MockAddressMapping; +impl AddressMapping for MockAddressMapping { + fn into_account_id(address: H160) -> AccountId32 { + if address == alice_evm_addr() { + return ALICE; + } + if address == bob_evm_addr() { + return BOB; + } + if address == charlie_evm_addr() { + return CHARLIE; + } + + return pallet_evm::HashedAddressMapping::::into_account_id(address); + } +} + +pub struct MockAccountMapping; +impl AccountMapping for MockAccountMapping { + fn into_h160(account_id: AccountId) -> H160 { + if account_id == ALICE { + return alice_evm_addr(); + } + if account_id == BOB { + return bob_evm_addr(); + } + if account_id == CHARLIE { + return charlie_evm_addr(); + } + + let data = (b"evm:", account_id); + return H160::from_slice(&data.using_encoded(blake2_256)[0..20]); } } @@ -271,10 +294,63 @@ impl GasWeightMapping for MockGasWeightMapping { } } +parameter_types! { + pub WeightPerGas: Weight = Weight::from_parts(1, 0); + pub const BlockGasLimit: U256 = U256::MAX; +} + +impl pallet_evm::Config for Test { + type FeeCalculator = MockFeeCalculator; + type GasWeightMapping = pallet_evm::FixedGasWeightMapping; + type WeightPerGas = WeightPerGas; + type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; + type CallOrigin = pallet_evm::EnsureAddressRoot; + type WithdrawOrigin = pallet_evm::EnsureAddressTruncated; + type AddressMapping = MockAddressMapping; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type Runner = pallet_evm::runner::stack::Runner; + type PrecompilesType = (); + type PrecompilesValue = (); + type ChainId = ConstU64<1024>; + type OnChargeTransaction = (); + type BlockGasLimit = BlockGasLimit; + type OnCreate = (); + type FindAuthor = MockFindAuthor; + type Timestamp = Timestamp; + type WeightInfo = pallet_evm::weights::SubstrateWeight; + type GasLimitPovSizeRatio = ConstU64<4>; +} + +parameter_types! { + pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes; +} + +impl pallet_ethereum::Config for Test { + type RuntimeEvent = RuntimeEvent; + type StateRoot = pallet_ethereum::IntermediateStateRoot; + type PostLogContent = PostBlockAndTxnHashes; + type ExtraDataLength = ConstU32<30>; +} + +parameter_types! { + pub TxWeightLimit: Weight = Weight::from_parts(u64::max_value(), 0); +} + +impl pallet_ethereum_checked::Config for Test { + type ReservedXcmpWeight = TxWeightLimit; + type XvmTxWeightLimit = TxWeightLimit; + type InvalidEvmTransactionError = pallet_ethereum::InvalidTransactionWrapper; + type ValidatedTransaction = pallet_ethereum::ValidatedTransaction; + type AccountMapping = MockAccountMapping; + type XcmTransactOrigin = EnsureXcmEthereumTx; + type WeightInfo = (); +} + impl pallet_xvm::Config for Test { type GasWeightMapping = MockGasWeightMapping; - type AccountMapping = HashedAccountMapping; - type EthereumTransact = MockEthereumTransact; + type AccountMapping = MockAddressMapping; + type EthereumTransact = EthereumChecked; type WeightInfo = (); } @@ -288,10 +364,18 @@ impl pallet_erc20::Config for Test { type XvmCallApi = Xvm; } -///TODO: Placeholder account mapping. This would be replaced once account abstraction is finished. -pub struct HashedAccountMapping; -impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { +impl astar_primitives::ethereum_checked::AccountMapping for MockAddressMapping { fn into_h160(account_id: AccountId) -> H160 { + if account_id == ALICE { + return alice_evm_addr(); + } + if account_id == BOB { + return bob_evm_addr(); + } + if account_id == CHARLIE { + return charlie_evm_addr(); + } + let data = (b"evm:", account_id); return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); } @@ -307,7 +391,7 @@ impl pallet_currencies::Config for Test { type NativeCurrency = AdaptedBasicCurrency; type GetNativeCurrencyId = NativeCurrencyId; type WeightInfo = (); - type AddressMapping = HashedAccountMapping; + type AddressMapping = MockAddressMapping; type EVMBridge = pallet_erc20::EVMBridge; } @@ -318,7 +402,7 @@ parameter_types! { impl pallet_dex::Config for Test { type RuntimeEvent = RuntimeEvent; - type MultiCurrency = Tokens; + type MultiCurrency = Currencies; type NativeCurrency = AdaptedBasicCurrency; type PalletId = DexPalletId; type PrivilegedOrigin = frame_system::EnsureRoot; @@ -328,6 +412,23 @@ impl pallet_dex::Config for Test { pub const ALICE: AccountId = AccountId32::new([1u8; 32]); pub const BOB: AccountId = AccountId32::new([2u8; 32]); +pub const CHARLIE: AccountId = AccountId32::new([3u8; 32]); + +pub fn alice_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000001").unwrap() +} + +pub fn bob_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000002").unwrap() +} + +pub fn charlie_evm_addr() -> EvmAddress { + EvmAddress::from_str("1000000000000000000000000000000000000003").unwrap() +} + +pub fn erc20_address() -> EvmAddress { + EvmAddress::from_str("0x85728369a08dfe6660c7ff2c4f8f011fc1300973").unwrap() +} pub const NATIVE_CURRENCY_ID: CurrencyId = CurrencyId::Token(TokenSymbol::GGX); pub const USDT: CurrencyId = CurrencyId::Token(TokenSymbol::USDT); @@ -335,6 +436,34 @@ pub const GGXT: CurrencyId = CurrencyId::Token(TokenSymbol::GGXT); pub const BTC: CurrencyId = CurrencyId::Token(TokenSymbol::BTC); pub const DOT: CurrencyId = CurrencyId::Token(TokenSymbol::DOT); +pub fn deploy_contracts() { + System::set_block_number(1); + + let json: serde_json::Value = serde_json::from_str(include_str!( + "../../../node/tests/data/Erc20DemoContract2.json" + )) + .unwrap(); + + let code = hex::decode(json.get("bytecode").unwrap().as_str().unwrap()).unwrap(); + + assert_ok!(Evm::create2( + RuntimeOrigin::root(), + alice_evm_addr(), + code, + H256::zero(), + U256::zero(), + 1_000_000_000, + U256::one(), + None, + Some(U256::zero()), + vec![], + )); + + System::assert_last_event(RuntimeEvent::Evm(pallet_evm::Event::Created { + address: erc20_address(), + })); +} + pub struct ExtBuilder; impl Default for ExtBuilder { @@ -351,7 +480,7 @@ impl ExtBuilder { // This will cause some initial issuance pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, 9000), (BOB, 800)], + balances: vec![(ALICE, 100_000_000_000), (BOB, 800)], } .assimilate_storage(&mut storage) .ok(); @@ -412,7 +541,9 @@ impl ExtBuilder { CurrencyId::ForeignAsset(8888), CurrencyId::ForeignAsset(999), CurrencyId::ForeignAsset(888), - CurrencyId::ForeignAsset(777),], + CurrencyId::ForeignAsset(777), + CurrencyId::Erc20(erc20_address()), + ], native_asset_id: NATIVE_CURRENCY_ID, }, &mut storage, diff --git a/pallet/dex/src/tests.rs b/pallet/dex/src/tests.rs index 1670cf71..d47e7e0c 100644 --- a/pallet/dex/src/tests.rs +++ b/pallet/dex/src/tests.rs @@ -62,7 +62,7 @@ fn test_withdraw() { #[test] fn test_deposit_native() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(ALICE), 9000); + assert_eq!(Balances::free_balance(ALICE), 100_000_000_000); assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(ALICE), 10)); assert_eq!( @@ -73,7 +73,7 @@ fn test_deposit_native() { } ); - assert_eq!(Balances::free_balance(ALICE), 8990); + assert_eq!(Balances::free_balance(ALICE), 99999999990); assert_eq!( UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { @@ -87,7 +87,7 @@ fn test_deposit_native() { #[test] fn test_withdraw_native() { new_test_ext().execute_with(|| { - assert_eq!(Balances::free_balance(ALICE), 9000); + assert_eq!(Balances::free_balance(ALICE), 100_000_000_000); assert_noop!( Dex::withdraw_native(RuntimeOrigin::signed(ALICE), 10), @@ -96,7 +96,7 @@ fn test_withdraw_native() { assert_ok!(Dex::deposit_native(RuntimeOrigin::signed(ALICE), 10)); - assert_eq!(Balances::free_balance(ALICE), 8990); + assert_eq!(Balances::free_balance(ALICE), 99999999990); assert_eq!( UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { @@ -112,7 +112,7 @@ fn test_withdraw_native() { assert_ok!(Dex::withdraw_native(RuntimeOrigin::signed(ALICE), 10)); - assert_eq!(Balances::free_balance(ALICE), 9000); + assert_eq!(Balances::free_balance(ALICE), 100_000_000_000); assert_eq!( UserTokenInfoes::::get(ALICE, NativeAssetId::::get()), TokenInfo { @@ -123,6 +123,76 @@ fn test_withdraw_native() { }) } +#[test] +fn test_deposit_erc20() { + new_test_ext().execute_with(|| { + deploy_contracts(); + + assert_ok!(Dex::deposit( + RuntimeOrigin::signed(ALICE), + CurrencyId::Erc20(erc20_address()), + 10 + )); + + assert_eq!( + UserTokenInfoes::::get(ALICE, CurrencyId::Erc20(erc20_address()),), + TokenInfo { + amount: 10, + reserved: 0 + } + ); + }) +} + +#[test] +fn test_withdraw_erc20() { + new_test_ext().execute_with(|| { + assert_noop!( + Dex::withdraw( + RuntimeOrigin::signed(ALICE), + CurrencyId::Erc20(erc20_address()), + 10 + ), + Error::::AssetIdNotInTokenInfoes + ); + + assert_ok!(Dex::deposit( + RuntimeOrigin::signed(ALICE), + CurrencyId::Erc20(erc20_address()), + 10 + )); + assert_eq!( + UserTokenInfoes::::get(ALICE, CurrencyId::Erc20(erc20_address()),), + TokenInfo { + amount: 10, + reserved: 0 + } + ); + + assert_noop!( + Dex::withdraw( + RuntimeOrigin::signed(ALICE), + CurrencyId::Erc20(erc20_address()), + 11 + ), + Error::::NotEnoughBalance + ); + + assert_ok!(Dex::withdraw( + RuntimeOrigin::signed(ALICE), + CurrencyId::Erc20(erc20_address()), + 10 + )); + assert_eq!( + UserTokenInfoes::::get(ALICE, CurrencyId::Erc20(erc20_address()),), + TokenInfo { + amount: 0, + reserved: 0 + } + ); + }) +} + #[test] fn test_make_order() { new_test_ext().execute_with(|| { From 359bb356153ef0e667f730ef49ea5f5f2af41a18 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 28 May 2024 20:37:55 +0800 Subject: [PATCH 20/27] fix cargo clippy --- node/src/runtime/testnet.rs | 2 +- pallet/currencies/src/lib.rs | 4 ++-- pallet/erc-20/src/lib.rs | 17 +++++++---------- runtime/brooklyn/src/currencies.rs | 2 +- runtime/sydney/src/currencies.rs | 2 +- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/node/src/runtime/testnet.rs b/node/src/runtime/testnet.rs index e0d2257e..7c5cdcc3 100644 --- a/node/src/runtime/testnet.rs +++ b/node/src/runtime/testnet.rs @@ -380,7 +380,7 @@ pub fn testnet_genesis( }, dex: DexConfig { asset_ids: vec![ - native_asset_id: ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::CurrencyId::Token( ggx_primitives::currency::TokenSymbol::GGX, ), ForeignAsset(8888), diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index e8343581..f6fbb13e 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -267,8 +267,8 @@ impl MultiCurrency for Pallet { source_vm_id: VmId::Wasm, weight_limit: Weight::from_parts(100_000_000_000, 1_000_000_000), }; - return T::EVMBridge::balance_of(context, contract, who.clone(), address) - .unwrap_or_default(); + T::EVMBridge::balance_of(context, contract, who.clone(), address) + .unwrap_or_default() } id if id == T::GetNativeCurrencyId::get() => T::NativeCurrency::free_balance(who), _ => T::MultiCurrency::free_balance(currency_id, who), diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 81f8548b..3b4e8e82 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -150,16 +150,13 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { Pallet::::handle_exit_reason(call_result.clone())?; - match call_result { - Ok(call_output) => { - let value: u128 = U256::from(call_output.output.as_slice()) - .try_into() - .map_err(|_| ArithmeticError::Overflow)?; - let balance = value.try_into().map_err(|_| ArithmeticError::Overflow)?; - return Ok(balance); - } - _ => {} - } + if let Ok(call_output) = call_result { + let value: u128 = U256::from(call_output.output.as_slice()) + .try_into() + .map_err(|_| ArithmeticError::Overflow)?; + let balance = value.try_into().map_err(|_| ArithmeticError::Overflow)?; + return Ok(balance); + }; Ok(Default::default()) } diff --git a/runtime/brooklyn/src/currencies.rs b/runtime/brooklyn/src/currencies.rs index 7bde0391..2062dafc 100644 --- a/runtime/brooklyn/src/currencies.rs +++ b/runtime/brooklyn/src/currencies.rs @@ -31,7 +31,7 @@ pub struct HashedAccountMapping; impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { fn into_h160(account_id: AccountId) -> H160 { let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]) } } diff --git a/runtime/sydney/src/currencies.rs b/runtime/sydney/src/currencies.rs index c37da33d..52baf045 100644 --- a/runtime/sydney/src/currencies.rs +++ b/runtime/sydney/src/currencies.rs @@ -32,7 +32,7 @@ pub struct HashedAccountMapping; impl astar_primitives::ethereum_checked::AccountMapping for HashedAccountMapping { fn into_h160(account_id: AccountId) -> H160 { let data = (b"evm:", account_id); - return H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]); + H160::from_slice(&data.using_encoded(sp_io::hashing::blake2_256)[0..20]) } } From 82104c83ae1dd9da41dbd8d07d4c48d5437d7ab0 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Tue, 28 May 2024 20:56:13 +0800 Subject: [PATCH 21/27] allow from_over_into --- primitives/src/currency.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index 365bd076..fa10eec6 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -1,3 +1,4 @@ +#![allow(clippy::from_over_into)] use bstringify::bstringify; use core::ops::Range; use num_enum::{IntoPrimitive, TryFromPrimitive}; From d4b789cc8944544f979ca6384e98ff7ddc9bc00c Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 29 May 2024 17:25:54 +0800 Subject: [PATCH 22/27] update DexConfig --- node/src/runtime/mainnet.rs | 62 +++++++++++++++++++++++++++++++++++-- node/src/runtime/testnet.rs | 44 ++++++++++++++++++++++---- runtime/brooklyn/src/dex.rs | 4 +-- runtime/sydney/src/dex.rs | 4 +-- 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/node/src/runtime/mainnet.rs b/node/src/runtime/mainnet.rs index f1d0aaf0..ce0d997b 100644 --- a/node/src/runtime/mainnet.rs +++ b/node/src/runtime/mainnet.rs @@ -268,6 +268,43 @@ pub fn testnet_genesis( .flat_map(|k| vec![(k.clone().0, Token(GGXT), 1 << 70)]) .collect(), }, + ggx_tokens: GGXTokensConfig { + balances: endowed_accounts + .iter() + .flat_map(|k| { + vec![ + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), + 1u128 << 70, + ), + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::BTC, + ), + 1u128 << 70, + ), + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGXT, + ), + 1u128 << 70, + ), + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::USDT, + ), + 1u128 << 70, + ), + ] + }) + .collect(), + }, oracle: OracleConfig { authorized_oracles: endowed_accounts .iter() @@ -333,8 +370,29 @@ pub fn testnet_genesis( min_exchange_rate: Rate::from_inner(loans::DEFAULT_MIN_EXCHANGE_RATE), }, dex: DexConfig { - asset_ids: vec![8888, 999, 888, 777, 666, 667], - native_asset_id: 8888, + asset_ids: vec![ + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), + ForeignAsset(8888), + ForeignAsset(999), + ForeignAsset(888), + ForeignAsset(777), + ForeignAsset(666), + ForeignAsset(667), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::USDT, + ), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGXT, + ), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::BTC, + ), + ], + native_asset_id: ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), }, } } diff --git a/node/src/runtime/testnet.rs b/node/src/runtime/testnet.rs index 7c5cdcc3..a6d5bb33 100644 --- a/node/src/runtime/testnet.rs +++ b/node/src/runtime/testnet.rs @@ -304,13 +304,36 @@ pub fn testnet_genesis( balances: endowed_accounts .iter() .flat_map(|k| { - vec![( - k.clone().0, - ggx_primitives::currency::CurrencyId::Token( - ggx_primitives::currency::TokenSymbol::GGX, + vec![ + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGX, + ), + 1u128 << 70, ), - 1u128 << 70, - )] + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::BTC, + ), + 1u128 << 70, + ), + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGXT, + ), + 1u128 << 70, + ), + ( + k.clone().0, + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::USDT, + ), + 1u128 << 70, + ), + ] }) .collect(), }, @@ -389,6 +412,15 @@ pub fn testnet_genesis( ForeignAsset(777), ForeignAsset(666), ForeignAsset(667), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::USDT, + ), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::GGXT, + ), + ggx_primitives::currency::CurrencyId::Token( + ggx_primitives::currency::TokenSymbol::BTC, + ), ], native_asset_id: ggx_primitives::currency::CurrencyId::Token( ggx_primitives::currency::TokenSymbol::GGX, diff --git a/runtime/brooklyn/src/dex.rs b/runtime/brooklyn/src/dex.rs index d6f1d755..35e24b31 100644 --- a/runtime/brooklyn/src/dex.rs +++ b/runtime/brooklyn/src/dex.rs @@ -3,7 +3,7 @@ use frame_support::PalletId; use pallet_currencies::BasicCurrencyAdapter; -use crate::{prelude::*, BlockNumber, GGXTokens}; +use crate::{prelude::*, BlockNumber, GGXCurrencies}; parameter_types! { pub const DexPalletId: PalletId = PalletId(*b"py/sudex"); @@ -13,7 +13,7 @@ parameter_types! { impl pallet_dex::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = DexPalletId; - type MultiCurrency = GGXTokens; + type MultiCurrency = GGXCurrencies; type NativeCurrency = BasicCurrencyAdapter; type PrivilegedOrigin = frame_system::EnsureRoot; type Currency = Balances; diff --git a/runtime/sydney/src/dex.rs b/runtime/sydney/src/dex.rs index 44589a55..48ccbce9 100644 --- a/runtime/sydney/src/dex.rs +++ b/runtime/sydney/src/dex.rs @@ -1,7 +1,7 @@ use frame_support::PalletId; use pallet_currencies::BasicCurrencyAdapter; -use crate::{currencies::Amount, prelude::*, BlockNumber, GGXTokens}; +use crate::{currencies::Amount, prelude::*, BlockNumber, GGXCurrencies}; parameter_types! { pub const UnsignedPriority: BlockNumber = 1; @@ -11,7 +11,7 @@ parameter_types! { impl pallet_dex::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletId = DexPalletId; - type MultiCurrency = GGXTokens; + type MultiCurrency = GGXCurrencies; type NativeCurrency = BasicCurrencyAdapter; type PrivilegedOrigin = frame_system::EnsureRoot; type UnsignedPriority = UnsignedPriority; From c3fa93668f9fffe4390c78abbfbe47af92f4fa46 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 29 May 2024 17:49:31 +0800 Subject: [PATCH 23/27] use ForeignAsset in node/src/runtime/mainnet.rs --- node/src/runtime/mainnet.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/runtime/mainnet.rs b/node/src/runtime/mainnet.rs index ce0d997b..6ff4bb81 100644 --- a/node/src/runtime/mainnet.rs +++ b/node/src/runtime/mainnet.rs @@ -2,6 +2,7 @@ use bitcoin::utils::{ virtual_transaction_size, InputType, TransactionInputMetadata, TransactionOutputMetadata, }; +use ggx_primitives::currency::CurrencyId::ForeignAsset; pub use ggxchain_runtime_sydney::{btcbridge::CurrencyId::Token, opaque::SessionKeys, *}; use primitives::{CurrencyId, Rate, TokenSymbol::GGXT, VaultCurrencyPair}; use rand::SeedableRng; From b4f6aab64547b8ff4f16063983bf8e0b3cf5d676 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Wed, 29 May 2024 20:24:58 +0800 Subject: [PATCH 24/27] update runtime metadata for test --- .../scale/eth_light_client_brooklyn.scale | Bin 362573 -> 372253 bytes .../data/scale/eth_light_client_sydney.scale | Bin 362559 -> 372239 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/node/tests/data/scale/eth_light_client_brooklyn.scale b/node/tests/data/scale/eth_light_client_brooklyn.scale index 001cdf472473ba5d034a0293dfa65f8ddf581a1e..8b0abb6bf0bbacefe132a08a9a3d470b61b98b87 100644 GIT binary patch delta 14142 zcmbt54Oo;_*6;nB{}~5iVE7pwR1^>p6jV%9R7_I*1H!~_L+brEl zPwqzM?)tRux0KY{o0b)Q>lRy+b2bI!dS*&5q)B3AGBhCH?cTZ{e-Bm2XhtdzX-%v4^;$?@>rhHTOq-ftL1y259$ zd@&qr96}xX@C0KTafK_5StL0e#=j}ySB$wNE&QD^n`DMlO&KIVTxQB9Md5o)<4H;Q zCDSxsW+0Ek@p{j^6&(64)++y1F)@>X4P5eucbn6R zFZ_miIPr(SHV-4UVW%a9YzR-X3@4kyUP~s~91dH?kZs{tEtB|81GyzUM>xZ|_YWjZ z2ucqxwGJe^!?o5dvM2nwHJ$7Yziv$?&EZa~J7L)M*WXwgSnaK@<5G)(++E|Ts`7@G z-FoY~aG}}Br%O^PoDQ-$c%YCOpBZKQehKM#CVkaJLOQ~p)%njn?u&^O!+-rrPzB0b zQ+Pp@H-gkv^$jKM;m-mUocMZjr5=r&c)!~Hs zDwmD!-vnDfpmWI{IQ0QNXS=HD*oQQW>;-ayHf*$v$H`t+6ZH9gA>SHrox4ICOhdnJ z>@n&pacQ@XWT?f34gM8@DoN^@qAp5Oi`MuHD=UNEx;lwSNjP^oIeB>o>8d8lN$mAG zqsL2B%HB955cK+Ptu9oC!6hppUgYHx5^AXw=QHpA%?)JYD& z_b2FJ(hLbF>B__w9a-LIax&b#>j4j(q@!@sUpPr0ckRcinyYYG81jVb>m;c~CrRAU zq-)Yi`=RW;n>03krBhuq)VStCePX-^>S+XOnyoz!={ejB* zDzAMS?nKT@VX}+P9nsd?Uqn4n*RR5qhy^YzqD4Jg8x3i9Qu_eO{!MAnQ(d>x8+6wN z{NXplNpbG_YMdAM@@`#2{av0VeHw0gI3M1+ky;X#hax1)sy&KYF6+iLK=v{^3WnTC zorCRv?915e)=+yC7#bH-2kB+%7++sg=?Qt4t?*QNsw=z}Vp+Q?uwyaJ>lJzC5nQxF ze*i7O+?5kcCrQ-uhDPP~s8DxcrQ1_cp&+=IBl+?lAIi(H?R}CCgP$Qfc;Z|8ECCxF<|(FMqxSO6I86T zFy#}PWk*5-8CDahLxWMhGH@Dh|AZ!!PWkaq=+E`EO9#6@WeM_}FHzU&MU?bQlyLJ` zw3J+ekG`UZ@$;K=G>u$_H_y@d=|oS46|M7yP>w(lg+O`Nc!SC&)}tlB2Ca_!FJ^`( zt$Mly8d!8Fw<;7_->dAEEFmXg3?nPfkhPy5loTNzL z(8FWrX&Q~!%WdbWn_>aJ>Y^porH8kYs1p|ajUJ=PdidR7I!wOdYg$5BiarKr4WUEi z7rvpZ2u;(&z9BRj(nl~eEcllGgJjBczN5Etk|RI+4_e1a4y0e9gGe3}U!f!LQ+tJ` zl6?5Z6*`6#z?)ZS4k>t;O)(be(Hs=&rNZsSER_^(53*6jv;9{ro78T9n~f#)U?S`~ z-k>L|;C8}dVHshGWHUTPSUfyTSOVFil*jRHdJ?Da$0Su%5CU zau|M3*%;CWrzp!MN5H`lr5&a-Hi}veP|w(S8fAc|7@J63aE@X3$uN|&(If>Hah4U8 ziKendwG~BcywxEo2CRBE6rSTKMlqZ-upwkV3^1}ZvIN|Mxqup&8_ET9+e`GsJ*~=z zRA}F&5PFi$^-Uo(+c21REArhRUSjmNwLQC8toVJW6@Ok4cmSf6%jN;)U1rEG5>jClhCSJ!qB+L!qE= zMSTc6^J*OoF|h0epPpna@>U>{(#a%A@+qrTu9y58($5SGog>(1VAuUvZ!TOtRoXR1 zmfQ~^j!F$sXvVqw&d97$8*soqBH*d9L2DatVlG#so@7r8R9AZ|LcTz?a{dpiQ0Ea1 zXbA*Os5P75mnN2d)f6}OPH}45COvn~tx*^#8wyz(>~jLuI9kcRFyQxcsSyW;Hf6KY z@u+L$*#eC}2Hpm(W;W&;?Cr3704{rqg*nJh*c#0Slijc{nq}abdomhZ@?)3{555QO zs4p$hVps7zPHeGT*(h5RF6+ENP*s$s-cgvrZ)I`Fsv9#Jp0lzcQG3wBOk3r_8LCoL zYmY{;!^Tpuzh2xWHkN1Y%euKw z;SL-uZZs_C{@8HGlS4ZO;^yl&Uf3PSl9ka$!}oS}oweT>V1Sb)!6`e_gExxB{ClR8 zqH*sX)@Iy4kU9Sc*likiLo|#1A7CHRu^pX zVKmgnp;0`pmEVbD=`knuB)1fu_CS58+X|dix{rsEPBvmdd9QU)PD_Pwh5ZaFi$a5E zg1<(R&cNGFT(+|s*9q}#@PJMu5Y1+E0-#YVgqs zEbXd=yfT>OK~ut2_?I>OD~Nx!^5W1*0?UD)B(k9vVd(Y=B>`PSaa>oTxe=aEWNFIW zsEBb%EbB)U*Q($rLqigC{Xdt%1>dA}5= ztkl&3<+@pBT)cryEUZ{v9avlCt-RIiSI!zK-T++|JO;M9SsorwsvMuWQI7w&f+cIS z^~ez1$p05+gH!OtO;MOk_^~bGhMmLMAd&{p4P*J59Y}x^u{f)^+zM@4nxU_GK6I^l zKBSrFOsGu3K5}4J3hwkgcrFF`=D>RhG-Avp(R_oH4++EBOk;skEi_1luzEP#MT-nj zo50gVSkj zC@nF-!5QcUjYwxx$b5NKI(wSnL7tew*3&WrJXT8Gu(TLY_*XL6QnEx&&SV=1SpvJV zP=m`2(7uSq$RA~~P6PEA;Gs&IB%d9JtcX`m&u7ah@xlGqu@4M>gC)jSS63e&ZG%C=ABI~+I*(4;Ag?cEe##mR1R9H&L%uSNRT8XP zprwMw!1^M##I(s^NeX&vsyr3Q+adq0h%IDvvjHZ}=kfCLVs=4Kw#f76Gc%)G3_IrX zSO}G}9Md*~#ToRj^#m)!?d1;mV=22HJ+8t~U`C92 zaQ$d@ccf)_c#|UT5iZ=H}_ON z$zyXOl@wS!mW_*4f;||M$FT>f0BIHo%?0yW+sMmK@#9?&qqry4`vK(Il>k=hid z3$ze1+KkQXmW2Wso2fBllH-hyjMrSliHp14+#{MChFbJK+QC)J5@>sm9I&z$gNP3J zMJ1H@*a?*02et%L>I?gwtzqPd2V)x0sAZBoIc)8X<^^5IFh}L`4XuuVeWp zhe8l#l;Vx@z3UVU;L<2vZA9xTxesNsg4{-=6gd4;T(vY6RU1;`-5PpkAM{KG{cb4- z%5P&?1M`fMLGq)MBIOyCWtGrrxQ(sBa4}{Bn~dRN=>|5R=J)a(OAC4{!$#yshEmw4 zheD-?e4|u^Uv98VQn4}om@5$ix3f1%2~66^3eZ&FwvpAE%2br!=SoZ9yN%dwIaJ@l z=A-d_`3{y&%e7HEJdsYkeLC?#P9vLZ@+y6KjFL}7h2=gTP5kg?Bf9*x@Q+5^c(swH zpWTV!S3T^yla-JL=)4mZa|2Adi=~X)VC0yC4tl*Mo*Dz6MI^q6*ijK0k-7SZZZb;v z!_i1~X|vMh7NfKU9=(elFl|%ee{f3MVcFem2cE+CNdWsMHZ{6QLEUYX@Tbhg%hDcW zc==GbylE5rQt#TUv^E9jFAywdQ3zFqAl{lv~WF6+tbywCKhvy+8%9 zMd-__<)eU!gw7q0uwjXvMv^-fvsabg%7qx_R^KWSXPuhL?S#pXusqtSia(Wh8N=11 zoN!<_v&bJk!Y1j^KX>h7PojVR#x4x%FUjBTLWhH1*6<0Yv}JTwmF1?wB=6eIrZL=) z3UH8vYFckK_3lTj3Fq2Dr6?1O-h(cH!z7pQQ5^nwm8QUD(r8lp&>*Z&7cP^OW(wP=O@XV(yO0H;S&nr7~ z@L{$YkGH*t(aLq0!Y`L6$mb8U2Z{N(!p49X6Vgejc@4vz-@eM`U;z8wtE>q3Lcwb| zmeWehay(VrUqgqi3*4_`q6Gpd9m&PF8c>?7e>m9_m6lR6avvD&3DN`zx= zc;;W!y37AFn~MFYT|fF~cGp$xFKZJ(%-U`d=H4Af%!=ez;*cPrDX9O+!~c zc$8d_GNHYT<>co?mLjjuQsihjPALxy6l?j)x4;evp+`P%clbH-0?#Q>$KJkyFa1va@)u35r(Jxioaki zf~WgmP^B9n_ft&!Y)~d@8flat|CCLkv740cH=8B=;r34BTg*Gnc$Rf2!B=a`_{4m&<)L$P-7b2h@bU7?HDOFQAq&rv~|Am$6qtTw^eFW8X8CNr5?R6Gx_ zAM+P@E4;p%&~&_mz`F>k3F^LJKN+yyOx%iZI6H7FdWXB=+!t)bq&>K1S`t_y+3FRP zN6oa>?d@Gm;tcrxXq1}G-T7c8X^cGf$n(#lX-M9y$d$&WX63ubEVU?K9MXQ}yTvRW zkYE0i=@jqb)vs8-xfQ|O&_%PQ!?O7tn@ee%8D4hLA#nR&*|YSBS-pAycRDwN_dI*p z(ykIXol=KcyN3Y0hcH6+1w2=do3*=$FE6mq&^1uz89up)Ynb{s=0jWb^S`0Hj&`aG zJp^>I$I`Rr9TPBwANe&tIOv2szGmZG?K8<+8PEWKoCL zg}=VY(&B`LOqq#SQZuTxkfTm@*Dq_Fu3ThqQDTvge#?HtsIUMQ66I~*vx7Qnw7}f& zXyOyA2)9wIMY%*sf_nz=fr#;dR_$F&(> zm&FMMQ9K1U+xg(wWDAK=d^NAsFX{fGohKxvSd_dx-U)hxHJ)Io0rw8=BY4AN`p}Y z`5a>=j)dk|FjPP;N${(IJU1cFqN$n7S?+$BWl1WqK&=Cl zXqZVfz%9|-F`}?{jBfP;9PMv!=8<5Y!;c4Y5j+yjlTrSI(R|Q=erfQ+UY0XyQE$Zn zz8D_Av5zn$wL;6&eUY7VSXHU(gu}_ z3+{{iUvk+H5%ceHJOhn-ij#juP^+U7_)@%^#E(d^p0i) z&4Or43{s22X}<--wU932Ka3Y9H|OvhDY44?b9kMZ3M-@+@GW|y)nZxc^+L-G?$lY;3bcI6qUG}ioDdd; zmQ%@r%KFKCEuju8+%bj6GDidq%~SYP8jp7fQ}{T8%c><`H3riP`DkiRwko@=2;U*3 zz#Y^0B2${x;tT{m6;)cFcpH9c8qXyxr@N==Mf?VWp~yoh5hkvGI|GeLzWnDId@;rR z##1-&LGqMhyqZibw32xX)QqfmfpQB|*ApxkDrmQ$vt*gYhmc}<)GYoLMT>N04v&M; zbNCyW&%iQ}Ei%mIiwP-%^Yc)FmdFM3`3e2da#iSBfh*^U6uX4vjT8~&vub&$`Ac}# zK);n_sOgA>-jI4a`C;1<9%HLTd`bC3kx#wcatp5^QyNqzc4W69!VV#g8gP?U!k=>7 z3%p;AG;gs=_(Kg=XfU3txS3}W_x4EZ57JJx^aFO$6oDaRx7Hi(h#^aPETwy`YAzP$ zF6XzInV>R@B-jpzs&x$>(@Hu0ZI{UZPkK{Met_ZJ-5nh-2@VeL^ z-<82Vv6mEH7p>A|Yu}8r{9p#3P3^?i|3MUVW$~DeMeDp3^-6AahR0Whi#4SO;9iLk zZ{@@uK;+pA;WK+c?x6ZK##=eQ2c*4$p}dz48DS>27ejkj!&HoMTIX)B^44Z%arGKc zm9KJvH&h?2UgW8&_ez}4i$Jk21?)zYdM}**kkvSZt!JFQ&$pCuMZ?hyJeDQ?LRqzE zMU~eb3b-o*)#$r~-1uZHfJm=^51}IWVtLDSaDK>&nv^;1QZSqake4m}BMVeDK;s(f!RH`;|w;8$P0P<{7 zo((2%L=XCzjXZ~&KFd=!}7}6xI~HQx1OCe52)le5WV!qPj@{@rR7Epjk{YjS8Zyi z(iAhcb`xT8dRpEDq+!sw84dRlcw;l)hw=D^`}s0*Tt0a}9%kgMJb4Q`5qNz!1sd<* z4mt1;pT#jycs|S@pqL1JY?jE3jhPv!s;nb~Q%t?%ORg%n0)W!kiQWE9qiRt19iR22~=7u@v-+R7C9=|}h*6fadb{*o`iJJ4gl zrsV zj~IFLF@6ujDYw7Ne}ZAzPv7O&p;sWk%g0e-k}tf=*K$nFg6~7_rbZL|>_a|_V*2&{ z5BWEkeuXzr@O&C?l8qtsa4Y#d^qvRfBb^a!MTL!FY%;q zluv!hZ{`@*Pdv}3;@oXK&zGPJc>Fvcjp4lI0{@!qezuDjQhZrE^=rPKG|Pv+=Gz&n z|HAM1uLwCTfBSd-td6=3@{?EiK8^)g&c#@qI^bfZGId-$s7%6xLTtjf;Bt&X2z)pW z2}Y48j+;)J-dCn@EZlDtza*FC;U=-2QcRZ}vS7h#hEl7TijE9e#rGVqVtzhQY(;Nl zXtYADlTfM3qs2iSuro&ZiATOCM$A@xj<+461V^15D`ugi~*-rX9S;7yf9d}aLzs$ERKt0Y&inYxrLIwnU*Ym&f3kIF2moG#bJ?x?H%yS z5K)B*>QO_*5RrzETCWOhhYDF-)xBm}&S^s#u5l z*2!t&BC2X$x_HQ%sdu{&PYHx3 zO+Y=_BL9AZIK@%pw@elz*iOqnMF}(DFOx-KPfcDpMLfuGAAB-R`~wy3qv@#7XvB&{ z8h!#rxMI6uOObF7-J^&=&Tvv<;Jqqka@RDB@`hH8u8=U1T%i2c#7(LNGGgvXPH>X@dR-#M>X1h6DnjoxNjCuP^%T%ZWcpm6yn@0k|>Y2 zVr1lAE;5~$1@RmB6ud(8)YS(YdNvp=SSoHnO>bH%RolVmY)@ zTrZ+athgA?MILlSF#pAAmzXcVxmvuaScNTq;kIrz7kx5Gz4F$;FB5hmur+V9thGUmm?oRBDl+iFA{?!a5ticId+p%LA(R?I}x zVXGBctO2nm*NSy&;b5)U$TlEE<*O8s?@|q?PAq4Q2vK=&#)8WGx{$D|V5}WNi)^V! zZQBOv^&N>@b!DlA#-6O`}Ll^VCVhn51wZoKqMSNkqid$Ca4XW>6@O(5- zdffVhB<0Rg|D!>@`z@{{7-`|_1&Qp`k>-9X@ymNf>cErMX}$leM3f>l6^nSK+tUxB z`~G^d$mXq945qFWi?C?5c3S)FNNmB-2tBVX-m1fsLD`iXFI%T;|J8(+UngB-DHNAo zBE(kI{~wzq(uT;hulI&D@$qg#`IjgBAEb!z1=c{wsvNe`u_r^+9VDD delta 12130 zcmb_?3s{v^*6_Zb`>WhJ+!Rz4l&gx0c|%1d#XBmN(GiYul*1j9CN(OXq12?4uBa$! zqN1|Vig_bHD`#>h`=n2rY_j50Dx0Vh;Hhmh_u_MgvbyvFv^eOwyr#Nl&_41|k=quAjmY@fG_gd0ur?1VDN{{(YVgI-< z%sPZ!F!?506Djo-SyQO=`S8Eh_Xq1(s`&nHO{0On1X~h~@#WdlXrk{v+XR~Kd($?9 zX8O2&9L@4gw5QW-Ux|Gz&G9wcN77v15&Lku$amI0jOO{Aj(FqpT9-rHhOuasz zV+^hF{n;@^)LH1wzWLJWE51L7Zb8sU-z`cIt@l+ZDRi4}w=$A8`2JmqqdR@QO6)6H z1EN>b_E&Bxoo1 zqJq)=_-j993uqI({we$R^0ZgGSPE^1&%0PHEIPpwvHz4~ zVp*_GkVCjOA&%_INMw8m_#Iu_=zp0 zU2x}5><~87FQLG@q2v;ah&pAW!?HJcs*#y8lrcf3*SjmL1?e-v?n^8@=zKrIELXLw zgm6N-;qWCklbtf{9LV>x9@EYvJfHQNUFn8bJ@yJ%8xV?35&2kHgS zr4;@u_%}?N;Y*tsu6`}~T*|Cw7(A4XR9$B7qD(Qv+F>jXepAjJ&}ZR4&_MNDE5A+9 zP<815Ud1VL703tC2>4qdAA!xlAf7;DU_uZdL*t+%h^J%oL=c~5jWeUp#G6Sx{7u72 zgn(e4O0!{FFi)d-P!Y_>(R_F=nBO2)nQ1XB4B=sLF_=eDFXV>s2pAp0BWZ=!A1`Xm zwA#RUB7{fNTG$`LQ&4Na4&lkDj?PeAw-s&-MK1Qhrcgds>@(96s0&5ScsG=X(>C}l zl&7*jGX#h63GBQXa>F>@d$>Og`H*lhjE|;PI2XoKLIUwp<(3uIl(@6kyGyG{2qB5k z9LWbmUO2Ls3>D#g2+e>!Q9O}OhBv}_3<7n8e}?nefOIpBol)Y!sX0Z2q?@60ln8}s zPCg7L>1g+2KQPlw6AZMawdHO?GPN-$bUIP6lMOs)1W!@2%+xu@?YXVEnvg6F9swm0 zJPSps)9Q%$WuBs8aU>7sIc5rPMe?X1>MVA<&@?PE(@Asm9vltlqqM=a$Xqi`TIMdq z0d1Wrgyd?cmt`i4j71Wokoi2L?~TF}_(dV)8werMJnkxla7I?ai5Na~Q0#(ocWF+k z2e%@K3k8r>U0vx}T~qBwW8>0s;KOJh6XQ11v>9ckrS8INPgyC-kq#@=MT({}9Rgxd zqdbrq!_%&jw)={-?a&y*V-h`P;apIzQ4wfckgg?QepxBXn*=N=^ST9b<5tnAc(v72 z1FvPO0tOHI1#k@%4B}(1!>$E7g2%!i2k}t45mJWp!E_7EAI_8LHaIv0M`DKZ0ki>j zj7LLQHke!JPFOHhN1iqkhhG}ZQwP-HfiEnp)U~J1*w3z5)VM8h87CN)At12cOoz=V zcA=C?G)=4b-+OB;-kxoKGyWdSGZcT)4Ss_qaXcaTI+>H5ekdQu@t6UPW*WWBU0H?F zB&1Q>Yy=F#ec@HqH(oG=hy2pUC!otZI07%}^;?G_v3x8%GL+vCaLs;Nex@nGGK>%W zzYsn;40qgW%(2IF=f8r!$3PDs&cpr{^nDt7=D&j3W)MzEz{}YV1JdzMAAnVDZ+nue+?K+PJ`Qaww06!z1~Kfmv6qhvqqr$?2o;;v7cp z(Pp6o@s<;UesmNci@sAQ|IsKucwi?QvL)_{8h2?S-j_~oOOX(pgj+ghV3j8Ep|&eJ z1(Qee3~eKc*B)h;fqz3XA9|Gzb{p`fWS)4fHsijVN8?7VDSU{d$9y@kAw3!!5wI`? z4R)_Fy)A{O{DSuO8D|idiVo|4;tXQIJDLand=Tdi@?WL#`2R2RkuYU64`3I}uyFL1 zbJm`5|F^Jalhrq; z@{N>Dw!p0`SO_f6LQ9*a-j>Cgm1SFC>y2WNT7M&-LTQfr&Rkx=Xf7no=O0@aSsWpr zs;U|{bW0wr4qCtmbM)m?7W4fyU;SY*x6zP%O$4hf1b;+WvP~`%ajDLw+{>sNrmhy@ zYSS`aM41~`UxUGna|O@0dn}IVN_TmQtI+LRG$2@ga0Oq=nb!gZPqT0pS^wTlE7b1_ zxt+5L3+!Dh!XW52bOJT-KnWiQDa9BN*20+*zSwBOVWk%>%oTVzyzWJL?3 z3V{&1j@MoWJhP5}fxZ@5EHXg;-2F@krxjnGq47lP)#pn2VM@2DmF4J7XoFf`!B08R z!Iy19;w{j#i7&)v;%5FJHt%jmeQJR(H}m+*X&z>Z81>%8omT-W?&5FLMwog(&$BdX z$8?4?!{hgBBzJAakU8lAJ`3Gm)dPGuYqjW!k#9c@ov_D39MoA_R_S$>?6FX>l+dKI za(5+W3uUE0gNAusrA4mlvdUTmhwMS3i;biz*p8zc3aZO6m(jDV=+MI^I-&oHF25Wq z?$gb%fA*U=*H(R8K^poiIBhh1! z7*dZ`V3Chcvh`|ndMu<*Upy`JeE*~iev{4{lg{~grtN};f8IhaT6`BDcB%^==4Tnh z^g>I9V-8b;X=%N}w6tp5ro;*jfaj>_sQM;Hg$DZJ1!{Qrl29we_R%mH_6QFTim(z3 z@uG7l5mxP(Nd)9R!q;O~_Vy!uDyCzikuPE~S4a+n9gRGQ#rZ*o$5;)f;{6tj*A|Ph zl0?oyxGkN%f+`{SSLf6xw`^;p#f2lx!mdJX8HP-bXkpP$C`Y2prL%u+Kfq7+m*Y8Fuw#)+OA6grAnDXmSgiR%!veB7q_WzcJN;dmTQAEEi@bo-sd;s?Rx%w zelIo}yXkrTOXvG7ou`uzIL1i6wmLqp(jiWl4fAwu4Gavl*;73Ivn%{&Bg{|a-s?r~ zMPgdctuy6>RUhzTYlXIu$3|+@_dehq9G&aqAECkDXoJl!Amg#e`O~&Kor$ynvPEAU zE*-}bN4?GB3tS!#6FkTp#!}WceSFs^JcKv&4^R4pCn`H_SQB)vFRR8Rwh<~n z;iE$kq@8L~o|QCeEZ}pKK0Bege`_s%TWi*_(`i5eY0_?KZgd4t1(c-FyeNAJE8Hh(gIhi2VXH{}rEOjB^N{{Tw5c zF6jLnw{l1uxfOkJ-4__YV5;~frhmub%$Hb;IjnOyqNAU~PCpJibkYGAIO)_F#K&VA zp(wcf6h;cijpcey@#(mZzVy5=`90T=?>5Mv>L=ghNB)#fUZGCXqmjqQUW0tWQEFBn z{2M>TS)UE!&Y%&wkKjS-f<++cX^G=ETBuwfB!M=$Pu&39;H`d75m*dlkKrwHvCg%`g=^VAL> zeuvq(6)t>--uHq|u3*u{tF#ztU0XT2fC4}*rgndAm-g%Mq+Q38(0PVekG5Wgu3V3< z80cDq9_I`RggQl}XNKAh+ZJKJV%tIu94Cpu4#TGyt&Ou2{NZGU#@jKi>F(o~umIcr zJr8pv+G)s)n#%Q<&?jpAL_qXe{s&A~PMqaoiOF^vJIk}dU6eC!ETOTr1!Zg2pxe0$ z%rFqJYw>p!WS+xFH(etW>^oX$RZGtCog8x+_7DC!wPtF(OtxcSaQXtDWzVwHlIfnJ zxt`LZU8k`wyW|HggMs27xYwSov+K;VlN>nt14e1NIsiS?A{h2h%;WOZf`9UtIXeHK zOZ#7|Hbbud(jwF7JIG*$~i=at=tLFg8ET!;}<>hY+IS}UPx)s?Q&Dwkf*tlDqTqSV82{~)vB~eqh6&_%%^eNG`z zmQi9PyQsrbLa(orQil_|W3<#YNsJ7W4jQ5bYHmXPi`Jz{A~M?Q(CXSK6L)2~tFpQl zFB!f;((0*If$(&an8l<6PR5|cLQ-}JN*3do)gMxxETWL1ty<%O=aNNixZXmvObym8)=x!5XPAXofbXc1z z1`WKbjvRl5O<+;jBGB|A^+7NJ`~NK(u6`Du8zYjaTRk>Ld_z%@4`zs4 z@WmfCPIbaKkwaMpB5LV!M}N9pgVl`7Iev|HXdRT)sz=9*KT}ND9?2B7_B#Cxdqfi2 z-{^@V7i%(WCyE%YCi9yc#QWyZ1`WZ12$L;jr$(dEK^mcK21=_5T4spBp-mbTN1OXe zVYkI#WROQ1{> zfWwl6MVb4XxKVsfF}PblPdtoo5$w5Q1v}+X-MOO5&Uzg1@d~lc-0N^S*0|l^S}mNWKK)^* zO9ZP=<_k*Md52!-Q`ME?cFHa|Anj%mrnP$YZ`I9WI=kqA=9|TM3ssErqCWfV&0;jO zV*w8DQZ~MZ~>gGo#?!MGA&x{i8pUje74#T%xWYhLA1BYN-A1 z*W#&RF4XfY@sPctAA^vcaNnI`1r`-g+$oA;niNY&Ng2i_7{3^vh)`i!mWKS3X7$#M zBF&6di^uLoLAB~TPt!{@Y>)8}pJeFtK1>NN-_L!x6iXs)`idlpv@1})iHE9BZ9#t6 z0R`UNF7g8oDk0e$Fe;*l6wG6L6-anc%x4D`*zlmZHynXPL?2c>kOr|gfOYi`_cn_p z)~!I)Qy4NKVIoA2LV8dUp2B@1FE2eMRt8_q;aC(%pc?gC@mGOWowLu1n;30Y7d$VD zDa!J-7sSNnEfz0jylxdSlYo{FzG7q={XG7?L1^zuaP&P>dh$jCwhIWOW3*#{55DE88J$lfCg=mE854_XM?p_=y!C)P*R z*q6m>fl<~yzZYBCDGLOuVgkdGZPBwa)-Eb{(aRmD5s*cE7U^R&2i$f!oaU-q z?Q%ZK6h3jtBj`wi~3Hm%wn`2Y+>>a zd_S=zOk%dyq(()`rzmYz--wdGH?gBcT|Y$b71)7<5po>Ls9=O#qseH5+^+3*S%Tbx zU%;uKj+7EVmxIqn$qaeGcF^__Wc^l*gT+bmG1{%3PLewr>$Sm_RJqgCXT!sN74~IF zCrn7g9R#WcY4QhwW$Kj~atB)JZ!$D8CW2ZPKTf`mTR%BYdTF*gf4rQh+3Lq8$Xwii z&jdLa#gvgL_wro(BKRs(Zo^<_{Y2?iI!(i37rIJH-1zZCn|fxVtkzz2xu?i@%p4z> zA~OT(Y%aUNbUY4k3a;gb52nai3_#9Lk#q2^&y=Zh3@TFPRGEc$`qioO7I_@enjn0d zoD$WnO`ViwWHn3ht%>V4cNL`;##*3!noN)v5VuurnkK)bgYo{7VKe8HRbx25q-M<; zPoefn5T-R-wDtGEQ`6;fDa`~Wd)Ex9<+S#h@*&=4ze^KiEW9;S9+FlZZ-@J{WeHZ) z|DG*}NChDWV9+c%67#g2S+d-82)Pn&NSiHF;q)vy2~EPN*%D1bCv2Z9H(&wEJWrlS zt-Ux;KBxqmV`G;T7Q40Yo4VA-Txqjlas(}Ta=4Zob>zu8{JcF0N|wnXFmaho!KW-( zw@l7um=wLXOy0;Z+9}B8ax#x`#6k9QIg`818L)M^T*xOoI^l#il!cwaE94}ejh$Px zPL3lNnpViEe32s)POOkec)HmQFXhXLJkOC2-{d3CDu)Y3u0++12hUA%B)qgzj+ZgG zV>f)gQWoJkEx1WW7^5jN(L$(Kef%crp{5E43ZWbp?iZmDyGkxWA78yno)mZ&@>a_c ze4}HpCe|c)VYSTq`ALl`l-oJpkmuLPf1=_&a~oIEw;Qi)m>dYx{#ooeWX}U=M9dXYF9B{Figl-td+&+I}fgvYGmgBY2F@q zXr25sYQf49=@D&?cE_$4q))av4msY^SWbfnz49+OfWaV|^khlB66+?NFUocJ>7po; zqo~YANgRi<<;ZrIdP})HM)3lUt(3btUYKJwG7$s7->;XyW2Rih>~W}V8{`JTdL59u zQND&6^3_K9EbDVX!zMWdqd&E6lZ>cOF8byB^YErZh)JPGGA7k({@mr1Zb znW665F5l2hMBWY=t9UJzD<=eZ?~u>p_jDs0r1r9TWrJLX&AtZtB+pW6A-YlK@oen8 z@DO%#uydqQF5?w47jE{+G&HE&d}tW*;X@zZgjG0hepqhMJ9j@UH**(4bYfZuiOq$+ zoif-!+$C@2ZUpP3z1Tt0S-}ZQN?cXNOVLQx>Xt*p&<0>R$UAu*3afdYjNk;9{vMEn zt9h<9mdWEAFB7ga<}XM4fE*_auL)IFXL^hJ#G^8Z%6b%Dz1sGebfT|>_a2wGqsyGt zgeFHcC_5G1wZi{;Le`>BD1TBGO5UjGZZ8zRc^a+3&rfq(WDaXkAZwirhAGd;@o>@) zq9WwqDVj>#b233`usHkQvGUj9mO=&sE~7u05utCFmIVonfK7OZhQLe=_P+7<2x#M@GsX J<;Mu~{{~zhw7>uW diff --git a/node/tests/data/scale/eth_light_client_sydney.scale b/node/tests/data/scale/eth_light_client_sydney.scale index dd25c98e83324ac6b5651b53a1fa0de4e5aaf50a..421edb90f29144d945528b27b32911a41406a36b 100644 GIT binary patch delta 14175 zcmbt53wV^(mH&Osdxi;lOm0I2(7qM zjAJ}fjfgFEp;Dnre^F6zjT$LxR9sL2u~Lm1F>2h>itM@nOp*z({kpr~H(&mH&pnU( zIQQIh&b@i*zL;$v#pu0mzsok+wqJjakpqD)wvfE{^fX?;$;rS*LpJFOJZ%_5x&wc~ za!(-2IE+T?0~3wuBq?x zF_u))7?@-kK{f}>x9qHrWzx zBFCQ|v3e3A#{>I+mjCo4o~U5)_d!75!8Lb;N^>jSA*8O#?ov8`Pgi(wCMuV)~*plw71Mtgo$g zSCxC**z@*4!98Vh1At-pGw*u(-d{d_FHxVqmtJ2&TXpdER2~acJj@1(AJCYAkOd#m z_?%W985t7LP+Xyqk*>NroEA?-+1SgQCi+&ba@WEikPLqJ0nN1T(vg&TwH5B##SPVN zXgWosq2~j7)HaY1Uj2|}k=@YqA#K=TnTQi!R$c4ydidt+^bs9Bdaq6~kPN?Tjk~tYC#P|*jznqmsgPW+%U`~_ ztO7Tur?T!KeEks}O7?>76kV0DUq@DkO;?7qfBoRjQ*;d31^Z6X$C3`<q(8&~Q>V3=T3DyU`uav$;Bp8t%(+bQ*PmtI)oh3WO$}Km8!|SW4 zuXKZBAH5;1yK+YWJWL~O_U{+hx~l3>VV!k8 zFI3(@6JwqARXEGemAyKLTD~$%`4o;UBBKJw9~d+u!!K!E<$hmn)=I66^kr2psj6kY zR0jBZDIEiUd6>pJiT#yuF>YrNw@<4B9f4@lFCaNwz{L9M3YXtqc8jahRaNe`5X-vN zJ{a^KO^2i#sHJx}MaOU%3%ouw8uM07T0BLemOlq6oh}XP^sREb%F88!b0xA^d9`5% zR{lBz9{LkmWITpTF04w24kBJ;*|6bLHkcmQ!M>v`9!{L0^XN$(oIg+EAZ`>hL&?YV zadHa2`I!D&&M6&tEOgh^SNaWnF*&Q_MWjsE5mWhHOIORj8 zub!pJ(qsc&wh3>WPT0d^osF^OmtCA}bdXgd=w5qfK7hz}@ok5Y%-9?|L zLJz~frpu^N4~<{b;j;cXeq)V#ZYlJwLmeasIPP@(qbOEAeDpOPO(XPRJWrQOCa&`| zCc&sDGZ1-FS{?32PkDy3&R;u43X9gm{pV>qjnk`#&QmAF0-WilB_s(lzolQ&WIa4O zl%}XtzC##G)kne9VRV?f?|ZtM&~!aK{|y_iPX2*%LNoO+mGA_0#edP+oaCr`{z2;) z$$=r4=n#?zlP}RUmZvua9-HNW4VS2eg^dw`cyL?iR_Y_6($ki#;E8ZYdqk*BL6f7Sx;3Qu~ zND`?JBCIyDIgd1j`EP9w7pZp85x`2Dq>Tk8F8JT@A`F-DnKQc{zi zWEc9Xs@&y%kFQF)4JqZ?45CFXfeI5FNjAe)6U)AAa+~DjCPNqU7`0i?9rLOsz1%;@ z(O{qJt8(KGvM=&^-CSwHfub4N(l0&oimq)9HEuJrD;t|bjc=J*Y{cb*YJsVPQ3GNv zEShYGZBc9}*$GcYu?#$&--^VR(NWBX2jZP}HY|3(o=jWnuC2q)_DzhUY=@j!MBHm* zkq~WViPl!sf%(2#O^;e(ij_@7p8Ys`tZbNl7uuS_)h?X7N~vzUf-`c_ih8;`40pDT zM-j=I{gp*a@!l{V(D?Ce_Wfbjrvps4u~sO$fneRd>{w@vnD;=h8~9_;s;NEY+2 zpdSmO*GI9qe+9iGh`uozyL}uUjmDjQ680yei8>2s60z0^WH=g-ZkQUwMvxv@kc6KL zuwW>DF2ar^HkuLxoQ+{w)M$W+Sk$HCazSo^?l?9MUX5j=qE6{a?qc-%ef9ocGjU4F zje{fyOB+<$Z$9MFDXGW8W(Ui*pF@R_gm`Rts}8`ld?Zsmv+5o>D+P~Hm>)Pl>I9XKVZaTLNhg}_|F5Rejd_*5 z>x6$x!Np03Jt-_dXdmL?%@~|&Q~=2#J>3v)&ktQ`&kqIdc_u7P#RE16np2qrosvDN z$TtVt5opBVO`-V)B_Av!*ev5@SuHRq1yDMI?I1;PaRk~6bPLkhJUqsdM`~v(ev;s& zG*&bKv@Tdnf}!aw0$v-5A~gyP@GzE;vLeZKb1XC>eac^n2AKy%V9Mb6#QX0R-|+3lt#6(fO#otf~J`~R_!ii z6@)e!Ai0PqLR}FiWj3p?7O@&ew-_LM0gr>yqJBaCtKCR16*8g%_7b4 z&|>CBXKTR{77L9x;OR7S37*IrU}Z17>_(iH50VC4yx;7pn6S?{hW zmQgeMwHSfeJz9CY!IFrEXiZ?jlxVQuz?SqZ?36hTSbIQ?glOAMkJ4Y;j*@OAgb5X2h5e`D59pP|FB7H}st}OzgO8 z*SagN(x@DRPpjD|v;~7|&|r0FJ%k%;Fork|_ts#Pa1z>U*l#d&_13b<>8A{Rk=j`U zYBc`AQ&x`ooI$}K?n5`VE1iab)fTIMQOlmAqziV{vo&~zMyzGmME4l@BDohX8i+&s z;~0o5J+N{utFT=#ki>;=72BOvSG%HQb3PEAy9B1MmqMxEFnf1gM5s} zem=qoE=lBH$Cew7MkEqO#TrHw5h98XBZ|<7VqyGxmT!udL=i?M&KNix84thT$t>!Q z_3RwQXsJ(jQacICP7Y&}EGgTGk_zws9M?KsqFaba=7}!!a)$Zo){Q2D+Nq3jFj+z4auVyP1vjodkXajn~3;;J_A*+k(>i5(TD3595X=w_pWKOC82 zSGGveTaC(A_|;wPps87dKjTo)ByM64;t7nOc%Ylv^vG6;y3?rOPtM9=WtTCqVz^UX zx0!vRPueY8_Zk)aNzQFV*{_uj7;}{aaK~0QnjBR3Y-QyHoqO9h`&w9{`a=NYhQS?1%t6VVX>TgAL$=1iloreh z9GB%9+;L}H(BVD>|7c-Tv8Ev`co4&hQ^E4~2ie2sv$A&119z-sE> zs8$nBb~IHYOpvmRrPFAWI&YWs{^K;7$w{UlO==ho!ouR*WYZOKZZa~(jg$TNKA(B}aXJ4|{@`^CZNOZ*rioB*zdvIV8FuO!Q=U z`bpLtSs+6 z)JsuVZO|Z&Mw8O0kp=f!lUAOxImBXX7z>1j&Fq#dXLbv6lo^Cj&mMi2d5l}7w9O`^ zS+yTz#~5ufLBTE(1>e2EmeTE}K*ZuW7=4f#!Fz~pH??Yg%C;*zgIy|k5jABOlDtet z!0j(${%JQn^&)fOC*mbmME8c8?sy3!tNkWSZ#vfc{Fpg70MER{#zrAXE@VcHQ8^$x zg7t$M=TV1313VHoz(X2#4zb&nBN7|yZ6-@#+RdqO+hMkowFfJKpOzZcIY-zla??h% zu`PHWKHSDe(c`AT3#IY!{24qAy4u)AVm>K38t~pjIR#H0#eMeiCq%%nUt@DI*6n-^ z{k97*=5-v_*|6q~ud`{Gx&4pV(YfpfOFM?QJ&@6k!OJ$XT2U)(-&SoNgzx2^>u<0naAMmR;*j<+ix~K^nNzB3hCCvSMl9=U?ti+)REK#f) z%_?TIb(~tw@a$V`6&k3aZ{seFFvFa;*#;VChQ~TsTIf3h5neJAvw2qTYXk?Pqj>S-ZPXSA2wlfpLlK%`!9k2-&Am=}KYUX~ZpsJ*S!1?9#gE zC^ai?7P2-_%9g5;A#ICWYPd5K1JPW49-gM`lQJm zyrcNNY>C+{rEW1R_`|)P&bOMkoAI3g{I3|4HN)J`aH*T2<}-{~THx-_*l?^p`58+y zwn(}-J*E{u`V6(A6?C6tMBfS{KSzpInEg2(uC3tyoc(N2iP$ zZOSfOm|1QY-f$@-yZ0gsUGuu#{VPTsKCc(e(Oz?JR$1aBk6mhECmMlayJaWRxw2P& zcbS#_@{9dHAirD9%0YAR0_Nx!tP35AgI}_I^AT+0hHjdzw5b=rWb-KI@k_pDC+RV> zc5?x9&a)ks4h_rUP>!2}HyD677)BWO4FhsgeeN4(AoNt&tipReEDGYkWgav$o4#e^ z=sB$wGD|da*46yY(OoVs9p6|3A*sI^6``8`UyzhIQ z-=03eLbN_en+P}eu-IW2akl2j>uJ1Hp5v*)Tbg<;%U!lk3tQ^&wy~uL&wgQn!`MS~ zDm2>e9`+W+wt^m(pq~1HZDA5atKIc?_MDCyEvmemu@Ng|MPt5w?I0c%Kk)7$!XhWK zM3341=pfQdgLoQxzMl=^qtM6D=rZj*D*DPCT9U;9V#d^O<;!k{Q8E5s05O_#@r~pu9KbN6X;H4RKW0x>tGDr(4LhLR21) zU#7t3YcNGghvdP0t}zokPID|693YoOcwjKkjnA_LRV?Vap^D{6B)lTa502yFU>=ni zo-w~Hu{aqzVlmG#GmGW6+!M)@vHMR(@*%dc47h?u zNMqI=$!B32Nh>dkLflsPI-18UFSd{wq2RPHH;+9owuGBt?BC@kcvmo`RU$`**A)xo zcZo&8AFgAo9-EiR!46GdtcE0|BgwcWKu+$)K~}qlF-c-_-O=Yy%OU2Ou9v@I03_Xle#sYk0*4i zMLWz!9}7jo&6v^Xjpm!>>K!9Wi>2>D!Yyw1Do8$v$-r@m{C9+Iw*NF52rt1j)RRMa5}~^-S~^kvYAD~QkKQZMEQq$upzN0t4p=ZQ+n>hs=s^qE zzok*|V;VO_ACzr~b11|Xi${W;P4bAK*V7i(**1yp5lXwddL#!zjy*VvKV#|8h?N?l z91qe)pR@#NPleH*1TmT~G@g@Fp5qvWboC-E=kd8QM%QJ z48Dlc9t*rQfelf=%Hl@}8qsI7`2%PVOLF*)lvvd#a(JDY3M(W|=38|}tHrX)4IPC% zj#{ni8p2xtBXna6J+m?u6vA9Z1wI%Wa?NI$Gp>sgJ!6>)`%-9mAPiU{&RvIi%ia2e0a z^;$`WmO)tL_G|eiuQilXK!Cg?MJ`;aL1OI>#cI8}YZ2;yuBA^)gs*GfO4#MTfDAv=S@ zQSqZz;AGL=R(P`%H(%jOew%r32oGN!!RssejhJXmcJYd&gH}USr4L`(paY{_sNylp z4NJ3eP|6|oaTm|ln~!L;3O-Y6gLhZsbhgV`%1LU~1(o?2di%Y*_88(~dQ<7pP*PAY zaa79jFpT38BSSeEWSXIzQlIzm42mI+WIF7eHAvDKMsm(-2!GyW8O>+MbV@eotV-9w zwp&N@o6xz?SoMThT?k{-#isp`F+!aFQnvP<-;ES!jdZ2EtPJk-{&m%Rmrh9{j1&1 zAc515j}e_7By)!7vT{R(#XjGh4Zd}#aC1Tsr>73N_?(r#by&U==8e;9mtHP`2#DHByVKZ}c&mh`>Hs`B}rt7Jp&3^%@W!Y4*)!9j4o zJ_M0zZhTTDdm^#j>#Olqg}VZ}?`750XoJo*e3{*9iz-@=K0S%Bp?2rnU|}VnORY9| zypnHcbbtqE^(es$+JPu26UWvZQwZ+dv#(1 zzbSHHUvqI^C#gku^8e(Rh)mkdms4^`ZTKZ$P0%EKayP#Q6Ou_=_+yy6cySBgC$ow7 z@G=Yu-ns`*CDN(pY~>Ehx(w5x=1v~1y0&qA+tdwv1N>f!$-4Vyi%e_OEMH|s9U+`5 zRwL9ufcx8ORDbgTe}>UGBP@G}Cm529_(rSJxj3-ljKiLlfx#%gs`W3b^!YLSt^W2Q z{%48@N6o{0As!g7Jj@>?Me6cL&~jl&`b;Y?#~{=3C?CSn%R%7=-4x$T-S;dnBnRQW zXZfF5k+B(mbC7SvvnJ;`UW>8eZ=d7i#b)Dniie@XJ$0I6JO`r zrPsW6{w5*&VaQQzKM1~~=tCWXdyn#bazuUgC^w6t?MAahOW)R!(AOTN)p09O`!V?D zZI1V+#^Vs*!RNBG#&fWygI{2s#`#iol=|~`_%9gFIenl13Us`|M3y8mUCQr1`pFr*mj1m z9hzgZN6oMGt#2T~k0DXkJZ`y|0&f*kKIX6B)OCK$J2{@N@1EnSY?-N4{l_^Tp!ia1 z+vj`)@u+|LoX^Fn1@Q%*$xZ4zU-0D|1M95wd^%2L&3V2IbLvOW^Reh&{&b#yhnI)n ze!~kWzLm}Wj^9T1s!x5#TNtWn(SPyB329S5{~LeIj3>_)E>@v#e#6DD3bkQG+6<%wXF2y-td)r=I(V@mWgkN4jZ%YuVn8`ShAoA_4 zrbgtikYwCOD7p!LN)S#A_l72lS-PE4bT#ZuMA3I83I{6IBZ;B__v-0Hu|o79!9gfU z5>rse?o1MK{D?VQQ&7BATECO@(X>%wn>ADKbS^4i?UwI}FR1@9N|+27hQnK9 z#RzJ(z<-SuvuFec>Epx#7GWucmT_XXHQJKP6~lVx8h67rPB=V>J3!=$G!|z`f-$*b zGRwD224Ak2!J707;7_??K3it#0%IOFm13bdPfTJiEZi*%Zi@$A%M(+X*RlkRqx2Ug96dr>1f=FL^^(4MYwi5VMCE{4&NoaLC$efV&MJCWpY+G zjB)!{k1ba)|NU~2n9lZE_N)4t;x>8NwDCHz8g2WR*9kR#$^S&x4lm3Suc2OSDi$8r zVL1-p6pIH$hvls0uoYpVMF3K35rbCt;9`8wQ!g)7BWv;cRl6xU%$q8@dLHwbQGl$~uT(UC^% zQa-#{j*~xG{ad-n!xJOexI{-bV`H(pYL&Q7M3z`_F&s->=rl;*nRbf>>ftrwMQI;4 zc!krt#bD@PBzV#*p1}7ii>t&KREL}z5eX~nMIn~6YQ+v#Y7GJJ^WplrdTT2;2_1ax zlN#I$npQ1}aA(e4Co;KPhsJfoIx&mXKUgEOSVItLeQzNWUaAq5tP#PQ6j{(jqm+q| zP$wdTm~~<$YwB(5m${`Egfg=r(=Y7(SQ@CwFK$PJ{*xbdv>6iXMfTOk*3!#H8{78Y zTECpuUJx=Zq(5qd%f=0%jclj-`Z_U~h@Ck1yVNu5(H7!q@wW!C4quv7--gN}_FDH_ zLndtK?Wpy8)nDH($^|=M4IZ3OR*!GR6E@<^4g~#tBd)++cxj_}Ao!WB?zjuf;vgySv3v}Z6y>#IG%ryCN}uC>Z$4TYo7=4nAcq?Eil!B8#xCSj0)$dx}LNKVm&=h3;Yzz#ey5!}c_`bX%qO zmc@_g@RX7J`r3=u8Nq*v!c#=2Tw!aZgRT%_D;oH3Q3`3-DR9XzqBn&4Dr_^2Hl8@G zaJ9R9%_8)uL&0XW%|20sEnXjj#M$iG8ss{6mAlSUmt@NhVwB+R1jaS~hGbjzNDTv@ oCzrd^Z9iscwcsn3OxuquF=beLt6Td&5Xih+SVf-g$2|Ri1Cq2PJ^%m! delta 11842 zcmbt)3tUxYw)p;D=j`*?dJqmC5D*kZl&6Y{iHb@}ii(PFvm+eiDDQ_!6Be1xSfSF% zmRgq13^`O*=Ge}P(pxssNHa7#Wy)2jX#V_*lG3?DY2LN>J_x4&`=5I+zw_gJt#7UG zTi<$p>)YGT2EVgC*j(hPboc904w~B;+2!kG^U0qNP2m}wH2EHslS!-ZkeozL`98<` zX#*z%*cv}j|^sTjxAz8j>Z6ipw??c-#lH=>LMUz}#usw#jeG~1& zh}V~APas9Udi!Wn=8`A*kfcUfaDf(E4wxi~9yCb@;lm3w2GLx+Ko>_hm`IQgEs^-5J|wSqONUKx z>@-W>k;DhkBPMv@3la+Jzr)=$!TaCQKagXv^?Ukg$}tmn&G%GP6;{f8Avtd1nWV); zWO?p7E*(eGl4Q>;FXvJV)`^5&zAlFgR$rn+Ni#fr30Kq%FKR^#e0+%}I&h9mqDxCE zkd4J_N{)l$GL0gw>Zr@~aWgrk9=}2-5OVs-pJ)kbgVLYqaV*AOLpEN3yROlY>Fp*G zow>nViBwC1TpKXj5|x5(cUQU#xpdh-LvKnOUja0V@k|~R$S54}2$|5ONpoX(-Lg0^_eMN+-3RX^t zMIB*gj}fYv;m&9p1#hG=8+;+NA4!0E-oozY#Hr5g$0`_c!dn3>f`q`C02WI_%)WW0 zArL-**-1Ez7{Er8D7bR~OTl9M05-)EWk&IcF-tLUdH@?v;(!LSB$5fE0$DQ2g}gvE zmMn$cf$TQE(o71VUl0q1Zv)vNQUsHOSO`Q1u~1T`)yMHFGpRHnwg<5=QVj=!SRxAO z*&vpHl4o@y-A0(`#8n)CQYRZj4nl(yK@P)7CrhGTW)Q(_JiTm&$-xYD814&3`T`CG zvr)tXUk0Nfu|DBeYYKzup)8PO z!IDrG6P#lv6K8tdsJ$7LmF3>mRh39A%OLP-C`%5_Hk0^8o;(E7h)j~CZ0+1K%uOQez63NPZe#3&Fcu!} zF_YwJCB?;_yh?9LF*1)t=jnVzgO>s{9L2{ABg0wp&sgl~W%2MhubI2%mTCwz%|Vp1 zV@^pi?pAUvC@J!A$%7k1Ls6s=PP%D5We^Z?i|#7OiD08|g06;?At)DzBbbxaK;$qs zm~4hA!&p42gQ8(L(magyBlQq56eVT{WDM2ex<=s0-oY%XUo9T%ypnQVP-=U3VS}rK z*+4|q0~rW2BiWFEEoKrut-y^OD%3=4i+{%UNEU+xdx1M5S*p?(cYUA1JEPd}z?)bt z?dSt?B8r9g+hrzUi#+8O$Vo}srEN3>9JpIlH>{7j)qcmLtJxlnI(Xxb_w_;j$WRoZ zEwC;UUE9PV`0t0ItpEQ9*GDm^c8vzBuSPT1zXE>10JjWd!T$>QK?6K67WMNM2ia$1 z`eF_n;E}`8OdWYL1(mf4<|d&HIu12S*lK}iQ}M)4!M+qWjGTsVldxz5$5<>bKzcG- z@OCrYAIB1Drx{+3L%BJkF=-T#5oi{hjC%eEHX`VlnT%QJE%KC9RrVNwV;c1kcyk1c z?Vr(W7&PyvOupfe~cm853K8;J+jVqpDnBpckn6>Zc4Pg#|xI1g2$RYMpG z1LAQzrwpjO;@MDZuLwcX2$l-}7SG}wKNG?>13n?)M)+?u_-zR{!?zpoKOnrl!`u@j zNFBzWrY52t?leI5C$hv_2x^zXdpQZ6(Ep0};qc337I6IlE*p41OGah-AK?v!70qx)-n!zFdkQ`IcYBI7_aa@@074*gG)qN?R67=p!}`&< zi2t=n2@P2k3{OR+{huIvc^vv!i-u&vt&}1X;>O__C@^yzOEXkH6bj>zr6}9l+&D$< zYm4{YY>W39wm1MTjYAqvNE(mY9Rf4QBVH%mJ)TXlgvjWJ!euEOo*&OC({TmTnW*fd>WgJ-e<}L6lA?veM2i8&Q4&7EnouhRq_ z&p;@f$cFM1*?yPrsMQ6pOk^`is`}4~>{Wtp`-MsDUYaJu>_s#ZzFCg`eEwv1CrMWi zPG&U({dH0XMg$q^(hNo|G*gC+ckl@H7k98pgk-62%wnr3$%fE5>@zt>wg-7DDyn=J z!UNU*b6F%q=bAj9y-Aj;U(aV&60}s?=t^0_pTy-%liMV@RqH}lM2QDdR`Y@CwnZ$T zP>&3)ckwU?Si%|)VccpovfNYQDPQl&zr~<* z5T1C9jX-^Q=P?#a4_{v;$aNSwAAyN=7#lZ1bshT+UcP>0ka`!f0sRCjM>Z&1<-x%F%vdX!`JY=ZN&%ok{~aX}_7Ez(?wLFQ?2 zJkIj_waFxGzQ82yZ6F zN`<9&rNW|Zl}HxY1n9&S4Sd3&hYY}gK7aul;6suVt^rFN5Mq&JsR%u@6k^d1T?&E8 zJK1`?D!sOoO~yOYKX$SlY-!lEn=tlh)!1;0fjOoR<`@lgxJ8P?lFJTBO0f9;96ksF zcC(L23Y_1~($PpoJjKeaX*$S@W2AK0^%RoJ0LRlvCmU8jjpv@xyH{tXpHNmGLYeTF zr`cRfmPRkrB4zi2!-_q4r^tcQJs9HV!k#^7{&M>aCp?40OCjSKykM?`ZO>o=$PIsc zhQ*9?TX^Kuh2n#%gG|b0| zv_r4$vW&r)Hn9-{u{{X?$w0Ndk+j7tq=?!W%E(^{`Rf;cRk1o%AA` z#qdfw_#g{YpL-eI>VU%*5}%XO1%xNr#Lh}Pai(Gx7EEWW)-E?C~g?CJx*XOm1Al)m!@ zdkKTm;y2N0wW&MbM4yYnDQ?wJG+i7qTI*@+XHPpUYDN>A#vMq<)|)PH!m3~31nhd3{nKK> z7A00mQFp(`-Y50|Y;(KhIx0D>pv)ly)lKiCZMTJJ{c^a~g^@(mUs#GW%1=9{5A7(( z`+(I4#%MUBtWumlCjsXq7;{qmb5i@vNrCKUw$YNR%}KFJY3j*l2Gp9a&qWE(fT|Ph zcX(5eXu%6?rj7`7MafbhYhf>PRLiuF*=kg)r$1&7VWBNACD%`CX&+L#I!?zaDlOHh zVRNP4<8oW^BCSm`5PS4`y4R1QtPcw8>%-lmo4H$r81?J%*psZ*Ql`=ITBR!W=t!{O~Dz%UY{bPj*O~4dPv=Ss>eDmEohaEC%8~!&tr!R(;0YSRDI|WwQF7 zvBWbhPT66_RGe#lNhRJgcR~IcHYy0aw9|{vwMe@((%9ak;~u`xznO+Uo7tyBrx1rj zYS5su-3TYnvf(iDEZd6;i}g#I!X7)%wxGM4b%BkbN36b!D??%3kEjZJF0coQy-7nO zOA3*WS+zXmV7TLR3~-LauFo+dX@hg0vr+W8e`wSfYzn3nE55+!XEYz{u{Q9cUwszy!uNx+w+*(Ek$ZUW$ew5Q^K0SzU37 z0mHk@rT<``6HA)5wsaeY2j{!l?HCZm{($fqulVg7D)X*aT~~-hqxO z2ZDdZJ5#Qj^CNqep`+*5*dv;wzlKOw!e6hUIJpfT>E6S0cq*SlgS{HHBAbLiRPH!l zW~;HGYu`z^2k#$0Q9cBVD8_@)yo_gjD7IEG9&4%A=3O;OHSieYaikVrV>}9rPZ`dr zg&!FY!NSS;+Wyrx5~&51vrF#AuyQkOGk||e+BF1WYTW?7g^>=UF*=yPVS=dsJV+(s z+|rMB*|cnUC=46Pg9hE0D8H<;BgKq4=Wah#$w(fHQVb*c2zu4u*M>8lH>WR&-3903 zc?^t<=YxZVodjtC87f!b6!Km1JQNMgFSH^6o{ZPi63}pL~_)L6((Gjy`U6-Co;laxj>}0zCdU-v)j4MvC z_qD0GzMtFPEk^n#McWys)l;=H%`V{&#lO~!!|B>)2gfb&6z5mWb5|BfcpdsLHl3k? z$NyJs$<(@jpy5H^)v3^@n~%OP2ky>ZdoybhZA0B?@gXr z)MswvFPWY78n7LK(`9LgMrfB^+6C@uJQW`kU>YCn+@tm4=srJMtTq^{jqnP?**5lB zZKDS6719B_o{Uq|rt|d#?dmI;{P*_5Iu5B!NJk75VNG@e#j!ppn(T5sW@8HBr(g0} zmSY;iCOan39W%I_HX9S2E&hqEeI~ZR>oa(PrB$2JVwX;-aWnY>N=~aackus9(2f?& z=1<^7>gsI1gtpt&#o4^VMmy|qVhOJ^b=vLrH6Ey4#Y1S9UA=cHiVeMN*K&AHn7e|T z)R&j>G7{QtCo{7!LFk#U$!5j%>t%N@=u~>u4!#w993ko-SMb@?hKV**yi9xvx4@89 zc*9npdKId9fcn%bK89dQHD?VER=>Q9-$9HlqLyvFV>N<=tA(riVv6|(1c^}pmXH2} z#V7IiwQ}C`a+b7 zboE>zKWiSEp|7k=;Gtytt6f6M@>j7dThV0G3Ex-p#4$MviPw__3p|y2o+wB0XAiJL zd)7lVT*}4S`ag=zrD|>!FC}-Z)KNMRx!aE%dpt&`SCR0id1is{fBxYzMZzD7r#45b zQtV;)YO)RuEVPc}f$ETZcmM`ke&8!ojb6Kg6l?u`*t6LnjymvOHFAsADSFBgx_-g$ zv(@|IBxwh1xQ{Qv#9`}wJU@JoA_o2-Nxt8V+yR@#vdApoe~dgR$7!+<&@HarSs7{Z)&7ZW! zS@8aef3g$m-{#5cig);6f)V?DM|mDeQO_Uc5ggUy+Izf`q^Xt1`6`Zjak7~gQj()) zoZznr%=&-V%Ku78oZ9>sK2R$!oaAFEmab3u4nkI{FMY}zDSi{N-NRBU@hk z3d3zurw;rY!$C}kf7!|BMeMOy!)9QdoR8lr^;BF&AVs8ou<#q6MjF(u-*B72Sa$dK zXzvfg>)-QOT*(pm+xL79J8o%)(U*8PYq89O)&^wv^virRLw0}oPrep|&D3sw8(PP* zZa$8-Th!;f`8_X3S_mY1Eh^ffiv;kr%CP91y#3=OG z?+*~)lg;WIfg*$A+x8WwxECK9?gn%NEJ=iW7bbKX&npGj$SIg0ij-DUbmTle1jx!itp06+sMH>(7Ecl}c;l;?B+?wUR<{km zMj}zDMo7y8?@tnu7%=~Rl9-7vHOZ63XcVdZ$sz+a^ts96PH`H+_JC!Im=v~8n~JZX zd6>UMw^mZ_zS~nlh)ijN4PN;zA7YirQck*YMx(lIif|BAzr7iFj0e=WGsMe82(yF? zET1N{yXVzu;&E~qwoey-7Zw~i0{3N#Ld>akWQrj|!JZ~?+%867uJyLtMJZ-=Uet;f zHGGCx&GC-(z$~!=5p<($p?H2fTWnJT%#o1`@(MiKH$ZLbquIhL(@q;et{A4>VBX0U zGudTZJlwfR41xGXA`x2|uyT=@Me*wL{33A&yJ{owAB#jf3%5tXxW!^R^O#d%<6<$7 zrQ2JfbukWQU?pIQn8-4*GEb{y*|TBW5;2+O*wdhOi8#Sh%pTagR7_yG_NCCa6k%4{ z-4M16mKX6tSdheccg9>8XpQ6M6R zZn0~J-_A*j%zGup8d+MMs zbwbNpu_rX`|ApZIJhV>y0grihq42W9_9O6mp?Cr-$JMz-s44ug9fLG9-HE(NVCLeH zVu3GB>OYFbNFp+E)2CrrDXzRtomVPO5!9ezG(f>o0h|}V-@2bSh)Rc{&9d>p9 z2C;$DPCG=^h}TgXKC2P?F+PJ$8^sU|&(!@JMHuB*?VN-AVUggvDoBpZr{IHzyP~SR z`ntM+y;fjs1&eFNY9u3552SN#Ujl|>=e(k45b?S?Gm{x6DxZj z$4VAf-rgk^u`-bjb9^EhE#Lh<)a|A4fe$&pQo&c>!Yv{M0-q3fGHgQS6XJg6#)^(o zt02l*@c9lAsE>E=5O*;TcIyO+u!00K;PR8gp?B-8ED-k%u9f-h8J@~H_%gcQgBh}N z{6?iZE5A(O3#x<*`2uh~H}0U?AeYN(dI;1S1Qw$m!1X8aA`=R)zJ<-|_T6Ft5nGUz zTh#qe2^YFSIQq1>2fg9=J!n&Sy|P2mohJOBXGArc^3~6ZJi&G;hDU={^}+<7{}u)O z#;$1%Vj8W-r@^)8Y?7Z7uwL1=3HubP_MUuuC%+%khvhs;!#48fnWgf>KYO zKR#_%9OL!Ag&X`mEs7&q@0sB#_EdN)T9sr2A{#TA?m};6^(iHJxDJ8e;N^MRlq>Oi U%Xq}bK=9%L5h^;AD Date: Thu, 30 May 2024 16:54:42 +0800 Subject: [PATCH 25/27] add erc20 testdata --- node/tests/data/Erc20DemoContract2.json | 12753 ++++++++++++++++++++++ node/tests/data/Erc20DemoContract2.sol | 16 + 2 files changed, 12769 insertions(+) create mode 100644 node/tests/data/Erc20DemoContract2.json create mode 100644 node/tests/data/Erc20DemoContract2.sol diff --git a/node/tests/data/Erc20DemoContract2.json b/node/tests/data/Erc20DemoContract2.json new file mode 100644 index 00000000..a2e07e18 --- /dev/null +++ b/node/tests/data/Erc20DemoContract2.json @@ -0,0 +1,12753 @@ +{ + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "evm": { + "bytecode": { + "functionDebugData": { + "@_1018": { + "entryPoint": null, + "id": 1018, + "parameterSlots": 0, + "returnSlots": 0 + }, + "@_44": { + "entryPoint": null, + "id": 44, + "parameterSlots": 2, + "returnSlots": 0 + }, + "@_afterTokenTransfer_585": { + "entryPoint": 551, + "id": 585, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_beforeTokenTransfer_574": { + "entryPoint": 546, + "id": 574, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_mint_403": { + "entryPoint": 189, + "id": 403, + "parameterSlots": 2, + "returnSlots": 0 + }, + "abi_encode_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e_to_t_string_memory_ptr_fromStack": { + "entryPoint": 1452, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_uint256_to_t_uint256_fromStack": { + "entryPoint": 1625, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "abi_encode_tuple_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 1490, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed": { + "entryPoint": 1642, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "array_dataslot_t_string_storage": { + "entryPoint": 708, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "array_length_t_string_memory_ptr": { + "entryPoint": 556, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "array_storeLengthForEncoding_t_string_memory_ptr_fromStack": { + "entryPoint": 1396, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "checked_add_t_uint256": { + "entryPoint": 1567, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "clean_up_bytearray_end_slots_t_string_storage": { + "entryPoint": 1017, + "id": null, + "parameterSlots": 3, + "returnSlots": 0 + }, + "cleanup_t_uint256": { + "entryPoint": 838, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "clear_storage_range_t_bytes1": { + "entryPoint": 979, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "convert_t_uint256_to_t_uint256": { + "entryPoint": 856, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "copy_byte_array_to_storage_from_t_string_memory_ptr_to_t_string_storage": { + "entryPoint": 1168, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "divide_by_32_ceil": { + "entryPoint": 726, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "extract_byte_array_length": { + "entryPoint": 656, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "extract_used_part_and_set_length_of_short_byte_array": { + "entryPoint": 1139, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "identity": { + "entryPoint": 847, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "mask_bytes_dynamic": { + "entryPoint": 1109, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "panic_error_0x11": { + "entryPoint": 1522, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "panic_error_0x22": { + "entryPoint": 611, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "panic_error_0x41": { + "entryPoint": 566, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "prepare_store_t_uint256": { + "entryPoint": 895, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "shift_left_dynamic": { + "entryPoint": 741, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "shift_right_unsigned_dynamic": { + "entryPoint": 1097, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "storage_set_to_zero_t_uint256": { + "entryPoint": 951, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "store_literal_in_memory_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e": { + "entryPoint": 1412, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "update_byte_slice_dynamic32": { + "entryPoint": 753, + "id": null, + "parameterSlots": 3, + "returnSlots": 1 + }, + "update_storage_value_t_uint256_to_t_uint256": { + "entryPoint": 904, + "id": null, + "parameterSlots": 3, + "returnSlots": 0 + }, + "zero_value_for_split_t_uint256": { + "entryPoint": 947, + "id": null, + "parameterSlots": 0, + "returnSlots": 1 + } + }, + "generatedSources": [ + { + "ast": { + "nativeSrc": "0:7125:17", + "nodeType": "YulBlock", + "src": "0:7125:17", + "statements": [ + { + "body": { + "nativeSrc": "66:40:17", + "nodeType": "YulBlock", + "src": "66:40:17", + "statements": [ + { + "nativeSrc": "77:22:17", + "nodeType": "YulAssignment", + "src": "77:22:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "93:5:17", + "nodeType": "YulIdentifier", + "src": "93:5:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "87:5:17", + "nodeType": "YulIdentifier", + "src": "87:5:17" + }, + "nativeSrc": "87:12:17", + "nodeType": "YulFunctionCall", + "src": "87:12:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "77:6:17", + "nodeType": "YulIdentifier", + "src": "77:6:17" + } + ] + } + ] + }, + "name": "array_length_t_string_memory_ptr", + "nativeSrc": "7:99:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "49:5:17", + "nodeType": "YulTypedName", + "src": "49:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "length", + "nativeSrc": "59:6:17", + "nodeType": "YulTypedName", + "src": "59:6:17", + "type": "" + } + ], + "src": "7:99:17" + }, + { + "body": { + "nativeSrc": "140:152:17", + "nodeType": "YulBlock", + "src": "140:152:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "157:1:17", + "nodeType": "YulLiteral", + "src": "157:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "160:77:17", + "nodeType": "YulLiteral", + "src": "160:77:17", + "type": "", + "value": "35408467139433450592217433187231851964531694900788300625387963629091585785856" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "150:6:17", + "nodeType": "YulIdentifier", + "src": "150:6:17" + }, + "nativeSrc": "150:88:17", + "nodeType": "YulFunctionCall", + "src": "150:88:17" + }, + "nativeSrc": "150:88:17", + "nodeType": "YulExpressionStatement", + "src": "150:88:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "254:1:17", + "nodeType": "YulLiteral", + "src": "254:1:17", + "type": "", + "value": "4" + }, + { + "kind": "number", + "nativeSrc": "257:4:17", + "nodeType": "YulLiteral", + "src": "257:4:17", + "type": "", + "value": "0x41" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "247:6:17", + "nodeType": "YulIdentifier", + "src": "247:6:17" + }, + "nativeSrc": "247:15:17", + "nodeType": "YulFunctionCall", + "src": "247:15:17" + }, + "nativeSrc": "247:15:17", + "nodeType": "YulExpressionStatement", + "src": "247:15:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "278:1:17", + "nodeType": "YulLiteral", + "src": "278:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "281:4:17", + "nodeType": "YulLiteral", + "src": "281:4:17", + "type": "", + "value": "0x24" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "271:6:17", + "nodeType": "YulIdentifier", + "src": "271:6:17" + }, + "nativeSrc": "271:15:17", + "nodeType": "YulFunctionCall", + "src": "271:15:17" + }, + "nativeSrc": "271:15:17", + "nodeType": "YulExpressionStatement", + "src": "271:15:17" + } + ] + }, + "name": "panic_error_0x41", + "nativeSrc": "112:180:17", + "nodeType": "YulFunctionDefinition", + "src": "112:180:17" + }, + { + "body": { + "nativeSrc": "326:152:17", + "nodeType": "YulBlock", + "src": "326:152:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "343:1:17", + "nodeType": "YulLiteral", + "src": "343:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "346:77:17", + "nodeType": "YulLiteral", + "src": "346:77:17", + "type": "", + "value": "35408467139433450592217433187231851964531694900788300625387963629091585785856" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "336:6:17", + "nodeType": "YulIdentifier", + "src": "336:6:17" + }, + "nativeSrc": "336:88:17", + "nodeType": "YulFunctionCall", + "src": "336:88:17" + }, + "nativeSrc": "336:88:17", + "nodeType": "YulExpressionStatement", + "src": "336:88:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "440:1:17", + "nodeType": "YulLiteral", + "src": "440:1:17", + "type": "", + "value": "4" + }, + { + "kind": "number", + "nativeSrc": "443:4:17", + "nodeType": "YulLiteral", + "src": "443:4:17", + "type": "", + "value": "0x22" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "433:6:17", + "nodeType": "YulIdentifier", + "src": "433:6:17" + }, + "nativeSrc": "433:15:17", + "nodeType": "YulFunctionCall", + "src": "433:15:17" + }, + "nativeSrc": "433:15:17", + "nodeType": "YulExpressionStatement", + "src": "433:15:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "464:1:17", + "nodeType": "YulLiteral", + "src": "464:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "467:4:17", + "nodeType": "YulLiteral", + "src": "467:4:17", + "type": "", + "value": "0x24" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "457:6:17", + "nodeType": "YulIdentifier", + "src": "457:6:17" + }, + "nativeSrc": "457:15:17", + "nodeType": "YulFunctionCall", + "src": "457:15:17" + }, + "nativeSrc": "457:15:17", + "nodeType": "YulExpressionStatement", + "src": "457:15:17" + } + ] + }, + "name": "panic_error_0x22", + "nativeSrc": "298:180:17", + "nodeType": "YulFunctionDefinition", + "src": "298:180:17" + }, + { + "body": { + "nativeSrc": "535:269:17", + "nodeType": "YulBlock", + "src": "535:269:17", + "statements": [ + { + "nativeSrc": "545:22:17", + "nodeType": "YulAssignment", + "src": "545:22:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "559:4:17", + "nodeType": "YulIdentifier", + "src": "559:4:17" + }, + { + "kind": "number", + "nativeSrc": "565:1:17", + "nodeType": "YulLiteral", + "src": "565:1:17", + "type": "", + "value": "2" + } + ], + "functionName": { + "name": "div", + "nativeSrc": "555:3:17", + "nodeType": "YulIdentifier", + "src": "555:3:17" + }, + "nativeSrc": "555:12:17", + "nodeType": "YulFunctionCall", + "src": "555:12:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "545:6:17", + "nodeType": "YulIdentifier", + "src": "545:6:17" + } + ] + }, + { + "nativeSrc": "576:38:17", + "nodeType": "YulVariableDeclaration", + "src": "576:38:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "606:4:17", + "nodeType": "YulIdentifier", + "src": "606:4:17" + }, + { + "kind": "number", + "nativeSrc": "612:1:17", + "nodeType": "YulLiteral", + "src": "612:1:17", + "type": "", + "value": "1" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "602:3:17", + "nodeType": "YulIdentifier", + "src": "602:3:17" + }, + "nativeSrc": "602:12:17", + "nodeType": "YulFunctionCall", + "src": "602:12:17" + }, + "variables": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "580:18:17", + "nodeType": "YulTypedName", + "src": "580:18:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "653:51:17", + "nodeType": "YulBlock", + "src": "653:51:17", + "statements": [ + { + "nativeSrc": "667:27:17", + "nodeType": "YulAssignment", + "src": "667:27:17", + "value": { + "arguments": [ + { + "name": "length", + "nativeSrc": "681:6:17", + "nodeType": "YulIdentifier", + "src": "681:6:17" + }, + { + "kind": "number", + "nativeSrc": "689:4:17", + "nodeType": "YulLiteral", + "src": "689:4:17", + "type": "", + "value": "0x7f" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "677:3:17", + "nodeType": "YulIdentifier", + "src": "677:3:17" + }, + "nativeSrc": "677:17:17", + "nodeType": "YulFunctionCall", + "src": "677:17:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "667:6:17", + "nodeType": "YulIdentifier", + "src": "667:6:17" + } + ] + } + ] + }, + "condition": { + "arguments": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "633:18:17", + "nodeType": "YulIdentifier", + "src": "633:18:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "626:6:17", + "nodeType": "YulIdentifier", + "src": "626:6:17" + }, + "nativeSrc": "626:26:17", + "nodeType": "YulFunctionCall", + "src": "626:26:17" + }, + "nativeSrc": "623:81:17", + "nodeType": "YulIf", + "src": "623:81:17" + }, + { + "body": { + "nativeSrc": "756:42:17", + "nodeType": "YulBlock", + "src": "756:42:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "panic_error_0x22", + "nativeSrc": "770:16:17", + "nodeType": "YulIdentifier", + "src": "770:16:17" + }, + "nativeSrc": "770:18:17", + "nodeType": "YulFunctionCall", + "src": "770:18:17" + }, + "nativeSrc": "770:18:17", + "nodeType": "YulExpressionStatement", + "src": "770:18:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "720:18:17", + "nodeType": "YulIdentifier", + "src": "720:18:17" + }, + { + "arguments": [ + { + "name": "length", + "nativeSrc": "743:6:17", + "nodeType": "YulIdentifier", + "src": "743:6:17" + }, + { + "kind": "number", + "nativeSrc": "751:2:17", + "nodeType": "YulLiteral", + "src": "751:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "740:2:17", + "nodeType": "YulIdentifier", + "src": "740:2:17" + }, + "nativeSrc": "740:14:17", + "nodeType": "YulFunctionCall", + "src": "740:14:17" + } + ], + "functionName": { + "name": "eq", + "nativeSrc": "717:2:17", + "nodeType": "YulIdentifier", + "src": "717:2:17" + }, + "nativeSrc": "717:38:17", + "nodeType": "YulFunctionCall", + "src": "717:38:17" + }, + "nativeSrc": "714:84:17", + "nodeType": "YulIf", + "src": "714:84:17" + } + ] + }, + "name": "extract_byte_array_length", + "nativeSrc": "484:320:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "data", + "nativeSrc": "519:4:17", + "nodeType": "YulTypedName", + "src": "519:4:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "length", + "nativeSrc": "528:6:17", + "nodeType": "YulTypedName", + "src": "528:6:17", + "type": "" + } + ], + "src": "484:320:17" + }, + { + "body": { + "nativeSrc": "864:87:17", + "nodeType": "YulBlock", + "src": "864:87:17", + "statements": [ + { + "nativeSrc": "874:11:17", + "nodeType": "YulAssignment", + "src": "874:11:17", + "value": { + "name": "ptr", + "nativeSrc": "882:3:17", + "nodeType": "YulIdentifier", + "src": "882:3:17" + }, + "variableNames": [ + { + "name": "data", + "nativeSrc": "874:4:17", + "nodeType": "YulIdentifier", + "src": "874:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "902:1:17", + "nodeType": "YulLiteral", + "src": "902:1:17", + "type": "", + "value": "0" + }, + { + "name": "ptr", + "nativeSrc": "905:3:17", + "nodeType": "YulIdentifier", + "src": "905:3:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "895:6:17", + "nodeType": "YulIdentifier", + "src": "895:6:17" + }, + "nativeSrc": "895:14:17", + "nodeType": "YulFunctionCall", + "src": "895:14:17" + }, + "nativeSrc": "895:14:17", + "nodeType": "YulExpressionStatement", + "src": "895:14:17" + }, + { + "nativeSrc": "918:26:17", + "nodeType": "YulAssignment", + "src": "918:26:17", + "value": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "936:1:17", + "nodeType": "YulLiteral", + "src": "936:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "939:4:17", + "nodeType": "YulLiteral", + "src": "939:4:17", + "type": "", + "value": "0x20" + } + ], + "functionName": { + "name": "keccak256", + "nativeSrc": "926:9:17", + "nodeType": "YulIdentifier", + "src": "926:9:17" + }, + "nativeSrc": "926:18:17", + "nodeType": "YulFunctionCall", + "src": "926:18:17" + }, + "variableNames": [ + { + "name": "data", + "nativeSrc": "918:4:17", + "nodeType": "YulIdentifier", + "src": "918:4:17" + } + ] + } + ] + }, + "name": "array_dataslot_t_string_storage", + "nativeSrc": "810:141:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "ptr", + "nativeSrc": "851:3:17", + "nodeType": "YulTypedName", + "src": "851:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "data", + "nativeSrc": "859:4:17", + "nodeType": "YulTypedName", + "src": "859:4:17", + "type": "" + } + ], + "src": "810:141:17" + }, + { + "body": { + "nativeSrc": "1001:49:17", + "nodeType": "YulBlock", + "src": "1001:49:17", + "statements": [ + { + "nativeSrc": "1011:33:17", + "nodeType": "YulAssignment", + "src": "1011:33:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "1029:5:17", + "nodeType": "YulIdentifier", + "src": "1029:5:17" + }, + { + "kind": "number", + "nativeSrc": "1036:2:17", + "nodeType": "YulLiteral", + "src": "1036:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "1025:3:17", + "nodeType": "YulIdentifier", + "src": "1025:3:17" + }, + "nativeSrc": "1025:14:17", + "nodeType": "YulFunctionCall", + "src": "1025:14:17" + }, + { + "kind": "number", + "nativeSrc": "1041:2:17", + "nodeType": "YulLiteral", + "src": "1041:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "div", + "nativeSrc": "1021:3:17", + "nodeType": "YulIdentifier", + "src": "1021:3:17" + }, + "nativeSrc": "1021:23:17", + "nodeType": "YulFunctionCall", + "src": "1021:23:17" + }, + "variableNames": [ + { + "name": "result", + "nativeSrc": "1011:6:17", + "nodeType": "YulIdentifier", + "src": "1011:6:17" + } + ] + } + ] + }, + "name": "divide_by_32_ceil", + "nativeSrc": "957:93:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "984:5:17", + "nodeType": "YulTypedName", + "src": "984:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "result", + "nativeSrc": "994:6:17", + "nodeType": "YulTypedName", + "src": "994:6:17", + "type": "" + } + ], + "src": "957:93:17" + }, + { + "body": { + "nativeSrc": "1109:54:17", + "nodeType": "YulBlock", + "src": "1109:54:17", + "statements": [ + { + "nativeSrc": "1119:37:17", + "nodeType": "YulAssignment", + "src": "1119:37:17", + "value": { + "arguments": [ + { + "name": "bits", + "nativeSrc": "1144:4:17", + "nodeType": "YulIdentifier", + "src": "1144:4:17" + }, + { + "name": "value", + "nativeSrc": "1150:5:17", + "nodeType": "YulIdentifier", + "src": "1150:5:17" + } + ], + "functionName": { + "name": "shl", + "nativeSrc": "1140:3:17", + "nodeType": "YulIdentifier", + "src": "1140:3:17" + }, + "nativeSrc": "1140:16:17", + "nodeType": "YulFunctionCall", + "src": "1140:16:17" + }, + "variableNames": [ + { + "name": "newValue", + "nativeSrc": "1119:8:17", + "nodeType": "YulIdentifier", + "src": "1119:8:17" + } + ] + } + ] + }, + "name": "shift_left_dynamic", + "nativeSrc": "1056:107:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "bits", + "nativeSrc": "1084:4:17", + "nodeType": "YulTypedName", + "src": "1084:4:17", + "type": "" + }, + { + "name": "value", + "nativeSrc": "1090:5:17", + "nodeType": "YulTypedName", + "src": "1090:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "newValue", + "nativeSrc": "1100:8:17", + "nodeType": "YulTypedName", + "src": "1100:8:17", + "type": "" + } + ], + "src": "1056:107:17" + }, + { + "body": { + "nativeSrc": "1245:317:17", + "nodeType": "YulBlock", + "src": "1245:317:17", + "statements": [ + { + "nativeSrc": "1255:35:17", + "nodeType": "YulVariableDeclaration", + "src": "1255:35:17", + "value": { + "arguments": [ + { + "name": "shiftBytes", + "nativeSrc": "1276:10:17", + "nodeType": "YulIdentifier", + "src": "1276:10:17" + }, + { + "kind": "number", + "nativeSrc": "1288:1:17", + "nodeType": "YulLiteral", + "src": "1288:1:17", + "type": "", + "value": "8" + } + ], + "functionName": { + "name": "mul", + "nativeSrc": "1272:3:17", + "nodeType": "YulIdentifier", + "src": "1272:3:17" + }, + "nativeSrc": "1272:18:17", + "nodeType": "YulFunctionCall", + "src": "1272:18:17" + }, + "variables": [ + { + "name": "shiftBits", + "nativeSrc": "1259:9:17", + "nodeType": "YulTypedName", + "src": "1259:9:17", + "type": "" + } + ] + }, + { + "nativeSrc": "1299:109:17", + "nodeType": "YulVariableDeclaration", + "src": "1299:109:17", + "value": { + "arguments": [ + { + "name": "shiftBits", + "nativeSrc": "1330:9:17", + "nodeType": "YulIdentifier", + "src": "1330:9:17" + }, + { + "kind": "number", + "nativeSrc": "1341:66:17", + "nodeType": "YulLiteral", + "src": "1341:66:17", + "type": "", + "value": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + ], + "functionName": { + "name": "shift_left_dynamic", + "nativeSrc": "1311:18:17", + "nodeType": "YulIdentifier", + "src": "1311:18:17" + }, + "nativeSrc": "1311:97:17", + "nodeType": "YulFunctionCall", + "src": "1311:97:17" + }, + "variables": [ + { + "name": "mask", + "nativeSrc": "1303:4:17", + "nodeType": "YulTypedName", + "src": "1303:4:17", + "type": "" + } + ] + }, + { + "nativeSrc": "1417:51:17", + "nodeType": "YulAssignment", + "src": "1417:51:17", + "value": { + "arguments": [ + { + "name": "shiftBits", + "nativeSrc": "1448:9:17", + "nodeType": "YulIdentifier", + "src": "1448:9:17" + }, + { + "name": "toInsert", + "nativeSrc": "1459:8:17", + "nodeType": "YulIdentifier", + "src": "1459:8:17" + } + ], + "functionName": { + "name": "shift_left_dynamic", + "nativeSrc": "1429:18:17", + "nodeType": "YulIdentifier", + "src": "1429:18:17" + }, + "nativeSrc": "1429:39:17", + "nodeType": "YulFunctionCall", + "src": "1429:39:17" + }, + "variableNames": [ + { + "name": "toInsert", + "nativeSrc": "1417:8:17", + "nodeType": "YulIdentifier", + "src": "1417:8:17" + } + ] + }, + { + "nativeSrc": "1477:30:17", + "nodeType": "YulAssignment", + "src": "1477:30:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "1490:5:17", + "nodeType": "YulIdentifier", + "src": "1490:5:17" + }, + { + "arguments": [ + { + "name": "mask", + "nativeSrc": "1501:4:17", + "nodeType": "YulIdentifier", + "src": "1501:4:17" + } + ], + "functionName": { + "name": "not", + "nativeSrc": "1497:3:17", + "nodeType": "YulIdentifier", + "src": "1497:3:17" + }, + "nativeSrc": "1497:9:17", + "nodeType": "YulFunctionCall", + "src": "1497:9:17" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "1486:3:17", + "nodeType": "YulIdentifier", + "src": "1486:3:17" + }, + "nativeSrc": "1486:21:17", + "nodeType": "YulFunctionCall", + "src": "1486:21:17" + }, + "variableNames": [ + { + "name": "value", + "nativeSrc": "1477:5:17", + "nodeType": "YulIdentifier", + "src": "1477:5:17" + } + ] + }, + { + "nativeSrc": "1516:40:17", + "nodeType": "YulAssignment", + "src": "1516:40:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "1529:5:17", + "nodeType": "YulIdentifier", + "src": "1529:5:17" + }, + { + "arguments": [ + { + "name": "toInsert", + "nativeSrc": "1540:8:17", + "nodeType": "YulIdentifier", + "src": "1540:8:17" + }, + { + "name": "mask", + "nativeSrc": "1550:4:17", + "nodeType": "YulIdentifier", + "src": "1550:4:17" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "1536:3:17", + "nodeType": "YulIdentifier", + "src": "1536:3:17" + }, + "nativeSrc": "1536:19:17", + "nodeType": "YulFunctionCall", + "src": "1536:19:17" + } + ], + "functionName": { + "name": "or", + "nativeSrc": "1526:2:17", + "nodeType": "YulIdentifier", + "src": "1526:2:17" + }, + "nativeSrc": "1526:30:17", + "nodeType": "YulFunctionCall", + "src": "1526:30:17" + }, + "variableNames": [ + { + "name": "result", + "nativeSrc": "1516:6:17", + "nodeType": "YulIdentifier", + "src": "1516:6:17" + } + ] + } + ] + }, + "name": "update_byte_slice_dynamic32", + "nativeSrc": "1169:393:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1206:5:17", + "nodeType": "YulTypedName", + "src": "1206:5:17", + "type": "" + }, + { + "name": "shiftBytes", + "nativeSrc": "1213:10:17", + "nodeType": "YulTypedName", + "src": "1213:10:17", + "type": "" + }, + { + "name": "toInsert", + "nativeSrc": "1225:8:17", + "nodeType": "YulTypedName", + "src": "1225:8:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "result", + "nativeSrc": "1238:6:17", + "nodeType": "YulTypedName", + "src": "1238:6:17", + "type": "" + } + ], + "src": "1169:393:17" + }, + { + "body": { + "nativeSrc": "1613:32:17", + "nodeType": "YulBlock", + "src": "1613:32:17", + "statements": [ + { + "nativeSrc": "1623:16:17", + "nodeType": "YulAssignment", + "src": "1623:16:17", + "value": { + "name": "value", + "nativeSrc": "1634:5:17", + "nodeType": "YulIdentifier", + "src": "1634:5:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "1623:7:17", + "nodeType": "YulIdentifier", + "src": "1623:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_uint256", + "nativeSrc": "1568:77:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1595:5:17", + "nodeType": "YulTypedName", + "src": "1595:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "1605:7:17", + "nodeType": "YulTypedName", + "src": "1605:7:17", + "type": "" + } + ], + "src": "1568:77:17" + }, + { + "body": { + "nativeSrc": "1683:28:17", + "nodeType": "YulBlock", + "src": "1683:28:17", + "statements": [ + { + "nativeSrc": "1693:12:17", + "nodeType": "YulAssignment", + "src": "1693:12:17", + "value": { + "name": "value", + "nativeSrc": "1700:5:17", + "nodeType": "YulIdentifier", + "src": "1700:5:17" + }, + "variableNames": [ + { + "name": "ret", + "nativeSrc": "1693:3:17", + "nodeType": "YulIdentifier", + "src": "1693:3:17" + } + ] + } + ] + }, + "name": "identity", + "nativeSrc": "1651:60:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1669:5:17", + "nodeType": "YulTypedName", + "src": "1669:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "ret", + "nativeSrc": "1679:3:17", + "nodeType": "YulTypedName", + "src": "1679:3:17", + "type": "" + } + ], + "src": "1651:60:17" + }, + { + "body": { + "nativeSrc": "1777:82:17", + "nodeType": "YulBlock", + "src": "1777:82:17", + "statements": [ + { + "nativeSrc": "1787:66:17", + "nodeType": "YulAssignment", + "src": "1787:66:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "1845:5:17", + "nodeType": "YulIdentifier", + "src": "1845:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "1827:17:17", + "nodeType": "YulIdentifier", + "src": "1827:17:17" + }, + "nativeSrc": "1827:24:17", + "nodeType": "YulFunctionCall", + "src": "1827:24:17" + } + ], + "functionName": { + "name": "identity", + "nativeSrc": "1818:8:17", + "nodeType": "YulIdentifier", + "src": "1818:8:17" + }, + "nativeSrc": "1818:34:17", + "nodeType": "YulFunctionCall", + "src": "1818:34:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "1800:17:17", + "nodeType": "YulIdentifier", + "src": "1800:17:17" + }, + "nativeSrc": "1800:53:17", + "nodeType": "YulFunctionCall", + "src": "1800:53:17" + }, + "variableNames": [ + { + "name": "converted", + "nativeSrc": "1787:9:17", + "nodeType": "YulIdentifier", + "src": "1787:9:17" + } + ] + } + ] + }, + "name": "convert_t_uint256_to_t_uint256", + "nativeSrc": "1717:142:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1757:5:17", + "nodeType": "YulTypedName", + "src": "1757:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "converted", + "nativeSrc": "1767:9:17", + "nodeType": "YulTypedName", + "src": "1767:9:17", + "type": "" + } + ], + "src": "1717:142:17" + }, + { + "body": { + "nativeSrc": "1912:28:17", + "nodeType": "YulBlock", + "src": "1912:28:17", + "statements": [ + { + "nativeSrc": "1922:12:17", + "nodeType": "YulAssignment", + "src": "1922:12:17", + "value": { + "name": "value", + "nativeSrc": "1929:5:17", + "nodeType": "YulIdentifier", + "src": "1929:5:17" + }, + "variableNames": [ + { + "name": "ret", + "nativeSrc": "1922:3:17", + "nodeType": "YulIdentifier", + "src": "1922:3:17" + } + ] + } + ] + }, + "name": "prepare_store_t_uint256", + "nativeSrc": "1865:75:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1898:5:17", + "nodeType": "YulTypedName", + "src": "1898:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "ret", + "nativeSrc": "1908:3:17", + "nodeType": "YulTypedName", + "src": "1908:3:17", + "type": "" + } + ], + "src": "1865:75:17" + }, + { + "body": { + "nativeSrc": "2022:193:17", + "nodeType": "YulBlock", + "src": "2022:193:17", + "statements": [ + { + "nativeSrc": "2032:63:17", + "nodeType": "YulVariableDeclaration", + "src": "2032:63:17", + "value": { + "arguments": [ + { + "name": "value_0", + "nativeSrc": "2087:7:17", + "nodeType": "YulIdentifier", + "src": "2087:7:17" + } + ], + "functionName": { + "name": "convert_t_uint256_to_t_uint256", + "nativeSrc": "2056:30:17", + "nodeType": "YulIdentifier", + "src": "2056:30:17" + }, + "nativeSrc": "2056:39:17", + "nodeType": "YulFunctionCall", + "src": "2056:39:17" + }, + "variables": [ + { + "name": "convertedValue_0", + "nativeSrc": "2036:16:17", + "nodeType": "YulTypedName", + "src": "2036:16:17", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "2111:4:17", + "nodeType": "YulIdentifier", + "src": "2111:4:17" + }, + { + "arguments": [ + { + "arguments": [ + { + "name": "slot", + "nativeSrc": "2151:4:17", + "nodeType": "YulIdentifier", + "src": "2151:4:17" + } + ], + "functionName": { + "name": "sload", + "nativeSrc": "2145:5:17", + "nodeType": "YulIdentifier", + "src": "2145:5:17" + }, + "nativeSrc": "2145:11:17", + "nodeType": "YulFunctionCall", + "src": "2145:11:17" + }, + { + "name": "offset", + "nativeSrc": "2158:6:17", + "nodeType": "YulIdentifier", + "src": "2158:6:17" + }, + { + "arguments": [ + { + "name": "convertedValue_0", + "nativeSrc": "2190:16:17", + "nodeType": "YulIdentifier", + "src": "2190:16:17" + } + ], + "functionName": { + "name": "prepare_store_t_uint256", + "nativeSrc": "2166:23:17", + "nodeType": "YulIdentifier", + "src": "2166:23:17" + }, + "nativeSrc": "2166:41:17", + "nodeType": "YulFunctionCall", + "src": "2166:41:17" + } + ], + "functionName": { + "name": "update_byte_slice_dynamic32", + "nativeSrc": "2117:27:17", + "nodeType": "YulIdentifier", + "src": "2117:27:17" + }, + "nativeSrc": "2117:91:17", + "nodeType": "YulFunctionCall", + "src": "2117:91:17" + } + ], + "functionName": { + "name": "sstore", + "nativeSrc": "2104:6:17", + "nodeType": "YulIdentifier", + "src": "2104:6:17" + }, + "nativeSrc": "2104:105:17", + "nodeType": "YulFunctionCall", + "src": "2104:105:17" + }, + "nativeSrc": "2104:105:17", + "nodeType": "YulExpressionStatement", + "src": "2104:105:17" + } + ] + }, + "name": "update_storage_value_t_uint256_to_t_uint256", + "nativeSrc": "1946:269:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "slot", + "nativeSrc": "1999:4:17", + "nodeType": "YulTypedName", + "src": "1999:4:17", + "type": "" + }, + { + "name": "offset", + "nativeSrc": "2005:6:17", + "nodeType": "YulTypedName", + "src": "2005:6:17", + "type": "" + }, + { + "name": "value_0", + "nativeSrc": "2013:7:17", + "nodeType": "YulTypedName", + "src": "2013:7:17", + "type": "" + } + ], + "src": "1946:269:17" + }, + { + "body": { + "nativeSrc": "2270:24:17", + "nodeType": "YulBlock", + "src": "2270:24:17", + "statements": [ + { + "nativeSrc": "2280:8:17", + "nodeType": "YulAssignment", + "src": "2280:8:17", + "value": { + "kind": "number", + "nativeSrc": "2287:1:17", + "nodeType": "YulLiteral", + "src": "2287:1:17", + "type": "", + "value": "0" + }, + "variableNames": [ + { + "name": "ret", + "nativeSrc": "2280:3:17", + "nodeType": "YulIdentifier", + "src": "2280:3:17" + } + ] + } + ] + }, + "name": "zero_value_for_split_t_uint256", + "nativeSrc": "2221:73:17", + "nodeType": "YulFunctionDefinition", + "returnVariables": [ + { + "name": "ret", + "nativeSrc": "2266:3:17", + "nodeType": "YulTypedName", + "src": "2266:3:17", + "type": "" + } + ], + "src": "2221:73:17" + }, + { + "body": { + "nativeSrc": "2353:136:17", + "nodeType": "YulBlock", + "src": "2353:136:17", + "statements": [ + { + "nativeSrc": "2363:46:17", + "nodeType": "YulVariableDeclaration", + "src": "2363:46:17", + "value": { + "arguments": [], + "functionName": { + "name": "zero_value_for_split_t_uint256", + "nativeSrc": "2377:30:17", + "nodeType": "YulIdentifier", + "src": "2377:30:17" + }, + "nativeSrc": "2377:32:17", + "nodeType": "YulFunctionCall", + "src": "2377:32:17" + }, + "variables": [ + { + "name": "zero_0", + "nativeSrc": "2367:6:17", + "nodeType": "YulTypedName", + "src": "2367:6:17", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "2462:4:17", + "nodeType": "YulIdentifier", + "src": "2462:4:17" + }, + { + "name": "offset", + "nativeSrc": "2468:6:17", + "nodeType": "YulIdentifier", + "src": "2468:6:17" + }, + { + "name": "zero_0", + "nativeSrc": "2476:6:17", + "nodeType": "YulIdentifier", + "src": "2476:6:17" + } + ], + "functionName": { + "name": "update_storage_value_t_uint256_to_t_uint256", + "nativeSrc": "2418:43:17", + "nodeType": "YulIdentifier", + "src": "2418:43:17" + }, + "nativeSrc": "2418:65:17", + "nodeType": "YulFunctionCall", + "src": "2418:65:17" + }, + "nativeSrc": "2418:65:17", + "nodeType": "YulExpressionStatement", + "src": "2418:65:17" + } + ] + }, + "name": "storage_set_to_zero_t_uint256", + "nativeSrc": "2300:189:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "slot", + "nativeSrc": "2339:4:17", + "nodeType": "YulTypedName", + "src": "2339:4:17", + "type": "" + }, + { + "name": "offset", + "nativeSrc": "2345:6:17", + "nodeType": "YulTypedName", + "src": "2345:6:17", + "type": "" + } + ], + "src": "2300:189:17" + }, + { + "body": { + "nativeSrc": "2545:136:17", + "nodeType": "YulBlock", + "src": "2545:136:17", + "statements": [ + { + "body": { + "nativeSrc": "2612:63:17", + "nodeType": "YulBlock", + "src": "2612:63:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "start", + "nativeSrc": "2656:5:17", + "nodeType": "YulIdentifier", + "src": "2656:5:17" + }, + { + "kind": "number", + "nativeSrc": "2663:1:17", + "nodeType": "YulLiteral", + "src": "2663:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "storage_set_to_zero_t_uint256", + "nativeSrc": "2626:29:17", + "nodeType": "YulIdentifier", + "src": "2626:29:17" + }, + "nativeSrc": "2626:39:17", + "nodeType": "YulFunctionCall", + "src": "2626:39:17" + }, + "nativeSrc": "2626:39:17", + "nodeType": "YulExpressionStatement", + "src": "2626:39:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "start", + "nativeSrc": "2565:5:17", + "nodeType": "YulIdentifier", + "src": "2565:5:17" + }, + { + "name": "end", + "nativeSrc": "2572:3:17", + "nodeType": "YulIdentifier", + "src": "2572:3:17" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "2562:2:17", + "nodeType": "YulIdentifier", + "src": "2562:2:17" + }, + "nativeSrc": "2562:14:17", + "nodeType": "YulFunctionCall", + "src": "2562:14:17" + }, + "nativeSrc": "2555:120:17", + "nodeType": "YulForLoop", + "post": { + "nativeSrc": "2577:26:17", + "nodeType": "YulBlock", + "src": "2577:26:17", + "statements": [ + { + "nativeSrc": "2579:22:17", + "nodeType": "YulAssignment", + "src": "2579:22:17", + "value": { + "arguments": [ + { + "name": "start", + "nativeSrc": "2592:5:17", + "nodeType": "YulIdentifier", + "src": "2592:5:17" + }, + { + "kind": "number", + "nativeSrc": "2599:1:17", + "nodeType": "YulLiteral", + "src": "2599:1:17", + "type": "", + "value": "1" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "2588:3:17", + "nodeType": "YulIdentifier", + "src": "2588:3:17" + }, + "nativeSrc": "2588:13:17", + "nodeType": "YulFunctionCall", + "src": "2588:13:17" + }, + "variableNames": [ + { + "name": "start", + "nativeSrc": "2579:5:17", + "nodeType": "YulIdentifier", + "src": "2579:5:17" + } + ] + } + ] + }, + "pre": { + "nativeSrc": "2559:2:17", + "nodeType": "YulBlock", + "src": "2559:2:17", + "statements": [] + }, + "src": "2555:120:17" + } + ] + }, + "name": "clear_storage_range_t_bytes1", + "nativeSrc": "2495:186:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "start", + "nativeSrc": "2533:5:17", + "nodeType": "YulTypedName", + "src": "2533:5:17", + "type": "" + }, + { + "name": "end", + "nativeSrc": "2540:3:17", + "nodeType": "YulTypedName", + "src": "2540:3:17", + "type": "" + } + ], + "src": "2495:186:17" + }, + { + "body": { + "nativeSrc": "2766:464:17", + "nodeType": "YulBlock", + "src": "2766:464:17", + "statements": [ + { + "body": { + "nativeSrc": "2792:431:17", + "nodeType": "YulBlock", + "src": "2792:431:17", + "statements": [ + { + "nativeSrc": "2806:54:17", + "nodeType": "YulVariableDeclaration", + "src": "2806:54:17", + "value": { + "arguments": [ + { + "name": "array", + "nativeSrc": "2854:5:17", + "nodeType": "YulIdentifier", + "src": "2854:5:17" + } + ], + "functionName": { + "name": "array_dataslot_t_string_storage", + "nativeSrc": "2822:31:17", + "nodeType": "YulIdentifier", + "src": "2822:31:17" + }, + "nativeSrc": "2822:38:17", + "nodeType": "YulFunctionCall", + "src": "2822:38:17" + }, + "variables": [ + { + "name": "dataArea", + "nativeSrc": "2810:8:17", + "nodeType": "YulTypedName", + "src": "2810:8:17", + "type": "" + } + ] + }, + { + "nativeSrc": "2873:63:17", + "nodeType": "YulVariableDeclaration", + "src": "2873:63:17", + "value": { + "arguments": [ + { + "name": "dataArea", + "nativeSrc": "2896:8:17", + "nodeType": "YulIdentifier", + "src": "2896:8:17" + }, + { + "arguments": [ + { + "name": "startIndex", + "nativeSrc": "2924:10:17", + "nodeType": "YulIdentifier", + "src": "2924:10:17" + } + ], + "functionName": { + "name": "divide_by_32_ceil", + "nativeSrc": "2906:17:17", + "nodeType": "YulIdentifier", + "src": "2906:17:17" + }, + "nativeSrc": "2906:29:17", + "nodeType": "YulFunctionCall", + "src": "2906:29:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "2892:3:17", + "nodeType": "YulIdentifier", + "src": "2892:3:17" + }, + "nativeSrc": "2892:44:17", + "nodeType": "YulFunctionCall", + "src": "2892:44:17" + }, + "variables": [ + { + "name": "deleteStart", + "nativeSrc": "2877:11:17", + "nodeType": "YulTypedName", + "src": "2877:11:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "3093:27:17", + "nodeType": "YulBlock", + "src": "3093:27:17", + "statements": [ + { + "nativeSrc": "3095:23:17", + "nodeType": "YulAssignment", + "src": "3095:23:17", + "value": { + "name": "dataArea", + "nativeSrc": "3110:8:17", + "nodeType": "YulIdentifier", + "src": "3110:8:17" + }, + "variableNames": [ + { + "name": "deleteStart", + "nativeSrc": "3095:11:17", + "nodeType": "YulIdentifier", + "src": "3095:11:17" + } + ] + } + ] + }, + "condition": { + "arguments": [ + { + "name": "startIndex", + "nativeSrc": "3077:10:17", + "nodeType": "YulIdentifier", + "src": "3077:10:17" + }, + { + "kind": "number", + "nativeSrc": "3089:2:17", + "nodeType": "YulLiteral", + "src": "3089:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "3074:2:17", + "nodeType": "YulIdentifier", + "src": "3074:2:17" + }, + "nativeSrc": "3074:18:17", + "nodeType": "YulFunctionCall", + "src": "3074:18:17" + }, + "nativeSrc": "3071:49:17", + "nodeType": "YulIf", + "src": "3071:49:17" + }, + { + "expression": { + "arguments": [ + { + "name": "deleteStart", + "nativeSrc": "3162:11:17", + "nodeType": "YulIdentifier", + "src": "3162:11:17" + }, + { + "arguments": [ + { + "name": "dataArea", + "nativeSrc": "3179:8:17", + "nodeType": "YulIdentifier", + "src": "3179:8:17" + }, + { + "arguments": [ + { + "name": "len", + "nativeSrc": "3207:3:17", + "nodeType": "YulIdentifier", + "src": "3207:3:17" + } + ], + "functionName": { + "name": "divide_by_32_ceil", + "nativeSrc": "3189:17:17", + "nodeType": "YulIdentifier", + "src": "3189:17:17" + }, + "nativeSrc": "3189:22:17", + "nodeType": "YulFunctionCall", + "src": "3189:22:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "3175:3:17", + "nodeType": "YulIdentifier", + "src": "3175:3:17" + }, + "nativeSrc": "3175:37:17", + "nodeType": "YulFunctionCall", + "src": "3175:37:17" + } + ], + "functionName": { + "name": "clear_storage_range_t_bytes1", + "nativeSrc": "3133:28:17", + "nodeType": "YulIdentifier", + "src": "3133:28:17" + }, + "nativeSrc": "3133:80:17", + "nodeType": "YulFunctionCall", + "src": "3133:80:17" + }, + "nativeSrc": "3133:80:17", + "nodeType": "YulExpressionStatement", + "src": "3133:80:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "len", + "nativeSrc": "2783:3:17", + "nodeType": "YulIdentifier", + "src": "2783:3:17" + }, + { + "kind": "number", + "nativeSrc": "2788:2:17", + "nodeType": "YulLiteral", + "src": "2788:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "gt", + "nativeSrc": "2780:2:17", + "nodeType": "YulIdentifier", + "src": "2780:2:17" + }, + "nativeSrc": "2780:11:17", + "nodeType": "YulFunctionCall", + "src": "2780:11:17" + }, + "nativeSrc": "2777:446:17", + "nodeType": "YulIf", + "src": "2777:446:17" + } + ] + }, + "name": "clean_up_bytearray_end_slots_t_string_storage", + "nativeSrc": "2687:543:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "array", + "nativeSrc": "2742:5:17", + "nodeType": "YulTypedName", + "src": "2742:5:17", + "type": "" + }, + { + "name": "len", + "nativeSrc": "2749:3:17", + "nodeType": "YulTypedName", + "src": "2749:3:17", + "type": "" + }, + { + "name": "startIndex", + "nativeSrc": "2754:10:17", + "nodeType": "YulTypedName", + "src": "2754:10:17", + "type": "" + } + ], + "src": "2687:543:17" + }, + { + "body": { + "nativeSrc": "3299:54:17", + "nodeType": "YulBlock", + "src": "3299:54:17", + "statements": [ + { + "nativeSrc": "3309:37:17", + "nodeType": "YulAssignment", + "src": "3309:37:17", + "value": { + "arguments": [ + { + "name": "bits", + "nativeSrc": "3334:4:17", + "nodeType": "YulIdentifier", + "src": "3334:4:17" + }, + { + "name": "value", + "nativeSrc": "3340:5:17", + "nodeType": "YulIdentifier", + "src": "3340:5:17" + } + ], + "functionName": { + "name": "shr", + "nativeSrc": "3330:3:17", + "nodeType": "YulIdentifier", + "src": "3330:3:17" + }, + "nativeSrc": "3330:16:17", + "nodeType": "YulFunctionCall", + "src": "3330:16:17" + }, + "variableNames": [ + { + "name": "newValue", + "nativeSrc": "3309:8:17", + "nodeType": "YulIdentifier", + "src": "3309:8:17" + } + ] + } + ] + }, + "name": "shift_right_unsigned_dynamic", + "nativeSrc": "3236:117:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "bits", + "nativeSrc": "3274:4:17", + "nodeType": "YulTypedName", + "src": "3274:4:17", + "type": "" + }, + { + "name": "value", + "nativeSrc": "3280:5:17", + "nodeType": "YulTypedName", + "src": "3280:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "newValue", + "nativeSrc": "3290:8:17", + "nodeType": "YulTypedName", + "src": "3290:8:17", + "type": "" + } + ], + "src": "3236:117:17" + }, + { + "body": { + "nativeSrc": "3410:118:17", + "nodeType": "YulBlock", + "src": "3410:118:17", + "statements": [ + { + "nativeSrc": "3420:68:17", + "nodeType": "YulVariableDeclaration", + "src": "3420:68:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "3469:1:17", + "nodeType": "YulLiteral", + "src": "3469:1:17", + "type": "", + "value": "8" + }, + { + "name": "bytes", + "nativeSrc": "3472:5:17", + "nodeType": "YulIdentifier", + "src": "3472:5:17" + } + ], + "functionName": { + "name": "mul", + "nativeSrc": "3465:3:17", + "nodeType": "YulIdentifier", + "src": "3465:3:17" + }, + "nativeSrc": "3465:13:17", + "nodeType": "YulFunctionCall", + "src": "3465:13:17" + }, + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "3484:1:17", + "nodeType": "YulLiteral", + "src": "3484:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "not", + "nativeSrc": "3480:3:17", + "nodeType": "YulIdentifier", + "src": "3480:3:17" + }, + "nativeSrc": "3480:6:17", + "nodeType": "YulFunctionCall", + "src": "3480:6:17" + } + ], + "functionName": { + "name": "shift_right_unsigned_dynamic", + "nativeSrc": "3436:28:17", + "nodeType": "YulIdentifier", + "src": "3436:28:17" + }, + "nativeSrc": "3436:51:17", + "nodeType": "YulFunctionCall", + "src": "3436:51:17" + } + ], + "functionName": { + "name": "not", + "nativeSrc": "3432:3:17", + "nodeType": "YulIdentifier", + "src": "3432:3:17" + }, + "nativeSrc": "3432:56:17", + "nodeType": "YulFunctionCall", + "src": "3432:56:17" + }, + "variables": [ + { + "name": "mask", + "nativeSrc": "3424:4:17", + "nodeType": "YulTypedName", + "src": "3424:4:17", + "type": "" + } + ] + }, + { + "nativeSrc": "3497:25:17", + "nodeType": "YulAssignment", + "src": "3497:25:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "3511:4:17", + "nodeType": "YulIdentifier", + "src": "3511:4:17" + }, + { + "name": "mask", + "nativeSrc": "3517:4:17", + "nodeType": "YulIdentifier", + "src": "3517:4:17" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "3507:3:17", + "nodeType": "YulIdentifier", + "src": "3507:3:17" + }, + "nativeSrc": "3507:15:17", + "nodeType": "YulFunctionCall", + "src": "3507:15:17" + }, + "variableNames": [ + { + "name": "result", + "nativeSrc": "3497:6:17", + "nodeType": "YulIdentifier", + "src": "3497:6:17" + } + ] + } + ] + }, + "name": "mask_bytes_dynamic", + "nativeSrc": "3359:169:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "data", + "nativeSrc": "3387:4:17", + "nodeType": "YulTypedName", + "src": "3387:4:17", + "type": "" + }, + { + "name": "bytes", + "nativeSrc": "3393:5:17", + "nodeType": "YulTypedName", + "src": "3393:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "result", + "nativeSrc": "3403:6:17", + "nodeType": "YulTypedName", + "src": "3403:6:17", + "type": "" + } + ], + "src": "3359:169:17" + }, + { + "body": { + "nativeSrc": "3614:214:17", + "nodeType": "YulBlock", + "src": "3614:214:17", + "statements": [ + { + "nativeSrc": "3747:37:17", + "nodeType": "YulAssignment", + "src": "3747:37:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "3774:4:17", + "nodeType": "YulIdentifier", + "src": "3774:4:17" + }, + { + "name": "len", + "nativeSrc": "3780:3:17", + "nodeType": "YulIdentifier", + "src": "3780:3:17" + } + ], + "functionName": { + "name": "mask_bytes_dynamic", + "nativeSrc": "3755:18:17", + "nodeType": "YulIdentifier", + "src": "3755:18:17" + }, + "nativeSrc": "3755:29:17", + "nodeType": "YulFunctionCall", + "src": "3755:29:17" + }, + "variableNames": [ + { + "name": "data", + "nativeSrc": "3747:4:17", + "nodeType": "YulIdentifier", + "src": "3747:4:17" + } + ] + }, + { + "nativeSrc": "3793:29:17", + "nodeType": "YulAssignment", + "src": "3793:29:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "3804:4:17", + "nodeType": "YulIdentifier", + "src": "3804:4:17" + }, + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "3814:1:17", + "nodeType": "YulLiteral", + "src": "3814:1:17", + "type": "", + "value": "2" + }, + { + "name": "len", + "nativeSrc": "3817:3:17", + "nodeType": "YulIdentifier", + "src": "3817:3:17" + } + ], + "functionName": { + "name": "mul", + "nativeSrc": "3810:3:17", + "nodeType": "YulIdentifier", + "src": "3810:3:17" + }, + "nativeSrc": "3810:11:17", + "nodeType": "YulFunctionCall", + "src": "3810:11:17" + } + ], + "functionName": { + "name": "or", + "nativeSrc": "3801:2:17", + "nodeType": "YulIdentifier", + "src": "3801:2:17" + }, + "nativeSrc": "3801:21:17", + "nodeType": "YulFunctionCall", + "src": "3801:21:17" + }, + "variableNames": [ + { + "name": "used", + "nativeSrc": "3793:4:17", + "nodeType": "YulIdentifier", + "src": "3793:4:17" + } + ] + } + ] + }, + "name": "extract_used_part_and_set_length_of_short_byte_array", + "nativeSrc": "3533:295:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "data", + "nativeSrc": "3595:4:17", + "nodeType": "YulTypedName", + "src": "3595:4:17", + "type": "" + }, + { + "name": "len", + "nativeSrc": "3601:3:17", + "nodeType": "YulTypedName", + "src": "3601:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "used", + "nativeSrc": "3609:4:17", + "nodeType": "YulTypedName", + "src": "3609:4:17", + "type": "" + } + ], + "src": "3533:295:17" + }, + { + "body": { + "nativeSrc": "3925:1303:17", + "nodeType": "YulBlock", + "src": "3925:1303:17", + "statements": [ + { + "nativeSrc": "3936:51:17", + "nodeType": "YulVariableDeclaration", + "src": "3936:51:17", + "value": { + "arguments": [ + { + "name": "src", + "nativeSrc": "3983:3:17", + "nodeType": "YulIdentifier", + "src": "3983:3:17" + } + ], + "functionName": { + "name": "array_length_t_string_memory_ptr", + "nativeSrc": "3950:32:17", + "nodeType": "YulIdentifier", + "src": "3950:32:17" + }, + "nativeSrc": "3950:37:17", + "nodeType": "YulFunctionCall", + "src": "3950:37:17" + }, + "variables": [ + { + "name": "newLen", + "nativeSrc": "3940:6:17", + "nodeType": "YulTypedName", + "src": "3940:6:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "4072:22:17", + "nodeType": "YulBlock", + "src": "4072:22:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "panic_error_0x41", + "nativeSrc": "4074:16:17", + "nodeType": "YulIdentifier", + "src": "4074:16:17" + }, + "nativeSrc": "4074:18:17", + "nodeType": "YulFunctionCall", + "src": "4074:18:17" + }, + "nativeSrc": "4074:18:17", + "nodeType": "YulExpressionStatement", + "src": "4074:18:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "newLen", + "nativeSrc": "4044:6:17", + "nodeType": "YulIdentifier", + "src": "4044:6:17" + }, + { + "kind": "number", + "nativeSrc": "4052:18:17", + "nodeType": "YulLiteral", + "src": "4052:18:17", + "type": "", + "value": "0xffffffffffffffff" + } + ], + "functionName": { + "name": "gt", + "nativeSrc": "4041:2:17", + "nodeType": "YulIdentifier", + "src": "4041:2:17" + }, + "nativeSrc": "4041:30:17", + "nodeType": "YulFunctionCall", + "src": "4041:30:17" + }, + "nativeSrc": "4038:56:17", + "nodeType": "YulIf", + "src": "4038:56:17" + }, + { + "nativeSrc": "4104:52:17", + "nodeType": "YulVariableDeclaration", + "src": "4104:52:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "slot", + "nativeSrc": "4150:4:17", + "nodeType": "YulIdentifier", + "src": "4150:4:17" + } + ], + "functionName": { + "name": "sload", + "nativeSrc": "4144:5:17", + "nodeType": "YulIdentifier", + "src": "4144:5:17" + }, + "nativeSrc": "4144:11:17", + "nodeType": "YulFunctionCall", + "src": "4144:11:17" + } + ], + "functionName": { + "name": "extract_byte_array_length", + "nativeSrc": "4118:25:17", + "nodeType": "YulIdentifier", + "src": "4118:25:17" + }, + "nativeSrc": "4118:38:17", + "nodeType": "YulFunctionCall", + "src": "4118:38:17" + }, + "variables": [ + { + "name": "oldLen", + "nativeSrc": "4108:6:17", + "nodeType": "YulTypedName", + "src": "4108:6:17", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "4249:4:17", + "nodeType": "YulIdentifier", + "src": "4249:4:17" + }, + { + "name": "oldLen", + "nativeSrc": "4255:6:17", + "nodeType": "YulIdentifier", + "src": "4255:6:17" + }, + { + "name": "newLen", + "nativeSrc": "4263:6:17", + "nodeType": "YulIdentifier", + "src": "4263:6:17" + } + ], + "functionName": { + "name": "clean_up_bytearray_end_slots_t_string_storage", + "nativeSrc": "4203:45:17", + "nodeType": "YulIdentifier", + "src": "4203:45:17" + }, + "nativeSrc": "4203:67:17", + "nodeType": "YulFunctionCall", + "src": "4203:67:17" + }, + "nativeSrc": "4203:67:17", + "nodeType": "YulExpressionStatement", + "src": "4203:67:17" + }, + { + "nativeSrc": "4280:18:17", + "nodeType": "YulVariableDeclaration", + "src": "4280:18:17", + "value": { + "kind": "number", + "nativeSrc": "4297:1:17", + "nodeType": "YulLiteral", + "src": "4297:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "srcOffset", + "nativeSrc": "4284:9:17", + "nodeType": "YulTypedName", + "src": "4284:9:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4308:17:17", + "nodeType": "YulAssignment", + "src": "4308:17:17", + "value": { + "kind": "number", + "nativeSrc": "4321:4:17", + "nodeType": "YulLiteral", + "src": "4321:4:17", + "type": "", + "value": "0x20" + }, + "variableNames": [ + { + "name": "srcOffset", + "nativeSrc": "4308:9:17", + "nodeType": "YulIdentifier", + "src": "4308:9:17" + } + ] + }, + { + "cases": [ + { + "body": { + "nativeSrc": "4372:611:17", + "nodeType": "YulBlock", + "src": "4372:611:17", + "statements": [ + { + "nativeSrc": "4386:37:17", + "nodeType": "YulVariableDeclaration", + "src": "4386:37:17", + "value": { + "arguments": [ + { + "name": "newLen", + "nativeSrc": "4405:6:17", + "nodeType": "YulIdentifier", + "src": "4405:6:17" + }, + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "4417:4:17", + "nodeType": "YulLiteral", + "src": "4417:4:17", + "type": "", + "value": "0x1f" + } + ], + "functionName": { + "name": "not", + "nativeSrc": "4413:3:17", + "nodeType": "YulIdentifier", + "src": "4413:3:17" + }, + "nativeSrc": "4413:9:17", + "nodeType": "YulFunctionCall", + "src": "4413:9:17" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "4401:3:17", + "nodeType": "YulIdentifier", + "src": "4401:3:17" + }, + "nativeSrc": "4401:22:17", + "nodeType": "YulFunctionCall", + "src": "4401:22:17" + }, + "variables": [ + { + "name": "loopEnd", + "nativeSrc": "4390:7:17", + "nodeType": "YulTypedName", + "src": "4390:7:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4437:51:17", + "nodeType": "YulVariableDeclaration", + "src": "4437:51:17", + "value": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "4483:4:17", + "nodeType": "YulIdentifier", + "src": "4483:4:17" + } + ], + "functionName": { + "name": "array_dataslot_t_string_storage", + "nativeSrc": "4451:31:17", + "nodeType": "YulIdentifier", + "src": "4451:31:17" + }, + "nativeSrc": "4451:37:17", + "nodeType": "YulFunctionCall", + "src": "4451:37:17" + }, + "variables": [ + { + "name": "dstPtr", + "nativeSrc": "4441:6:17", + "nodeType": "YulTypedName", + "src": "4441:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4501:10:17", + "nodeType": "YulVariableDeclaration", + "src": "4501:10:17", + "value": { + "kind": "number", + "nativeSrc": "4510:1:17", + "nodeType": "YulLiteral", + "src": "4510:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "i", + "nativeSrc": "4505:1:17", + "nodeType": "YulTypedName", + "src": "4505:1:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "4569:163:17", + "nodeType": "YulBlock", + "src": "4569:163:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "dstPtr", + "nativeSrc": "4594:6:17", + "nodeType": "YulIdentifier", + "src": "4594:6:17" + }, + { + "arguments": [ + { + "arguments": [ + { + "name": "src", + "nativeSrc": "4612:3:17", + "nodeType": "YulIdentifier", + "src": "4612:3:17" + }, + { + "name": "srcOffset", + "nativeSrc": "4617:9:17", + "nodeType": "YulIdentifier", + "src": "4617:9:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4608:3:17", + "nodeType": "YulIdentifier", + "src": "4608:3:17" + }, + "nativeSrc": "4608:19:17", + "nodeType": "YulFunctionCall", + "src": "4608:19:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "4602:5:17", + "nodeType": "YulIdentifier", + "src": "4602:5:17" + }, + "nativeSrc": "4602:26:17", + "nodeType": "YulFunctionCall", + "src": "4602:26:17" + } + ], + "functionName": { + "name": "sstore", + "nativeSrc": "4587:6:17", + "nodeType": "YulIdentifier", + "src": "4587:6:17" + }, + "nativeSrc": "4587:42:17", + "nodeType": "YulFunctionCall", + "src": "4587:42:17" + }, + "nativeSrc": "4587:42:17", + "nodeType": "YulExpressionStatement", + "src": "4587:42:17" + }, + { + "nativeSrc": "4646:24:17", + "nodeType": "YulAssignment", + "src": "4646:24:17", + "value": { + "arguments": [ + { + "name": "dstPtr", + "nativeSrc": "4660:6:17", + "nodeType": "YulIdentifier", + "src": "4660:6:17" + }, + { + "kind": "number", + "nativeSrc": "4668:1:17", + "nodeType": "YulLiteral", + "src": "4668:1:17", + "type": "", + "value": "1" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4656:3:17", + "nodeType": "YulIdentifier", + "src": "4656:3:17" + }, + "nativeSrc": "4656:14:17", + "nodeType": "YulFunctionCall", + "src": "4656:14:17" + }, + "variableNames": [ + { + "name": "dstPtr", + "nativeSrc": "4646:6:17", + "nodeType": "YulIdentifier", + "src": "4646:6:17" + } + ] + }, + { + "nativeSrc": "4687:31:17", + "nodeType": "YulAssignment", + "src": "4687:31:17", + "value": { + "arguments": [ + { + "name": "srcOffset", + "nativeSrc": "4704:9:17", + "nodeType": "YulIdentifier", + "src": "4704:9:17" + }, + { + "kind": "number", + "nativeSrc": "4715:2:17", + "nodeType": "YulLiteral", + "src": "4715:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4700:3:17", + "nodeType": "YulIdentifier", + "src": "4700:3:17" + }, + "nativeSrc": "4700:18:17", + "nodeType": "YulFunctionCall", + "src": "4700:18:17" + }, + "variableNames": [ + { + "name": "srcOffset", + "nativeSrc": "4687:9:17", + "nodeType": "YulIdentifier", + "src": "4687:9:17" + } + ] + } + ] + }, + "condition": { + "arguments": [ + { + "name": "i", + "nativeSrc": "4535:1:17", + "nodeType": "YulIdentifier", + "src": "4535:1:17" + }, + { + "name": "loopEnd", + "nativeSrc": "4538:7:17", + "nodeType": "YulIdentifier", + "src": "4538:7:17" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "4532:2:17", + "nodeType": "YulIdentifier", + "src": "4532:2:17" + }, + "nativeSrc": "4532:14:17", + "nodeType": "YulFunctionCall", + "src": "4532:14:17" + }, + "nativeSrc": "4524:208:17", + "nodeType": "YulForLoop", + "post": { + "nativeSrc": "4547:21:17", + "nodeType": "YulBlock", + "src": "4547:21:17", + "statements": [ + { + "nativeSrc": "4549:17:17", + "nodeType": "YulAssignment", + "src": "4549:17:17", + "value": { + "arguments": [ + { + "name": "i", + "nativeSrc": "4558:1:17", + "nodeType": "YulIdentifier", + "src": "4558:1:17" + }, + { + "kind": "number", + "nativeSrc": "4561:4:17", + "nodeType": "YulLiteral", + "src": "4561:4:17", + "type": "", + "value": "0x20" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4554:3:17", + "nodeType": "YulIdentifier", + "src": "4554:3:17" + }, + "nativeSrc": "4554:12:17", + "nodeType": "YulFunctionCall", + "src": "4554:12:17" + }, + "variableNames": [ + { + "name": "i", + "nativeSrc": "4549:1:17", + "nodeType": "YulIdentifier", + "src": "4549:1:17" + } + ] + } + ] + }, + "pre": { + "nativeSrc": "4528:3:17", + "nodeType": "YulBlock", + "src": "4528:3:17", + "statements": [] + }, + "src": "4524:208:17" + }, + { + "body": { + "nativeSrc": "4768:156:17", + "nodeType": "YulBlock", + "src": "4768:156:17", + "statements": [ + { + "nativeSrc": "4786:43:17", + "nodeType": "YulVariableDeclaration", + "src": "4786:43:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "src", + "nativeSrc": "4813:3:17", + "nodeType": "YulIdentifier", + "src": "4813:3:17" + }, + { + "name": "srcOffset", + "nativeSrc": "4818:9:17", + "nodeType": "YulIdentifier", + "src": "4818:9:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4809:3:17", + "nodeType": "YulIdentifier", + "src": "4809:3:17" + }, + "nativeSrc": "4809:19:17", + "nodeType": "YulFunctionCall", + "src": "4809:19:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "4803:5:17", + "nodeType": "YulIdentifier", + "src": "4803:5:17" + }, + "nativeSrc": "4803:26:17", + "nodeType": "YulFunctionCall", + "src": "4803:26:17" + }, + "variables": [ + { + "name": "lastValue", + "nativeSrc": "4790:9:17", + "nodeType": "YulTypedName", + "src": "4790:9:17", + "type": "" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "dstPtr", + "nativeSrc": "4853:6:17", + "nodeType": "YulIdentifier", + "src": "4853:6:17" + }, + { + "arguments": [ + { + "name": "lastValue", + "nativeSrc": "4880:9:17", + "nodeType": "YulIdentifier", + "src": "4880:9:17" + }, + { + "arguments": [ + { + "name": "newLen", + "nativeSrc": "4895:6:17", + "nodeType": "YulIdentifier", + "src": "4895:6:17" + }, + { + "kind": "number", + "nativeSrc": "4903:4:17", + "nodeType": "YulLiteral", + "src": "4903:4:17", + "type": "", + "value": "0x1f" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "4891:3:17", + "nodeType": "YulIdentifier", + "src": "4891:3:17" + }, + "nativeSrc": "4891:17:17", + "nodeType": "YulFunctionCall", + "src": "4891:17:17" + } + ], + "functionName": { + "name": "mask_bytes_dynamic", + "nativeSrc": "4861:18:17", + "nodeType": "YulIdentifier", + "src": "4861:18:17" + }, + "nativeSrc": "4861:48:17", + "nodeType": "YulFunctionCall", + "src": "4861:48:17" + } + ], + "functionName": { + "name": "sstore", + "nativeSrc": "4846:6:17", + "nodeType": "YulIdentifier", + "src": "4846:6:17" + }, + "nativeSrc": "4846:64:17", + "nodeType": "YulFunctionCall", + "src": "4846:64:17" + }, + "nativeSrc": "4846:64:17", + "nodeType": "YulExpressionStatement", + "src": "4846:64:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "loopEnd", + "nativeSrc": "4751:7:17", + "nodeType": "YulIdentifier", + "src": "4751:7:17" + }, + { + "name": "newLen", + "nativeSrc": "4760:6:17", + "nodeType": "YulIdentifier", + "src": "4760:6:17" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "4748:2:17", + "nodeType": "YulIdentifier", + "src": "4748:2:17" + }, + "nativeSrc": "4748:19:17", + "nodeType": "YulFunctionCall", + "src": "4748:19:17" + }, + "nativeSrc": "4745:179:17", + "nodeType": "YulIf", + "src": "4745:179:17" + }, + { + "expression": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "4944:4:17", + "nodeType": "YulIdentifier", + "src": "4944:4:17" + }, + { + "arguments": [ + { + "arguments": [ + { + "name": "newLen", + "nativeSrc": "4958:6:17", + "nodeType": "YulIdentifier", + "src": "4958:6:17" + }, + { + "kind": "number", + "nativeSrc": "4966:1:17", + "nodeType": "YulLiteral", + "src": "4966:1:17", + "type": "", + "value": "2" + } + ], + "functionName": { + "name": "mul", + "nativeSrc": "4954:3:17", + "nodeType": "YulIdentifier", + "src": "4954:3:17" + }, + "nativeSrc": "4954:14:17", + "nodeType": "YulFunctionCall", + "src": "4954:14:17" + }, + { + "kind": "number", + "nativeSrc": "4970:1:17", + "nodeType": "YulLiteral", + "src": "4970:1:17", + "type": "", + "value": "1" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4950:3:17", + "nodeType": "YulIdentifier", + "src": "4950:3:17" + }, + "nativeSrc": "4950:22:17", + "nodeType": "YulFunctionCall", + "src": "4950:22:17" + } + ], + "functionName": { + "name": "sstore", + "nativeSrc": "4937:6:17", + "nodeType": "YulIdentifier", + "src": "4937:6:17" + }, + "nativeSrc": "4937:36:17", + "nodeType": "YulFunctionCall", + "src": "4937:36:17" + }, + "nativeSrc": "4937:36:17", + "nodeType": "YulExpressionStatement", + "src": "4937:36:17" + } + ] + }, + "nativeSrc": "4365:618:17", + "nodeType": "YulCase", + "src": "4365:618:17", + "value": { + "kind": "number", + "nativeSrc": "4370:1:17", + "nodeType": "YulLiteral", + "src": "4370:1:17", + "type": "", + "value": "1" + } + }, + { + "body": { + "nativeSrc": "5000:222:17", + "nodeType": "YulBlock", + "src": "5000:222:17", + "statements": [ + { + "nativeSrc": "5014:14:17", + "nodeType": "YulVariableDeclaration", + "src": "5014:14:17", + "value": { + "kind": "number", + "nativeSrc": "5027:1:17", + "nodeType": "YulLiteral", + "src": "5027:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "value", + "nativeSrc": "5018:5:17", + "nodeType": "YulTypedName", + "src": "5018:5:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "5051:67:17", + "nodeType": "YulBlock", + "src": "5051:67:17", + "statements": [ + { + "nativeSrc": "5069:35:17", + "nodeType": "YulAssignment", + "src": "5069:35:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "src", + "nativeSrc": "5088:3:17", + "nodeType": "YulIdentifier", + "src": "5088:3:17" + }, + { + "name": "srcOffset", + "nativeSrc": "5093:9:17", + "nodeType": "YulIdentifier", + "src": "5093:9:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5084:3:17", + "nodeType": "YulIdentifier", + "src": "5084:3:17" + }, + "nativeSrc": "5084:19:17", + "nodeType": "YulFunctionCall", + "src": "5084:19:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "5078:5:17", + "nodeType": "YulIdentifier", + "src": "5078:5:17" + }, + "nativeSrc": "5078:26:17", + "nodeType": "YulFunctionCall", + "src": "5078:26:17" + }, + "variableNames": [ + { + "name": "value", + "nativeSrc": "5069:5:17", + "nodeType": "YulIdentifier", + "src": "5069:5:17" + } + ] + } + ] + }, + "condition": { + "name": "newLen", + "nativeSrc": "5044:6:17", + "nodeType": "YulIdentifier", + "src": "5044:6:17" + }, + "nativeSrc": "5041:77:17", + "nodeType": "YulIf", + "src": "5041:77:17" + }, + { + "expression": { + "arguments": [ + { + "name": "slot", + "nativeSrc": "5138:4:17", + "nodeType": "YulIdentifier", + "src": "5138:4:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "5197:5:17", + "nodeType": "YulIdentifier", + "src": "5197:5:17" + }, + { + "name": "newLen", + "nativeSrc": "5204:6:17", + "nodeType": "YulIdentifier", + "src": "5204:6:17" + } + ], + "functionName": { + "name": "extract_used_part_and_set_length_of_short_byte_array", + "nativeSrc": "5144:52:17", + "nodeType": "YulIdentifier", + "src": "5144:52:17" + }, + "nativeSrc": "5144:67:17", + "nodeType": "YulFunctionCall", + "src": "5144:67:17" + } + ], + "functionName": { + "name": "sstore", + "nativeSrc": "5131:6:17", + "nodeType": "YulIdentifier", + "src": "5131:6:17" + }, + "nativeSrc": "5131:81:17", + "nodeType": "YulFunctionCall", + "src": "5131:81:17" + }, + "nativeSrc": "5131:81:17", + "nodeType": "YulExpressionStatement", + "src": "5131:81:17" + } + ] + }, + "nativeSrc": "4992:230:17", + "nodeType": "YulCase", + "src": "4992:230:17", + "value": "default" + } + ], + "expression": { + "arguments": [ + { + "name": "newLen", + "nativeSrc": "4345:6:17", + "nodeType": "YulIdentifier", + "src": "4345:6:17" + }, + { + "kind": "number", + "nativeSrc": "4353:2:17", + "nodeType": "YulLiteral", + "src": "4353:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "gt", + "nativeSrc": "4342:2:17", + "nodeType": "YulIdentifier", + "src": "4342:2:17" + }, + "nativeSrc": "4342:14:17", + "nodeType": "YulFunctionCall", + "src": "4342:14:17" + }, + "nativeSrc": "4335:887:17", + "nodeType": "YulSwitch", + "src": "4335:887:17" + } + ] + }, + "name": "copy_byte_array_to_storage_from_t_string_memory_ptr_to_t_string_storage", + "nativeSrc": "3833:1395:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "slot", + "nativeSrc": "3914:4:17", + "nodeType": "YulTypedName", + "src": "3914:4:17", + "type": "" + }, + { + "name": "src", + "nativeSrc": "3920:3:17", + "nodeType": "YulTypedName", + "src": "3920:3:17", + "type": "" + } + ], + "src": "3833:1395:17" + }, + { + "body": { + "nativeSrc": "5330:73:17", + "nodeType": "YulBlock", + "src": "5330:73:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "5347:3:17", + "nodeType": "YulIdentifier", + "src": "5347:3:17" + }, + { + "name": "length", + "nativeSrc": "5352:6:17", + "nodeType": "YulIdentifier", + "src": "5352:6:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "5340:6:17", + "nodeType": "YulIdentifier", + "src": "5340:6:17" + }, + "nativeSrc": "5340:19:17", + "nodeType": "YulFunctionCall", + "src": "5340:19:17" + }, + "nativeSrc": "5340:19:17", + "nodeType": "YulExpressionStatement", + "src": "5340:19:17" + }, + { + "nativeSrc": "5368:29:17", + "nodeType": "YulAssignment", + "src": "5368:29:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "5387:3:17", + "nodeType": "YulIdentifier", + "src": "5387:3:17" + }, + { + "kind": "number", + "nativeSrc": "5392:4:17", + "nodeType": "YulLiteral", + "src": "5392:4:17", + "type": "", + "value": "0x20" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5383:3:17", + "nodeType": "YulIdentifier", + "src": "5383:3:17" + }, + "nativeSrc": "5383:14:17", + "nodeType": "YulFunctionCall", + "src": "5383:14:17" + }, + "variableNames": [ + { + "name": "updated_pos", + "nativeSrc": "5368:11:17", + "nodeType": "YulIdentifier", + "src": "5368:11:17" + } + ] + } + ] + }, + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "5234:169:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "5302:3:17", + "nodeType": "YulTypedName", + "src": "5302:3:17", + "type": "" + }, + { + "name": "length", + "nativeSrc": "5307:6:17", + "nodeType": "YulTypedName", + "src": "5307:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "updated_pos", + "nativeSrc": "5318:11:17", + "nodeType": "YulTypedName", + "src": "5318:11:17", + "type": "" + } + ], + "src": "5234:169:17" + }, + { + "body": { + "nativeSrc": "5515:75:17", + "nodeType": "YulBlock", + "src": "5515:75:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "5537:6:17", + "nodeType": "YulIdentifier", + "src": "5537:6:17" + }, + { + "kind": "number", + "nativeSrc": "5545:1:17", + "nodeType": "YulLiteral", + "src": "5545:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5533:3:17", + "nodeType": "YulIdentifier", + "src": "5533:3:17" + }, + "nativeSrc": "5533:14:17", + "nodeType": "YulFunctionCall", + "src": "5533:14:17" + }, + { + "hexValue": "45524332303a206d696e7420746f20746865207a65726f2061646472657373", + "kind": "string", + "nativeSrc": "5549:33:17", + "nodeType": "YulLiteral", + "src": "5549:33:17", + "type": "", + "value": "ERC20: mint to the zero address" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "5526:6:17", + "nodeType": "YulIdentifier", + "src": "5526:6:17" + }, + "nativeSrc": "5526:57:17", + "nodeType": "YulFunctionCall", + "src": "5526:57:17" + }, + "nativeSrc": "5526:57:17", + "nodeType": "YulExpressionStatement", + "src": "5526:57:17" + } + ] + }, + "name": "store_literal_in_memory_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e", + "nativeSrc": "5409:181:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "5507:6:17", + "nodeType": "YulTypedName", + "src": "5507:6:17", + "type": "" + } + ], + "src": "5409:181:17" + }, + { + "body": { + "nativeSrc": "5742:220:17", + "nodeType": "YulBlock", + "src": "5742:220:17", + "statements": [ + { + "nativeSrc": "5752:74:17", + "nodeType": "YulAssignment", + "src": "5752:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "5818:3:17", + "nodeType": "YulIdentifier", + "src": "5818:3:17" + }, + { + "kind": "number", + "nativeSrc": "5823:2:17", + "nodeType": "YulLiteral", + "src": "5823:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "5759:58:17", + "nodeType": "YulIdentifier", + "src": "5759:58:17" + }, + "nativeSrc": "5759:67:17", + "nodeType": "YulFunctionCall", + "src": "5759:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "5752:3:17", + "nodeType": "YulIdentifier", + "src": "5752:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "5924:3:17", + "nodeType": "YulIdentifier", + "src": "5924:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e", + "nativeSrc": "5835:88:17", + "nodeType": "YulIdentifier", + "src": "5835:88:17" + }, + "nativeSrc": "5835:93:17", + "nodeType": "YulFunctionCall", + "src": "5835:93:17" + }, + "nativeSrc": "5835:93:17", + "nodeType": "YulExpressionStatement", + "src": "5835:93:17" + }, + { + "nativeSrc": "5937:19:17", + "nodeType": "YulAssignment", + "src": "5937:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "5948:3:17", + "nodeType": "YulIdentifier", + "src": "5948:3:17" + }, + { + "kind": "number", + "nativeSrc": "5953:2:17", + "nodeType": "YulLiteral", + "src": "5953:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5944:3:17", + "nodeType": "YulIdentifier", + "src": "5944:3:17" + }, + "nativeSrc": "5944:12:17", + "nodeType": "YulFunctionCall", + "src": "5944:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "5937:3:17", + "nodeType": "YulIdentifier", + "src": "5937:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e_to_t_string_memory_ptr_fromStack", + "nativeSrc": "5596:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "5730:3:17", + "nodeType": "YulTypedName", + "src": "5730:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "5738:3:17", + "nodeType": "YulTypedName", + "src": "5738:3:17", + "type": "" + } + ], + "src": "5596:366:17" + }, + { + "body": { + "nativeSrc": "6139:248:17", + "nodeType": "YulBlock", + "src": "6139:248:17", + "statements": [ + { + "nativeSrc": "6149:26:17", + "nodeType": "YulAssignment", + "src": "6149:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "6161:9:17", + "nodeType": "YulIdentifier", + "src": "6161:9:17" + }, + { + "kind": "number", + "nativeSrc": "6172:2:17", + "nodeType": "YulLiteral", + "src": "6172:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6157:3:17", + "nodeType": "YulIdentifier", + "src": "6157:3:17" + }, + "nativeSrc": "6157:18:17", + "nodeType": "YulFunctionCall", + "src": "6157:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "6149:4:17", + "nodeType": "YulIdentifier", + "src": "6149:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "6196:9:17", + "nodeType": "YulIdentifier", + "src": "6196:9:17" + }, + { + "kind": "number", + "nativeSrc": "6207:1:17", + "nodeType": "YulLiteral", + "src": "6207:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6192:3:17", + "nodeType": "YulIdentifier", + "src": "6192:3:17" + }, + "nativeSrc": "6192:17:17", + "nodeType": "YulFunctionCall", + "src": "6192:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "6215:4:17", + "nodeType": "YulIdentifier", + "src": "6215:4:17" + }, + { + "name": "headStart", + "nativeSrc": "6221:9:17", + "nodeType": "YulIdentifier", + "src": "6221:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "6211:3:17", + "nodeType": "YulIdentifier", + "src": "6211:3:17" + }, + "nativeSrc": "6211:20:17", + "nodeType": "YulFunctionCall", + "src": "6211:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6185:6:17", + "nodeType": "YulIdentifier", + "src": "6185:6:17" + }, + "nativeSrc": "6185:47:17", + "nodeType": "YulFunctionCall", + "src": "6185:47:17" + }, + "nativeSrc": "6185:47:17", + "nodeType": "YulExpressionStatement", + "src": "6185:47:17" + }, + { + "nativeSrc": "6241:139:17", + "nodeType": "YulAssignment", + "src": "6241:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "6375:4:17", + "nodeType": "YulIdentifier", + "src": "6375:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e_to_t_string_memory_ptr_fromStack", + "nativeSrc": "6249:124:17", + "nodeType": "YulIdentifier", + "src": "6249:124:17" + }, + "nativeSrc": "6249:131:17", + "nodeType": "YulFunctionCall", + "src": "6249:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "6241:4:17", + "nodeType": "YulIdentifier", + "src": "6241:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "5968:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "6119:9:17", + "nodeType": "YulTypedName", + "src": "6119:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "6134:4:17", + "nodeType": "YulTypedName", + "src": "6134:4:17", + "type": "" + } + ], + "src": "5968:419:17" + }, + { + "body": { + "nativeSrc": "6421:152:17", + "nodeType": "YulBlock", + "src": "6421:152:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6438:1:17", + "nodeType": "YulLiteral", + "src": "6438:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "6441:77:17", + "nodeType": "YulLiteral", + "src": "6441:77:17", + "type": "", + "value": "35408467139433450592217433187231851964531694900788300625387963629091585785856" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6431:6:17", + "nodeType": "YulIdentifier", + "src": "6431:6:17" + }, + "nativeSrc": "6431:88:17", + "nodeType": "YulFunctionCall", + "src": "6431:88:17" + }, + "nativeSrc": "6431:88:17", + "nodeType": "YulExpressionStatement", + "src": "6431:88:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6535:1:17", + "nodeType": "YulLiteral", + "src": "6535:1:17", + "type": "", + "value": "4" + }, + { + "kind": "number", + "nativeSrc": "6538:4:17", + "nodeType": "YulLiteral", + "src": "6538:4:17", + "type": "", + "value": "0x11" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6528:6:17", + "nodeType": "YulIdentifier", + "src": "6528:6:17" + }, + "nativeSrc": "6528:15:17", + "nodeType": "YulFunctionCall", + "src": "6528:15:17" + }, + "nativeSrc": "6528:15:17", + "nodeType": "YulExpressionStatement", + "src": "6528:15:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6559:1:17", + "nodeType": "YulLiteral", + "src": "6559:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "6562:4:17", + "nodeType": "YulLiteral", + "src": "6562:4:17", + "type": "", + "value": "0x24" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "6552:6:17", + "nodeType": "YulIdentifier", + "src": "6552:6:17" + }, + "nativeSrc": "6552:15:17", + "nodeType": "YulFunctionCall", + "src": "6552:15:17" + }, + "nativeSrc": "6552:15:17", + "nodeType": "YulExpressionStatement", + "src": "6552:15:17" + } + ] + }, + "name": "panic_error_0x11", + "nativeSrc": "6393:180:17", + "nodeType": "YulFunctionDefinition", + "src": "6393:180:17" + }, + { + "body": { + "nativeSrc": "6623:147:17", + "nodeType": "YulBlock", + "src": "6623:147:17", + "statements": [ + { + "nativeSrc": "6633:25:17", + "nodeType": "YulAssignment", + "src": "6633:25:17", + "value": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6656:1:17", + "nodeType": "YulIdentifier", + "src": "6656:1:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "6638:17:17", + "nodeType": "YulIdentifier", + "src": "6638:17:17" + }, + "nativeSrc": "6638:20:17", + "nodeType": "YulFunctionCall", + "src": "6638:20:17" + }, + "variableNames": [ + { + "name": "x", + "nativeSrc": "6633:1:17", + "nodeType": "YulIdentifier", + "src": "6633:1:17" + } + ] + }, + { + "nativeSrc": "6667:25:17", + "nodeType": "YulAssignment", + "src": "6667:25:17", + "value": { + "arguments": [ + { + "name": "y", + "nativeSrc": "6690:1:17", + "nodeType": "YulIdentifier", + "src": "6690:1:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "6672:17:17", + "nodeType": "YulIdentifier", + "src": "6672:17:17" + }, + "nativeSrc": "6672:20:17", + "nodeType": "YulFunctionCall", + "src": "6672:20:17" + }, + "variableNames": [ + { + "name": "y", + "nativeSrc": "6667:1:17", + "nodeType": "YulIdentifier", + "src": "6667:1:17" + } + ] + }, + { + "nativeSrc": "6701:16:17", + "nodeType": "YulAssignment", + "src": "6701:16:17", + "value": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6712:1:17", + "nodeType": "YulIdentifier", + "src": "6712:1:17" + }, + { + "name": "y", + "nativeSrc": "6715:1:17", + "nodeType": "YulIdentifier", + "src": "6715:1:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6708:3:17", + "nodeType": "YulIdentifier", + "src": "6708:3:17" + }, + "nativeSrc": "6708:9:17", + "nodeType": "YulFunctionCall", + "src": "6708:9:17" + }, + "variableNames": [ + { + "name": "sum", + "nativeSrc": "6701:3:17", + "nodeType": "YulIdentifier", + "src": "6701:3:17" + } + ] + }, + { + "body": { + "nativeSrc": "6741:22:17", + "nodeType": "YulBlock", + "src": "6741:22:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "panic_error_0x11", + "nativeSrc": "6743:16:17", + "nodeType": "YulIdentifier", + "src": "6743:16:17" + }, + "nativeSrc": "6743:18:17", + "nodeType": "YulFunctionCall", + "src": "6743:18:17" + }, + "nativeSrc": "6743:18:17", + "nodeType": "YulExpressionStatement", + "src": "6743:18:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6733:1:17", + "nodeType": "YulIdentifier", + "src": "6733:1:17" + }, + { + "name": "sum", + "nativeSrc": "6736:3:17", + "nodeType": "YulIdentifier", + "src": "6736:3:17" + } + ], + "functionName": { + "name": "gt", + "nativeSrc": "6730:2:17", + "nodeType": "YulIdentifier", + "src": "6730:2:17" + }, + "nativeSrc": "6730:10:17", + "nodeType": "YulFunctionCall", + "src": "6730:10:17" + }, + "nativeSrc": "6727:36:17", + "nodeType": "YulIf", + "src": "6727:36:17" + } + ] + }, + "name": "checked_add_t_uint256", + "nativeSrc": "6579:191:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "x", + "nativeSrc": "6610:1:17", + "nodeType": "YulTypedName", + "src": "6610:1:17", + "type": "" + }, + { + "name": "y", + "nativeSrc": "6613:1:17", + "nodeType": "YulTypedName", + "src": "6613:1:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "sum", + "nativeSrc": "6619:3:17", + "nodeType": "YulTypedName", + "src": "6619:3:17", + "type": "" + } + ], + "src": "6579:191:17" + }, + { + "body": { + "nativeSrc": "6841:53:17", + "nodeType": "YulBlock", + "src": "6841:53:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "6858:3:17", + "nodeType": "YulIdentifier", + "src": "6858:3:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "6881:5:17", + "nodeType": "YulIdentifier", + "src": "6881:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "6863:17:17", + "nodeType": "YulIdentifier", + "src": "6863:17:17" + }, + "nativeSrc": "6863:24:17", + "nodeType": "YulFunctionCall", + "src": "6863:24:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6851:6:17", + "nodeType": "YulIdentifier", + "src": "6851:6:17" + }, + "nativeSrc": "6851:37:17", + "nodeType": "YulFunctionCall", + "src": "6851:37:17" + }, + "nativeSrc": "6851:37:17", + "nodeType": "YulExpressionStatement", + "src": "6851:37:17" + } + ] + }, + "name": "abi_encode_t_uint256_to_t_uint256_fromStack", + "nativeSrc": "6776:118:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "6829:5:17", + "nodeType": "YulTypedName", + "src": "6829:5:17", + "type": "" + }, + { + "name": "pos", + "nativeSrc": "6836:3:17", + "nodeType": "YulTypedName", + "src": "6836:3:17", + "type": "" + } + ], + "src": "6776:118:17" + }, + { + "body": { + "nativeSrc": "6998:124:17", + "nodeType": "YulBlock", + "src": "6998:124:17", + "statements": [ + { + "nativeSrc": "7008:26:17", + "nodeType": "YulAssignment", + "src": "7008:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "7020:9:17", + "nodeType": "YulIdentifier", + "src": "7020:9:17" + }, + { + "kind": "number", + "nativeSrc": "7031:2:17", + "nodeType": "YulLiteral", + "src": "7031:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7016:3:17", + "nodeType": "YulIdentifier", + "src": "7016:3:17" + }, + "nativeSrc": "7016:18:17", + "nodeType": "YulFunctionCall", + "src": "7016:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "7008:4:17", + "nodeType": "YulIdentifier", + "src": "7008:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value0", + "nativeSrc": "7088:6:17", + "nodeType": "YulIdentifier", + "src": "7088:6:17" + }, + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "7101:9:17", + "nodeType": "YulIdentifier", + "src": "7101:9:17" + }, + { + "kind": "number", + "nativeSrc": "7112:1:17", + "nodeType": "YulLiteral", + "src": "7112:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7097:3:17", + "nodeType": "YulIdentifier", + "src": "7097:3:17" + }, + "nativeSrc": "7097:17:17", + "nodeType": "YulFunctionCall", + "src": "7097:17:17" + } + ], + "functionName": { + "name": "abi_encode_t_uint256_to_t_uint256_fromStack", + "nativeSrc": "7044:43:17", + "nodeType": "YulIdentifier", + "src": "7044:43:17" + }, + "nativeSrc": "7044:71:17", + "nodeType": "YulFunctionCall", + "src": "7044:71:17" + }, + "nativeSrc": "7044:71:17", + "nodeType": "YulExpressionStatement", + "src": "7044:71:17" + } + ] + }, + "name": "abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed", + "nativeSrc": "6900:222:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "6970:9:17", + "nodeType": "YulTypedName", + "src": "6970:9:17", + "type": "" + }, + { + "name": "value0", + "nativeSrc": "6982:6:17", + "nodeType": "YulTypedName", + "src": "6982:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "6993:4:17", + "nodeType": "YulTypedName", + "src": "6993:4:17", + "type": "" + } + ], + "src": "6900:222:17" + } + ] + }, + "contents": "{\n\n function array_length_t_string_memory_ptr(value) -> length {\n\n length := mload(value)\n\n }\n\n function panic_error_0x41() {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x41)\n revert(0, 0x24)\n }\n\n function panic_error_0x22() {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x22)\n revert(0, 0x24)\n }\n\n function extract_byte_array_length(data) -> length {\n length := div(data, 2)\n let outOfPlaceEncoding := and(data, 1)\n if iszero(outOfPlaceEncoding) {\n length := and(length, 0x7f)\n }\n\n if eq(outOfPlaceEncoding, lt(length, 32)) {\n panic_error_0x22()\n }\n }\n\n function array_dataslot_t_string_storage(ptr) -> data {\n data := ptr\n\n mstore(0, ptr)\n data := keccak256(0, 0x20)\n\n }\n\n function divide_by_32_ceil(value) -> result {\n result := div(add(value, 31), 32)\n }\n\n function shift_left_dynamic(bits, value) -> newValue {\n newValue :=\n\n shl(bits, value)\n\n }\n\n function update_byte_slice_dynamic32(value, shiftBytes, toInsert) -> result {\n let shiftBits := mul(shiftBytes, 8)\n let mask := shift_left_dynamic(shiftBits, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n toInsert := shift_left_dynamic(shiftBits, toInsert)\n value := and(value, not(mask))\n result := or(value, and(toInsert, mask))\n }\n\n function cleanup_t_uint256(value) -> cleaned {\n cleaned := value\n }\n\n function identity(value) -> ret {\n ret := value\n }\n\n function convert_t_uint256_to_t_uint256(value) -> converted {\n converted := cleanup_t_uint256(identity(cleanup_t_uint256(value)))\n }\n\n function prepare_store_t_uint256(value) -> ret {\n ret := value\n }\n\n function update_storage_value_t_uint256_to_t_uint256(slot, offset, value_0) {\n let convertedValue_0 := convert_t_uint256_to_t_uint256(value_0)\n sstore(slot, update_byte_slice_dynamic32(sload(slot), offset, prepare_store_t_uint256(convertedValue_0)))\n }\n\n function zero_value_for_split_t_uint256() -> ret {\n ret := 0\n }\n\n function storage_set_to_zero_t_uint256(slot, offset) {\n let zero_0 := zero_value_for_split_t_uint256()\n update_storage_value_t_uint256_to_t_uint256(slot, offset, zero_0)\n }\n\n function clear_storage_range_t_bytes1(start, end) {\n for {} lt(start, end) { start := add(start, 1) }\n {\n storage_set_to_zero_t_uint256(start, 0)\n }\n }\n\n function clean_up_bytearray_end_slots_t_string_storage(array, len, startIndex) {\n\n if gt(len, 31) {\n let dataArea := array_dataslot_t_string_storage(array)\n let deleteStart := add(dataArea, divide_by_32_ceil(startIndex))\n // If we are clearing array to be short byte array, we want to clear only data starting from array data area.\n if lt(startIndex, 32) { deleteStart := dataArea }\n clear_storage_range_t_bytes1(deleteStart, add(dataArea, divide_by_32_ceil(len)))\n }\n\n }\n\n function shift_right_unsigned_dynamic(bits, value) -> newValue {\n newValue :=\n\n shr(bits, value)\n\n }\n\n function mask_bytes_dynamic(data, bytes) -> result {\n let mask := not(shift_right_unsigned_dynamic(mul(8, bytes), not(0)))\n result := and(data, mask)\n }\n function extract_used_part_and_set_length_of_short_byte_array(data, len) -> used {\n // we want to save only elements that are part of the array after resizing\n // others should be set to zero\n data := mask_bytes_dynamic(data, len)\n used := or(data, mul(2, len))\n }\n function copy_byte_array_to_storage_from_t_string_memory_ptr_to_t_string_storage(slot, src) {\n\n let newLen := array_length_t_string_memory_ptr(src)\n // Make sure array length is sane\n if gt(newLen, 0xffffffffffffffff) { panic_error_0x41() }\n\n let oldLen := extract_byte_array_length(sload(slot))\n\n // potentially truncate data\n clean_up_bytearray_end_slots_t_string_storage(slot, oldLen, newLen)\n\n let srcOffset := 0\n\n srcOffset := 0x20\n\n switch gt(newLen, 31)\n case 1 {\n let loopEnd := and(newLen, not(0x1f))\n\n let dstPtr := array_dataslot_t_string_storage(slot)\n let i := 0\n for { } lt(i, loopEnd) { i := add(i, 0x20) } {\n sstore(dstPtr, mload(add(src, srcOffset)))\n dstPtr := add(dstPtr, 1)\n srcOffset := add(srcOffset, 32)\n }\n if lt(loopEnd, newLen) {\n let lastValue := mload(add(src, srcOffset))\n sstore(dstPtr, mask_bytes_dynamic(lastValue, and(newLen, 0x1f)))\n }\n sstore(slot, add(mul(newLen, 2), 1))\n }\n default {\n let value := 0\n if newLen {\n value := mload(add(src, srcOffset))\n }\n sstore(slot, extract_used_part_and_set_length_of_short_byte_array(value, newLen))\n }\n }\n\n function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos {\n mstore(pos, length)\n updated_pos := add(pos, 0x20)\n }\n\n function store_literal_in_memory_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: mint to the zero address\")\n\n }\n\n function abi_encode_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 31)\n store_literal_in_memory_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e(pos)\n end := add(pos, 32)\n }\n\n function abi_encode_tuple_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_fc0b381caf0a47702017f3c4b358ebe3d3aff6c60ce819a8bf3ef5a95d4f202e_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function panic_error_0x11() {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x11)\n revert(0, 0x24)\n }\n\n function checked_add_t_uint256(x, y) -> sum {\n x := cleanup_t_uint256(x)\n y := cleanup_t_uint256(y)\n sum := add(x, y)\n\n if gt(x, sum) { panic_error_0x11() }\n\n }\n\n function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) {\n mstore(pos, cleanup_t_uint256(value))\n }\n\n function abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed(headStart , value0) -> tail {\n tail := add(headStart, 32)\n\n abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0))\n\n }\n\n}\n", + "id": 17, + "language": "Yul", + "name": "#utility.yul" + } + ], + "linkReferences": {}, + "object": "608060405234801562000010575f80fd5b5060405180608001604052806058815260200162001856605891396040518060400160405280600981526020017f54657374546f6b656e0000000000000000000000000000000000000000000000815250816003908162000072919062000490565b50806004908162000084919062000490565b505050620000b773100000000000000000000000000000000000000169152d02c7e14af6800000620000bd60201b60201c565b62000685565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036200012e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200012590620005d2565b60405180910390fd5b620001415f83836200022260201b60201c565b8060025f8282546200015491906200061f565b92505081905550805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508173ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516200020391906200066a565b60405180910390a36200021e5f83836200022760201b60201c565b5050565b505050565b505050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002a857607f821691505b602082108103620002be57620002bd62000263565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003227fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002e5565b6200032e8683620002e5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000378620003726200036c8462000346565b6200034f565b62000346565b9050919050565b5f819050919050565b620003938362000358565b620003ab620003a2826200037f565b848454620002f1565b825550505050565b5f90565b620003c1620003b3565b620003ce81848462000388565b505050565b5b81811015620003f557620003e95f82620003b7565b600181019050620003d4565b5050565b601f82111562000444576200040e81620002c4565b6200041984620002d6565b8101602085101562000429578190505b620004416200043885620002d6565b830182620003d3565b50505b505050565b5f82821c905092915050565b5f620004665f198460080262000449565b1980831691505092915050565b5f62000480838362000455565b9150826002028217905092915050565b6200049b826200022c565b67ffffffffffffffff811115620004b757620004b662000236565b5b620004c3825462000290565b620004d0828285620003f9565b5f60209050601f83116001811462000506575f8415620004f1578287015190505b620004fd858262000473565b8655506200056c565b601f1984166200051686620002c4565b5f5b828110156200053f5784890151825560018201915060208501945060208101905062000518565b868310156200055f57848901516200055b601f89168262000455565b8355505b6001600288020188555050505b505050505050565b5f82825260208201905092915050565b7f45524332303a206d696e7420746f20746865207a65726f2061646472657373005f82015250565b5f620005ba601f8362000574565b9150620005c78262000584565b602082019050919050565b5f6020820190508181035f830152620005eb81620005ac565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6200062b8262000346565b9150620006388362000346565b9250828201905080821115620006535762000652620005f2565b5b92915050565b620006648162000346565b82525050565b5f6020820190506200067f5f83018462000659565b92915050565b6111c380620006935f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063395093511161006f578063395093511461016557806370a082311461019557806395d89b41146101c5578063a457c2d7146101e3578063a9059cbb14610213578063dd62ed3e14610243576100a7565b806306fdde03146100ab578063095ea7b3146100c957806318160ddd146100f957806323b872dd14610117578063313ce56714610147575b5f80fd5b6100b3610273565b6040516100c09190610add565b60405180910390f35b6100e360048036038101906100de9190610b8e565b610303565b6040516100f09190610be6565b60405180910390f35b610101610325565b60405161010e9190610c0e565b60405180910390f35b610131600480360381019061012c9190610c27565b61032e565b60405161013e9190610be6565b60405180910390f35b61014f61035c565b60405161015c9190610c92565b60405180910390f35b61017f600480360381019061017a9190610b8e565b610364565b60405161018c9190610be6565b60405180910390f35b6101af60048036038101906101aa9190610cab565b61039a565b6040516101bc9190610c0e565b60405180910390f35b6101cd6103df565b6040516101da9190610add565b60405180910390f35b6101fd60048036038101906101f89190610b8e565b61046f565b60405161020a9190610be6565b60405180910390f35b61022d60048036038101906102289190610b8e565b6104e4565b60405161023a9190610be6565b60405180910390f35b61025d60048036038101906102589190610cd6565b610506565b60405161026a9190610c0e565b60405180910390f35b60606003805461028290610d41565b80601f01602080910402602001604051908101604052809291908181526020018280546102ae90610d41565b80156102f95780601f106102d0576101008083540402835291602001916102f9565b820191905f5260205f20905b8154815290600101906020018083116102dc57829003601f168201915b5050505050905090565b5f8061030d610588565b905061031a81858561058f565b600191505092915050565b5f600254905090565b5f80610338610588565b9050610345858285610752565b6103508585856107dd565b60019150509392505050565b5f6011905090565b5f8061036e610588565b905061038f8185856103808589610506565b61038a9190610d9e565b61058f565b600191505092915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6060600480546103ee90610d41565b80601f016020809104026020016040519081016040528092919081815260200182805461041a90610d41565b80156104655780601f1061043c57610100808354040283529160200191610465565b820191905f5260205f20905b81548152906001019060200180831161044857829003601f168201915b5050505050905090565b5f80610479610588565b90505f6104868286610506565b9050838110156104cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c290610e41565b60405180910390fd5b6104d8828686840361058f565b60019250505092915050565b5f806104ee610588565b90506104fb8185856107dd565b600191505092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036105fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f490610ecf565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361066b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066290610f5d565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107459190610c0e565b60405180910390a3505050565b5f61075d8484610506565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107d757818110156107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090610fc5565b60405180910390fd5b6107d6848484840361058f565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084290611053565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b0906110e1565b60405180910390fd5b6108c4838383610a49565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610947576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093e9061116f565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a309190610c0e565b60405180910390a3610a43848484610a4e565b50505050565b505050565b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a8a578082015181840152602081019050610a6f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aaf82610a53565b610ab98185610a5d565b9350610ac9818560208601610a6d565b610ad281610a95565b840191505092915050565b5f6020820190508181035f830152610af58184610aa5565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b2a82610b01565b9050919050565b610b3a81610b20565b8114610b44575f80fd5b50565b5f81359050610b5581610b31565b92915050565b5f819050919050565b610b6d81610b5b565b8114610b77575f80fd5b50565b5f81359050610b8881610b64565b92915050565b5f8060408385031215610ba457610ba3610afd565b5b5f610bb185828601610b47565b9250506020610bc285828601610b7a565b9150509250929050565b5f8115159050919050565b610be081610bcc565b82525050565b5f602082019050610bf95f830184610bd7565b92915050565b610c0881610b5b565b82525050565b5f602082019050610c215f830184610bff565b92915050565b5f805f60608486031215610c3e57610c3d610afd565b5b5f610c4b86828701610b47565b9350506020610c5c86828701610b47565b9250506040610c6d86828701610b7a565b9150509250925092565b5f60ff82169050919050565b610c8c81610c77565b82525050565b5f602082019050610ca55f830184610c83565b92915050565b5f60208284031215610cc057610cbf610afd565b5b5f610ccd84828501610b47565b91505092915050565b5f8060408385031215610cec57610ceb610afd565b5b5f610cf985828601610b47565b9250506020610d0a85828601610b47565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d5857607f821691505b602082108103610d6b57610d6a610d14565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610da882610b5b565b9150610db383610b5b565b9250828201905080821115610dcb57610dca610d71565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f775f8201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b5f610e2b602583610a5d565b9150610e3682610dd1565b604082019050919050565b5f6020820190508181035f830152610e5881610e1f565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f610eb9602483610a5d565b9150610ec482610e5f565b604082019050919050565b5f6020820190508181035f830152610ee681610ead565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f2061646472655f8201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b5f610f47602283610a5d565b9150610f5282610eed565b604082019050919050565b5f6020820190508181035f830152610f7481610f3b565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000005f82015250565b5f610faf601d83610a5d565b9150610fba82610f7b565b602082019050919050565b5f6020820190508181035f830152610fdc81610fa3565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f2061645f8201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b5f61103d602583610a5d565b915061104882610fe3565b604082019050919050565b5f6020820190508181035f83015261106a81611031565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6110cb602383610a5d565b91506110d682611071565b604082019050919050565b5f6020820190508181035f8301526110f8816110bf565b9050919050565b7f45524332303a207472616e7366657220616d6f756e74206578636565647320625f8201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b5f611159602683610a5d565b9150611164826110ff565b604082019050919050565b5f6020820190508181035f8301526111868161114d565b905091905056fea264697066735822122062680aa81bd47e484462a2becb3aeaae50eade823ecfad3c2cf3d21b8ba9f39a64736f6c634300081800336c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d65", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH3 0x10 JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x58 DUP2 MSTORE PUSH1 0x20 ADD PUSH3 0x1856 PUSH1 0x58 SWAP2 CODECOPY PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x9 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x54657374546F6B656E0000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x3 SWAP1 DUP2 PUSH3 0x72 SWAP2 SWAP1 PUSH3 0x490 JUMP JUMPDEST POP DUP1 PUSH1 0x4 SWAP1 DUP2 PUSH3 0x84 SWAP2 SWAP1 PUSH3 0x490 JUMP JUMPDEST POP POP POP PUSH3 0xB7 PUSH20 0x1000000000000000000000000000000000000001 PUSH10 0x152D02C7E14AF6800000 PUSH3 0xBD PUSH1 0x20 SHL PUSH1 0x20 SHR JUMP JUMPDEST PUSH3 0x685 JUMP JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH3 0x12E JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH3 0x125 SWAP1 PUSH3 0x5D2 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH3 0x141 PUSH0 DUP4 DUP4 PUSH3 0x222 PUSH1 0x20 SHL PUSH1 0x20 SHR JUMP JUMPDEST DUP1 PUSH1 0x2 PUSH0 DUP3 DUP3 SLOAD PUSH3 0x154 SWAP2 SWAP1 PUSH3 0x61F JUMP JUMPDEST SWAP3 POP POP DUP2 SWAP1 SSTORE POP DUP1 PUSH0 DUP1 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP4 PUSH1 0x40 MLOAD PUSH3 0x203 SWAP2 SWAP1 PUSH3 0x66A JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH3 0x21E PUSH0 DUP4 DUP4 PUSH3 0x227 PUSH1 0x20 SHL PUSH1 0x20 SHR JUMP JUMPDEST POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH1 0x2 DUP3 DIV SWAP1 POP PUSH1 0x1 DUP3 AND DUP1 PUSH3 0x2A8 JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 SUB PUSH3 0x2BE JUMPI PUSH3 0x2BD PUSH3 0x263 JUMP JUMPDEST JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP DUP2 PUSH0 MSTORE PUSH1 0x20 PUSH0 KECCAK256 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 PUSH1 0x1F DUP4 ADD DIV SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP3 DUP3 SHL SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x8 DUP4 MUL PUSH3 0x322 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 PUSH3 0x2E5 JUMP JUMPDEST PUSH3 0x32E DUP7 DUP4 PUSH3 0x2E5 JUMP JUMPDEST SWAP6 POP DUP1 NOT DUP5 AND SWAP4 POP DUP1 DUP7 AND DUP5 OR SWAP3 POP POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH3 0x378 PUSH3 0x372 PUSH3 0x36C DUP5 PUSH3 0x346 JUMP JUMPDEST PUSH3 0x34F JUMP JUMPDEST PUSH3 0x346 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH3 0x393 DUP4 PUSH3 0x358 JUMP JUMPDEST PUSH3 0x3AB PUSH3 0x3A2 DUP3 PUSH3 0x37F JUMP JUMPDEST DUP5 DUP5 SLOAD PUSH3 0x2F1 JUMP JUMPDEST DUP3 SSTORE POP POP POP POP JUMP JUMPDEST PUSH0 SWAP1 JUMP JUMPDEST PUSH3 0x3C1 PUSH3 0x3B3 JUMP JUMPDEST PUSH3 0x3CE DUP2 DUP5 DUP5 PUSH3 0x388 JUMP JUMPDEST POP POP POP JUMP JUMPDEST JUMPDEST DUP2 DUP2 LT ISZERO PUSH3 0x3F5 JUMPI PUSH3 0x3E9 PUSH0 DUP3 PUSH3 0x3B7 JUMP JUMPDEST PUSH1 0x1 DUP2 ADD SWAP1 POP PUSH3 0x3D4 JUMP JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x1F DUP3 GT ISZERO PUSH3 0x444 JUMPI PUSH3 0x40E DUP2 PUSH3 0x2C4 JUMP JUMPDEST PUSH3 0x419 DUP5 PUSH3 0x2D6 JUMP JUMPDEST DUP2 ADD PUSH1 0x20 DUP6 LT ISZERO PUSH3 0x429 JUMPI DUP2 SWAP1 POP JUMPDEST PUSH3 0x441 PUSH3 0x438 DUP6 PUSH3 0x2D6 JUMP JUMPDEST DUP4 ADD DUP3 PUSH3 0x3D3 JUMP JUMPDEST POP POP JUMPDEST POP POP POP JUMP JUMPDEST PUSH0 DUP3 DUP3 SHR SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH3 0x466 PUSH0 NOT DUP5 PUSH1 0x8 MUL PUSH3 0x449 JUMP JUMPDEST NOT DUP1 DUP4 AND SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH3 0x480 DUP4 DUP4 PUSH3 0x455 JUMP JUMPDEST SWAP2 POP DUP3 PUSH1 0x2 MUL DUP3 OR SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH3 0x49B DUP3 PUSH3 0x22C JUMP JUMPDEST PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH3 0x4B7 JUMPI PUSH3 0x4B6 PUSH3 0x236 JUMP JUMPDEST JUMPDEST PUSH3 0x4C3 DUP3 SLOAD PUSH3 0x290 JUMP JUMPDEST PUSH3 0x4D0 DUP3 DUP3 DUP6 PUSH3 0x3F9 JUMP JUMPDEST PUSH0 PUSH1 0x20 SWAP1 POP PUSH1 0x1F DUP4 GT PUSH1 0x1 DUP2 EQ PUSH3 0x506 JUMPI PUSH0 DUP5 ISZERO PUSH3 0x4F1 JUMPI DUP3 DUP8 ADD MLOAD SWAP1 POP JUMPDEST PUSH3 0x4FD DUP6 DUP3 PUSH3 0x473 JUMP JUMPDEST DUP7 SSTORE POP PUSH3 0x56C JUMP JUMPDEST PUSH1 0x1F NOT DUP5 AND PUSH3 0x516 DUP7 PUSH3 0x2C4 JUMP JUMPDEST PUSH0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH3 0x53F JUMPI DUP5 DUP10 ADD MLOAD DUP3 SSTORE PUSH1 0x1 DUP3 ADD SWAP2 POP PUSH1 0x20 DUP6 ADD SWAP5 POP PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH3 0x518 JUMP JUMPDEST DUP7 DUP4 LT ISZERO PUSH3 0x55F JUMPI DUP5 DUP10 ADD MLOAD PUSH3 0x55B PUSH1 0x1F DUP10 AND DUP3 PUSH3 0x455 JUMP JUMPDEST DUP4 SSTORE POP JUMPDEST PUSH1 0x1 PUSH1 0x2 DUP9 MUL ADD DUP9 SSTORE POP POP POP JUMPDEST POP POP POP POP POP POP JUMP JUMPDEST PUSH0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x45524332303A206D696E7420746F20746865207A65726F206164647265737300 PUSH0 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH3 0x5BA PUSH1 0x1F DUP4 PUSH3 0x574 JUMP JUMPDEST SWAP2 POP PUSH3 0x5C7 DUP3 PUSH3 0x584 JUMP JUMPDEST PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH3 0x5EB DUP2 PUSH3 0x5AC JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x11 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH3 0x62B DUP3 PUSH3 0x346 JUMP JUMPDEST SWAP2 POP PUSH3 0x638 DUP4 PUSH3 0x346 JUMP JUMPDEST SWAP3 POP DUP3 DUP3 ADD SWAP1 POP DUP1 DUP3 GT ISZERO PUSH3 0x653 JUMPI PUSH3 0x652 PUSH3 0x5F2 JUMP JUMPDEST JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH3 0x664 DUP2 PUSH3 0x346 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH3 0x67F PUSH0 DUP4 ADD DUP5 PUSH3 0x659 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0x11C3 DUP1 PUSH3 0x693 PUSH0 CODECOPY PUSH0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0xF JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0xA7 JUMPI PUSH0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x39509351 GT PUSH2 0x6F JUMPI DUP1 PUSH4 0x39509351 EQ PUSH2 0x165 JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x195 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x1C5 JUMPI DUP1 PUSH4 0xA457C2D7 EQ PUSH2 0x1E3 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x213 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x243 JUMPI PUSH2 0xA7 JUMP JUMPDEST DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0xAB JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0xF9 JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x117 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x147 JUMPI JUMPDEST PUSH0 DUP1 REVERT JUMPDEST PUSH2 0xB3 PUSH2 0x273 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xC0 SWAP2 SWAP1 PUSH2 0xADD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xE3 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0xDE SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x303 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xF0 SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x101 PUSH2 0x325 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x10E SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x131 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x12C SWAP2 SWAP1 PUSH2 0xC27 JUMP JUMPDEST PUSH2 0x32E JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x13E SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x14F PUSH2 0x35C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xC92 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x17F PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x17A SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x364 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x18C SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1AF PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x1AA SWAP2 SWAP1 PUSH2 0xCAB JUMP JUMPDEST PUSH2 0x39A JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x1BC SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1CD PUSH2 0x3DF JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x1DA SWAP2 SWAP1 PUSH2 0xADD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1FD PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x1F8 SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x46F JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x20A SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x22D PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x228 SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x4E4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x23A SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x25D PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x258 SWAP2 SWAP1 PUSH2 0xCD6 JUMP JUMPDEST PUSH2 0x506 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x26A SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x3 DUP1 SLOAD PUSH2 0x282 SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x2AE SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x2F9 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x2D0 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x2F9 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH0 MSTORE PUSH1 0x20 PUSH0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x2DC JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x30D PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x31A DUP2 DUP6 DUP6 PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x2 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x338 PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x345 DUP6 DUP3 DUP6 PUSH2 0x752 JUMP JUMPDEST PUSH2 0x350 DUP6 DUP6 DUP6 PUSH2 0x7DD JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH0 PUSH1 0x11 SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x36E PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x38F DUP2 DUP6 DUP6 PUSH2 0x380 DUP6 DUP10 PUSH2 0x506 JUMP JUMPDEST PUSH2 0x38A SWAP2 SWAP1 PUSH2 0xD9E JUMP JUMPDEST PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 SLOAD PUSH2 0x3EE SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x41A SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x465 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x43C JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x465 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH0 MSTORE PUSH1 0x20 PUSH0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x448 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x479 PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH0 PUSH2 0x486 DUP3 DUP7 PUSH2 0x506 JUMP JUMPDEST SWAP1 POP DUP4 DUP2 LT ISZERO PUSH2 0x4CB JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x4C2 SWAP1 PUSH2 0xE41 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x4D8 DUP3 DUP7 DUP7 DUP5 SUB PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP3 POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x4EE PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x4FB DUP2 DUP6 DUP6 PUSH2 0x7DD JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x1 PUSH0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 CALLER SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x5FD JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x5F4 SWAP1 PUSH2 0xECF JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x66B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x662 SWAP1 PUSH2 0xF5D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 PUSH1 0x1 PUSH0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 DUP4 PUSH1 0x40 MLOAD PUSH2 0x745 SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH0 PUSH2 0x75D DUP5 DUP5 PUSH2 0x506 JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 EQ PUSH2 0x7D7 JUMPI DUP2 DUP2 LT ISZERO PUSH2 0x7C9 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x7C0 SWAP1 PUSH2 0xFC5 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x7D6 DUP5 DUP5 DUP5 DUP5 SUB PUSH2 0x58F JUMP JUMPDEST JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x84B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x842 SWAP1 PUSH2 0x1053 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x8B9 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x8B0 SWAP1 PUSH2 0x10E1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x8C4 DUP4 DUP4 DUP4 PUSH2 0xA49 JUMP JUMPDEST PUSH0 DUP1 PUSH0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP DUP2 DUP2 LT ISZERO PUSH2 0x947 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x93E SWAP1 PUSH2 0x116F JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP2 DUP2 SUB PUSH0 DUP1 DUP7 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP5 PUSH1 0x40 MLOAD PUSH2 0xA30 SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH2 0xA43 DUP5 DUP5 DUP5 PUSH2 0xA4E JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xA8A JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xA6F JUMP JUMPDEST PUSH0 DUP5 DUP5 ADD MSTORE POP POP POP POP JUMP JUMPDEST PUSH0 PUSH1 0x1F NOT PUSH1 0x1F DUP4 ADD AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH2 0xAAF DUP3 PUSH2 0xA53 JUMP JUMPDEST PUSH2 0xAB9 DUP2 DUP6 PUSH2 0xA5D JUMP JUMPDEST SWAP4 POP PUSH2 0xAC9 DUP2 DUP6 PUSH1 0x20 DUP7 ADD PUSH2 0xA6D JUMP JUMPDEST PUSH2 0xAD2 DUP2 PUSH2 0xA95 JUMP JUMPDEST DUP5 ADD SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xAF5 DUP2 DUP5 PUSH2 0xAA5 JUMP JUMPDEST SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH2 0xB2A DUP3 PUSH2 0xB01 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xB3A DUP2 PUSH2 0xB20 JUMP JUMPDEST DUP2 EQ PUSH2 0xB44 JUMPI PUSH0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xB55 DUP2 PUSH2 0xB31 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xB6D DUP2 PUSH2 0xB5B JUMP JUMPDEST DUP2 EQ PUSH2 0xB77 JUMPI PUSH0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xB88 DUP2 PUSH2 0xB64 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0xBA4 JUMPI PUSH2 0xBA3 PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xBB1 DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x20 PUSH2 0xBC2 DUP6 DUP3 DUP7 ADD PUSH2 0xB7A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH0 DUP2 ISZERO ISZERO SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xBE0 DUP2 PUSH2 0xBCC JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xBF9 PUSH0 DUP4 ADD DUP5 PUSH2 0xBD7 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xC08 DUP2 PUSH2 0xB5B JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xC21 PUSH0 DUP4 ADD DUP5 PUSH2 0xBFF JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH0 PUSH1 0x60 DUP5 DUP7 SUB SLT ISZERO PUSH2 0xC3E JUMPI PUSH2 0xC3D PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xC4B DUP7 DUP3 DUP8 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP4 POP POP PUSH1 0x20 PUSH2 0xC5C DUP7 DUP3 DUP8 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x40 PUSH2 0xC6D DUP7 DUP3 DUP8 ADD PUSH2 0xB7A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 POP SWAP3 JUMP JUMPDEST PUSH0 PUSH1 0xFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xC8C DUP2 PUSH2 0xC77 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xCA5 PUSH0 DUP4 ADD DUP5 PUSH2 0xC83 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCC0 JUMPI PUSH2 0xCBF PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xCCD DUP5 DUP3 DUP6 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0xCEC JUMPI PUSH2 0xCEB PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xCF9 DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x20 PUSH2 0xD0A DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH1 0x2 DUP3 DIV SWAP1 POP PUSH1 0x1 DUP3 AND DUP1 PUSH2 0xD58 JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 SUB PUSH2 0xD6B JUMPI PUSH2 0xD6A PUSH2 0xD14 JUMP JUMPDEST JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x11 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH2 0xDA8 DUP3 PUSH2 0xB5B JUMP JUMPDEST SWAP2 POP PUSH2 0xDB3 DUP4 PUSH2 0xB5B JUMP JUMPDEST SWAP3 POP DUP3 DUP3 ADD SWAP1 POP DUP1 DUP3 GT ISZERO PUSH2 0xDCB JUMPI PUSH2 0xDCA PUSH2 0xD71 JUMP JUMPDEST JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x45524332303A2064656372656173656420616C6C6F77616E63652062656C6F77 PUSH0 DUP3 ADD MSTORE PUSH32 0x207A65726F000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xE2B PUSH1 0x25 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xE36 DUP3 PUSH2 0xDD1 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xE58 DUP2 PUSH2 0xE1F JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20617070726F76652066726F6D20746865207A65726F20616464 PUSH0 DUP3 ADD MSTORE PUSH32 0x7265737300000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xEB9 PUSH1 0x24 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xEC4 DUP3 PUSH2 0xE5F JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xEE6 DUP2 PUSH2 0xEAD JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20617070726F766520746F20746865207A65726F206164647265 PUSH0 DUP3 ADD MSTORE PUSH32 0x7373000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xF47 PUSH1 0x22 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xF52 DUP3 PUSH2 0xEED JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xF74 DUP2 PUSH2 0xF3B JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20696E73756666696369656E7420616C6C6F77616E6365000000 PUSH0 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xFAF PUSH1 0x1D DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xFBA DUP3 PUSH2 0xF7B JUMP JUMPDEST PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xFDC DUP2 PUSH2 0xFA3 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E736665722066726F6D20746865207A65726F206164 PUSH0 DUP3 ADD MSTORE PUSH32 0x6472657373000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x103D PUSH1 0x25 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x1048 DUP3 PUSH2 0xFE3 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x106A DUP2 PUSH2 0x1031 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E7366657220746F20746865207A65726F2061646472 PUSH0 DUP3 ADD MSTORE PUSH32 0x6573730000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x10CB PUSH1 0x23 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x10D6 DUP3 PUSH2 0x1071 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x10F8 DUP2 PUSH2 0x10BF JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E7366657220616D6F756E7420657863656564732062 PUSH0 DUP3 ADD MSTORE PUSH32 0x616C616E63650000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x1159 PUSH1 0x26 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x1164 DUP3 PUSH2 0x10FF JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x1186 DUP2 PUSH2 0x114D JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH3 0x680AA8 SHL 0xD4 PUSH31 0x484462A2BECB3AEAAE50EADE823ECFAD3C2CF3D21B8BA9F39A64736F6C6343 STOP ADDMOD XOR STOP CALLER PUSH13 0x6F6E6720737472696E67206E61 PUSH14 0x652C206C6F6E6720737472696E67 KECCAK256 PUSH15 0x616D652C206C6F6E6720737472696E PUSH8 0x206E616D652C206C PUSH16 0x6E6720737472696E67206E616D652C20 PUSH13 0x6F6E6720737472696E67206E61 PUSH14 0x6500000000000000000000000000 ", + "sourceMap": "128:420:9:-:0;;;171:278;;;;;;;;;;1980:113:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2054:5;2046;:13;;;;;;:::i;:::-;;2079:7;2069;:17;;;;;;:::i;:::-;;1980:113;;360:82:9::1;366:42;410:31;360:5;;;:82;;:::i;:::-;128:420:::0;;8520:535:0;8622:1;8603:21;;:7;:21;;;8595:65;;;;;;;;;;;;:::i;:::-;;;;;;;;;8671:49;8700:1;8704:7;8713:6;8671:20;;;:49;;:::i;:::-;8747:6;8731:12;;:22;;;;;;;:::i;:::-;;;;;;;;8921:6;8899:9;:18;8909:7;8899:18;;;;;;;;;;;;;;;;:28;;;;;;;;;;;8973:7;8952:37;;8969:1;8952:37;;;8982:6;8952:37;;;;;;:::i;:::-;;;;;;;;9000:48;9028:1;9032:7;9041:6;9000:19;;;:48;;:::i;:::-;8520:535;;:::o;12073:91::-;;;;:::o;12752:90::-;;;;:::o;7:99:17:-;59:6;93:5;87:12;77:22;;7:99;;;:::o;112:180::-;160:77;157:1;150:88;257:4;254:1;247:15;281:4;278:1;271:15;298:180;346:77;343:1;336:88;443:4;440:1;433:15;467:4;464:1;457:15;484:320;528:6;565:1;559:4;555:12;545:22;;612:1;606:4;602:12;633:18;623:81;;689:4;681:6;677:17;667:27;;623:81;751:2;743:6;740:14;720:18;717:38;714:84;;770:18;;:::i;:::-;714:84;535:269;484:320;;;:::o;810:141::-;859:4;882:3;874:11;;905:3;902:1;895:14;939:4;936:1;926:18;918:26;;810:141;;;:::o;957:93::-;994:6;1041:2;1036;1029:5;1025:14;1021:23;1011:33;;957:93;;;:::o;1056:107::-;1100:8;1150:5;1144:4;1140:16;1119:37;;1056:107;;;;:::o;1169:393::-;1238:6;1288:1;1276:10;1272:18;1311:97;1341:66;1330:9;1311:97;:::i;:::-;1429:39;1459:8;1448:9;1429:39;:::i;:::-;1417:51;;1501:4;1497:9;1490:5;1486:21;1477:30;;1550:4;1540:8;1536:19;1529:5;1526:30;1516:40;;1245:317;;1169:393;;;;;:::o;1568:77::-;1605:7;1634:5;1623:16;;1568:77;;;:::o;1651:60::-;1679:3;1700:5;1693:12;;1651:60;;;:::o;1717:142::-;1767:9;1800:53;1818:34;1827:24;1845:5;1827:24;:::i;:::-;1818:34;:::i;:::-;1800:53;:::i;:::-;1787:66;;1717:142;;;:::o;1865:75::-;1908:3;1929:5;1922:12;;1865:75;;;:::o;1946:269::-;2056:39;2087:7;2056:39;:::i;:::-;2117:91;2166:41;2190:16;2166:41;:::i;:::-;2158:6;2151:4;2145:11;2117:91;:::i;:::-;2111:4;2104:105;2022:193;1946:269;;;:::o;2221:73::-;2266:3;2221:73;:::o;2300:189::-;2377:32;;:::i;:::-;2418:65;2476:6;2468;2462:4;2418:65;:::i;:::-;2353:136;2300:189;;:::o;2495:186::-;2555:120;2572:3;2565:5;2562:14;2555:120;;;2626:39;2663:1;2656:5;2626:39;:::i;:::-;2599:1;2592:5;2588:13;2579:22;;2555:120;;;2495:186;;:::o;2687:543::-;2788:2;2783:3;2780:11;2777:446;;;2822:38;2854:5;2822:38;:::i;:::-;2906:29;2924:10;2906:29;:::i;:::-;2896:8;2892:44;3089:2;3077:10;3074:18;3071:49;;;3110:8;3095:23;;3071:49;3133:80;3189:22;3207:3;3189:22;:::i;:::-;3179:8;3175:37;3162:11;3133:80;:::i;:::-;2792:431;;2777:446;2687:543;;;:::o;3236:117::-;3290:8;3340:5;3334:4;3330:16;3309:37;;3236:117;;;;:::o;3359:169::-;3403:6;3436:51;3484:1;3480:6;3472:5;3469:1;3465:13;3436:51;:::i;:::-;3432:56;3517:4;3511;3507:15;3497:25;;3410:118;3359:169;;;;:::o;3533:295::-;3609:4;3755:29;3780:3;3774:4;3755:29;:::i;:::-;3747:37;;3817:3;3814:1;3810:11;3804:4;3801:21;3793:29;;3533:295;;;;:::o;3833:1395::-;3950:37;3983:3;3950:37;:::i;:::-;4052:18;4044:6;4041:30;4038:56;;;4074:18;;:::i;:::-;4038:56;4118:38;4150:4;4144:11;4118:38;:::i;:::-;4203:67;4263:6;4255;4249:4;4203:67;:::i;:::-;4297:1;4321:4;4308:17;;4353:2;4345:6;4342:14;4370:1;4365:618;;;;5027:1;5044:6;5041:77;;;5093:9;5088:3;5084:19;5078:26;5069:35;;5041:77;5144:67;5204:6;5197:5;5144:67;:::i;:::-;5138:4;5131:81;5000:222;4335:887;;4365:618;4417:4;4413:9;4405:6;4401:22;4451:37;4483:4;4451:37;:::i;:::-;4510:1;4524:208;4538:7;4535:1;4532:14;4524:208;;;4617:9;4612:3;4608:19;4602:26;4594:6;4587:42;4668:1;4660:6;4656:14;4646:24;;4715:2;4704:9;4700:18;4687:31;;4561:4;4558:1;4554:12;4549:17;;4524:208;;;4760:6;4751:7;4748:19;4745:179;;;4818:9;4813:3;4809:19;4803:26;4861:48;4903:4;4895:6;4891:17;4880:9;4861:48;:::i;:::-;4853:6;4846:64;4768:156;4745:179;4970:1;4966;4958:6;4954:14;4950:22;4944:4;4937:36;4372:611;;;4335:887;;3925:1303;;;3833:1395;;:::o;5234:169::-;5318:11;5352:6;5347:3;5340:19;5392:4;5387:3;5383:14;5368:29;;5234:169;;;;:::o;5409:181::-;5549:33;5545:1;5537:6;5533:14;5526:57;5409:181;:::o;5596:366::-;5738:3;5759:67;5823:2;5818:3;5759:67;:::i;:::-;5752:74;;5835:93;5924:3;5835:93;:::i;:::-;5953:2;5948:3;5944:12;5937:19;;5596:366;;;:::o;5968:419::-;6134:4;6172:2;6161:9;6157:18;6149:26;;6221:9;6215:4;6211:20;6207:1;6196:9;6192:17;6185:47;6249:131;6375:4;6249:131;:::i;:::-;6241:139;;5968:419;;;:::o;6393:180::-;6441:77;6438:1;6431:88;6538:4;6535:1;6528:15;6562:4;6559:1;6552:15;6579:191;6619:3;6638:20;6656:1;6638:20;:::i;:::-;6633:25;;6672:20;6690:1;6672:20;:::i;:::-;6667:25;;6715:1;6712;6708:9;6701:16;;6736:3;6733:1;6730:10;6727:36;;;6743:18;;:::i;:::-;6727:36;6579:191;;;;:::o;6776:118::-;6863:24;6881:5;6863:24;:::i;:::-;6858:3;6851:37;6776:118;;:::o;6900:222::-;6993:4;7031:2;7020:9;7016:18;7008:26;;7044:71;7112:1;7101:9;7097:17;7088:6;7044:71;:::i;:::-;6900:222;;;;:::o;128:420:9:-;;;;;;;" + }, + "deployedBytecode": { + "functionDebugData": { + "@_afterTokenTransfer_585": { + "entryPoint": 2638, + "id": 585, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_approve_520": { + "entryPoint": 1423, + "id": 520, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_beforeTokenTransfer_574": { + "entryPoint": 2633, + "id": 574, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_msgSender_701": { + "entryPoint": 1416, + "id": 701, + "parameterSlots": 0, + "returnSlots": 1 + }, + "@_spendAllowance_563": { + "entryPoint": 1874, + "id": 563, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@_transfer_346": { + "entryPoint": 2013, + "id": 346, + "parameterSlots": 3, + "returnSlots": 0 + }, + "@allowance_141": { + "entryPoint": 1286, + "id": 141, + "parameterSlots": 2, + "returnSlots": 1 + }, + "@approve_166": { + "entryPoint": 771, + "id": 166, + "parameterSlots": 2, + "returnSlots": 1 + }, + "@balanceOf_98": { + "entryPoint": 922, + "id": 98, + "parameterSlots": 1, + "returnSlots": 1 + }, + "@decimals_1027": { + "entryPoint": 860, + "id": 1027, + "parameterSlots": 0, + "returnSlots": 1 + }, + "@decreaseAllowance_269": { + "entryPoint": 1135, + "id": 269, + "parameterSlots": 2, + "returnSlots": 1 + }, + "@increaseAllowance_228": { + "entryPoint": 868, + "id": 228, + "parameterSlots": 2, + "returnSlots": 1 + }, + "@name_54": { + "entryPoint": 627, + "id": 54, + "parameterSlots": 0, + "returnSlots": 1 + }, + "@symbol_64": { + "entryPoint": 991, + "id": 64, + "parameterSlots": 0, + "returnSlots": 1 + }, + "@totalSupply_84": { + "entryPoint": 805, + "id": 84, + "parameterSlots": 0, + "returnSlots": 1 + }, + "@transferFrom_199": { + "entryPoint": 814, + "id": 199, + "parameterSlots": 3, + "returnSlots": 1 + }, + "@transfer_123": { + "entryPoint": 1252, + "id": 123, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_decode_t_address": { + "entryPoint": 2887, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_decode_t_uint256": { + "entryPoint": 2938, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_decode_tuple_t_address": { + "entryPoint": 3243, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_decode_tuple_t_addresst_address": { + "entryPoint": 3286, + "id": null, + "parameterSlots": 2, + "returnSlots": 2 + }, + "abi_decode_tuple_t_addresst_addresst_uint256": { + "entryPoint": 3111, + "id": null, + "parameterSlots": 2, + "returnSlots": 3 + }, + "abi_decode_tuple_t_addresst_uint256": { + "entryPoint": 2958, + "id": null, + "parameterSlots": 2, + "returnSlots": 2 + }, + "abi_encode_t_bool_to_t_bool_fromStack": { + "entryPoint": 3031, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack": { + "entryPoint": 2725, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f_to_t_string_memory_ptr_fromStack": { + "entryPoint": 4287, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029_to_t_string_memory_ptr_fromStack": { + "entryPoint": 3899, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe_to_t_string_memory_ptr_fromStack": { + "entryPoint": 4003, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6_to_t_string_memory_ptr_fromStack": { + "entryPoint": 4429, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea_to_t_string_memory_ptr_fromStack": { + "entryPoint": 4145, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208_to_t_string_memory_ptr_fromStack": { + "entryPoint": 3757, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8_to_t_string_memory_ptr_fromStack": { + "entryPoint": 3615, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_t_uint256_to_t_uint256_fromStack": { + "entryPoint": 3071, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "abi_encode_t_uint8_to_t_uint8_fromStack": { + "entryPoint": 3203, + "id": null, + "parameterSlots": 2, + "returnSlots": 0 + }, + "abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed": { + "entryPoint": 3046, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 2781, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 4321, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 3933, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 4037, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 4463, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 4179, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 3791, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8__to_t_string_memory_ptr__fromStack_reversed": { + "entryPoint": 3649, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed": { + "entryPoint": 3086, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "abi_encode_tuple_t_uint8__to_t_uint8__fromStack_reversed": { + "entryPoint": 3218, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "allocate_unbounded": { + "entryPoint": null, + "id": null, + "parameterSlots": 0, + "returnSlots": 1 + }, + "array_length_t_string_memory_ptr": { + "entryPoint": 2643, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "array_storeLengthForEncoding_t_string_memory_ptr_fromStack": { + "entryPoint": 2653, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "checked_add_t_uint256": { + "entryPoint": 3486, + "id": null, + "parameterSlots": 2, + "returnSlots": 1 + }, + "cleanup_t_address": { + "entryPoint": 2848, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "cleanup_t_bool": { + "entryPoint": 3020, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "cleanup_t_uint160": { + "entryPoint": 2817, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "cleanup_t_uint256": { + "entryPoint": 2907, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "cleanup_t_uint8": { + "entryPoint": 3191, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "copy_memory_to_memory_with_cleanup": { + "entryPoint": 2669, + "id": null, + "parameterSlots": 3, + "returnSlots": 0 + }, + "extract_byte_array_length": { + "entryPoint": 3393, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "panic_error_0x11": { + "entryPoint": 3441, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "panic_error_0x22": { + "entryPoint": 3348, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db": { + "entryPoint": null, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b": { + "entryPoint": 2813, + "id": null, + "parameterSlots": 0, + "returnSlots": 0 + }, + "round_up_to_mul_of_32": { + "entryPoint": 2709, + "id": null, + "parameterSlots": 1, + "returnSlots": 1 + }, + "store_literal_in_memory_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f": { + "entryPoint": 4209, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029": { + "entryPoint": 3821, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe": { + "entryPoint": 3963, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6": { + "entryPoint": 4351, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea": { + "entryPoint": 4067, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208": { + "entryPoint": 3679, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "store_literal_in_memory_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8": { + "entryPoint": 3537, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "validator_revert_t_address": { + "entryPoint": 2865, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + }, + "validator_revert_t_uint256": { + "entryPoint": 2916, + "id": null, + "parameterSlots": 1, + "returnSlots": 0 + } + }, + "generatedSources": [ + { + "ast": { + "nativeSrc": "0:13699:17", + "nodeType": "YulBlock", + "src": "0:13699:17", + "statements": [ + { + "body": { + "nativeSrc": "66:40:17", + "nodeType": "YulBlock", + "src": "66:40:17", + "statements": [ + { + "nativeSrc": "77:22:17", + "nodeType": "YulAssignment", + "src": "77:22:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "93:5:17", + "nodeType": "YulIdentifier", + "src": "93:5:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "87:5:17", + "nodeType": "YulIdentifier", + "src": "87:5:17" + }, + "nativeSrc": "87:12:17", + "nodeType": "YulFunctionCall", + "src": "87:12:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "77:6:17", + "nodeType": "YulIdentifier", + "src": "77:6:17" + } + ] + } + ] + }, + "name": "array_length_t_string_memory_ptr", + "nativeSrc": "7:99:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "49:5:17", + "nodeType": "YulTypedName", + "src": "49:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "length", + "nativeSrc": "59:6:17", + "nodeType": "YulTypedName", + "src": "59:6:17", + "type": "" + } + ], + "src": "7:99:17" + }, + { + "body": { + "nativeSrc": "208:73:17", + "nodeType": "YulBlock", + "src": "208:73:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "225:3:17", + "nodeType": "YulIdentifier", + "src": "225:3:17" + }, + { + "name": "length", + "nativeSrc": "230:6:17", + "nodeType": "YulIdentifier", + "src": "230:6:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "218:6:17", + "nodeType": "YulIdentifier", + "src": "218:6:17" + }, + "nativeSrc": "218:19:17", + "nodeType": "YulFunctionCall", + "src": "218:19:17" + }, + "nativeSrc": "218:19:17", + "nodeType": "YulExpressionStatement", + "src": "218:19:17" + }, + { + "nativeSrc": "246:29:17", + "nodeType": "YulAssignment", + "src": "246:29:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "265:3:17", + "nodeType": "YulIdentifier", + "src": "265:3:17" + }, + { + "kind": "number", + "nativeSrc": "270:4:17", + "nodeType": "YulLiteral", + "src": "270:4:17", + "type": "", + "value": "0x20" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "261:3:17", + "nodeType": "YulIdentifier", + "src": "261:3:17" + }, + "nativeSrc": "261:14:17", + "nodeType": "YulFunctionCall", + "src": "261:14:17" + }, + "variableNames": [ + { + "name": "updated_pos", + "nativeSrc": "246:11:17", + "nodeType": "YulIdentifier", + "src": "246:11:17" + } + ] + } + ] + }, + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "112:169:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "180:3:17", + "nodeType": "YulTypedName", + "src": "180:3:17", + "type": "" + }, + { + "name": "length", + "nativeSrc": "185:6:17", + "nodeType": "YulTypedName", + "src": "185:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "updated_pos", + "nativeSrc": "196:11:17", + "nodeType": "YulTypedName", + "src": "196:11:17", + "type": "" + } + ], + "src": "112:169:17" + }, + { + "body": { + "nativeSrc": "349:184:17", + "nodeType": "YulBlock", + "src": "349:184:17", + "statements": [ + { + "nativeSrc": "359:10:17", + "nodeType": "YulVariableDeclaration", + "src": "359:10:17", + "value": { + "kind": "number", + "nativeSrc": "368:1:17", + "nodeType": "YulLiteral", + "src": "368:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "i", + "nativeSrc": "363:1:17", + "nodeType": "YulTypedName", + "src": "363:1:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "428:63:17", + "nodeType": "YulBlock", + "src": "428:63:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "dst", + "nativeSrc": "453:3:17", + "nodeType": "YulIdentifier", + "src": "453:3:17" + }, + { + "name": "i", + "nativeSrc": "458:1:17", + "nodeType": "YulIdentifier", + "src": "458:1:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "449:3:17", + "nodeType": "YulIdentifier", + "src": "449:3:17" + }, + "nativeSrc": "449:11:17", + "nodeType": "YulFunctionCall", + "src": "449:11:17" + }, + { + "arguments": [ + { + "arguments": [ + { + "name": "src", + "nativeSrc": "472:3:17", + "nodeType": "YulIdentifier", + "src": "472:3:17" + }, + { + "name": "i", + "nativeSrc": "477:1:17", + "nodeType": "YulIdentifier", + "src": "477:1:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "468:3:17", + "nodeType": "YulIdentifier", + "src": "468:3:17" + }, + "nativeSrc": "468:11:17", + "nodeType": "YulFunctionCall", + "src": "468:11:17" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "462:5:17", + "nodeType": "YulIdentifier", + "src": "462:5:17" + }, + "nativeSrc": "462:18:17", + "nodeType": "YulFunctionCall", + "src": "462:18:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "442:6:17", + "nodeType": "YulIdentifier", + "src": "442:6:17" + }, + "nativeSrc": "442:39:17", + "nodeType": "YulFunctionCall", + "src": "442:39:17" + }, + "nativeSrc": "442:39:17", + "nodeType": "YulExpressionStatement", + "src": "442:39:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "i", + "nativeSrc": "389:1:17", + "nodeType": "YulIdentifier", + "src": "389:1:17" + }, + { + "name": "length", + "nativeSrc": "392:6:17", + "nodeType": "YulIdentifier", + "src": "392:6:17" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "386:2:17", + "nodeType": "YulIdentifier", + "src": "386:2:17" + }, + "nativeSrc": "386:13:17", + "nodeType": "YulFunctionCall", + "src": "386:13:17" + }, + "nativeSrc": "378:113:17", + "nodeType": "YulForLoop", + "post": { + "nativeSrc": "400:19:17", + "nodeType": "YulBlock", + "src": "400:19:17", + "statements": [ + { + "nativeSrc": "402:15:17", + "nodeType": "YulAssignment", + "src": "402:15:17", + "value": { + "arguments": [ + { + "name": "i", + "nativeSrc": "411:1:17", + "nodeType": "YulIdentifier", + "src": "411:1:17" + }, + { + "kind": "number", + "nativeSrc": "414:2:17", + "nodeType": "YulLiteral", + "src": "414:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "407:3:17", + "nodeType": "YulIdentifier", + "src": "407:3:17" + }, + "nativeSrc": "407:10:17", + "nodeType": "YulFunctionCall", + "src": "407:10:17" + }, + "variableNames": [ + { + "name": "i", + "nativeSrc": "402:1:17", + "nodeType": "YulIdentifier", + "src": "402:1:17" + } + ] + } + ] + }, + "pre": { + "nativeSrc": "382:3:17", + "nodeType": "YulBlock", + "src": "382:3:17", + "statements": [] + }, + "src": "378:113:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "dst", + "nativeSrc": "511:3:17", + "nodeType": "YulIdentifier", + "src": "511:3:17" + }, + { + "name": "length", + "nativeSrc": "516:6:17", + "nodeType": "YulIdentifier", + "src": "516:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "507:3:17", + "nodeType": "YulIdentifier", + "src": "507:3:17" + }, + "nativeSrc": "507:16:17", + "nodeType": "YulFunctionCall", + "src": "507:16:17" + }, + { + "kind": "number", + "nativeSrc": "525:1:17", + "nodeType": "YulLiteral", + "src": "525:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "500:6:17", + "nodeType": "YulIdentifier", + "src": "500:6:17" + }, + "nativeSrc": "500:27:17", + "nodeType": "YulFunctionCall", + "src": "500:27:17" + }, + "nativeSrc": "500:27:17", + "nodeType": "YulExpressionStatement", + "src": "500:27:17" + } + ] + }, + "name": "copy_memory_to_memory_with_cleanup", + "nativeSrc": "287:246:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "src", + "nativeSrc": "331:3:17", + "nodeType": "YulTypedName", + "src": "331:3:17", + "type": "" + }, + { + "name": "dst", + "nativeSrc": "336:3:17", + "nodeType": "YulTypedName", + "src": "336:3:17", + "type": "" + }, + { + "name": "length", + "nativeSrc": "341:6:17", + "nodeType": "YulTypedName", + "src": "341:6:17", + "type": "" + } + ], + "src": "287:246:17" + }, + { + "body": { + "nativeSrc": "587:54:17", + "nodeType": "YulBlock", + "src": "587:54:17", + "statements": [ + { + "nativeSrc": "597:38:17", + "nodeType": "YulAssignment", + "src": "597:38:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "615:5:17", + "nodeType": "YulIdentifier", + "src": "615:5:17" + }, + { + "kind": "number", + "nativeSrc": "622:2:17", + "nodeType": "YulLiteral", + "src": "622:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "611:3:17", + "nodeType": "YulIdentifier", + "src": "611:3:17" + }, + "nativeSrc": "611:14:17", + "nodeType": "YulFunctionCall", + "src": "611:14:17" + }, + { + "arguments": [ + { + "kind": "number", + "nativeSrc": "631:2:17", + "nodeType": "YulLiteral", + "src": "631:2:17", + "type": "", + "value": "31" + } + ], + "functionName": { + "name": "not", + "nativeSrc": "627:3:17", + "nodeType": "YulIdentifier", + "src": "627:3:17" + }, + "nativeSrc": "627:7:17", + "nodeType": "YulFunctionCall", + "src": "627:7:17" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "607:3:17", + "nodeType": "YulIdentifier", + "src": "607:3:17" + }, + "nativeSrc": "607:28:17", + "nodeType": "YulFunctionCall", + "src": "607:28:17" + }, + "variableNames": [ + { + "name": "result", + "nativeSrc": "597:6:17", + "nodeType": "YulIdentifier", + "src": "597:6:17" + } + ] + } + ] + }, + "name": "round_up_to_mul_of_32", + "nativeSrc": "539:102:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "570:5:17", + "nodeType": "YulTypedName", + "src": "570:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "result", + "nativeSrc": "580:6:17", + "nodeType": "YulTypedName", + "src": "580:6:17", + "type": "" + } + ], + "src": "539:102:17" + }, + { + "body": { + "nativeSrc": "739:285:17", + "nodeType": "YulBlock", + "src": "739:285:17", + "statements": [ + { + "nativeSrc": "749:53:17", + "nodeType": "YulVariableDeclaration", + "src": "749:53:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "796:5:17", + "nodeType": "YulIdentifier", + "src": "796:5:17" + } + ], + "functionName": { + "name": "array_length_t_string_memory_ptr", + "nativeSrc": "763:32:17", + "nodeType": "YulIdentifier", + "src": "763:32:17" + }, + "nativeSrc": "763:39:17", + "nodeType": "YulFunctionCall", + "src": "763:39:17" + }, + "variables": [ + { + "name": "length", + "nativeSrc": "753:6:17", + "nodeType": "YulTypedName", + "src": "753:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "811:78:17", + "nodeType": "YulAssignment", + "src": "811:78:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "877:3:17", + "nodeType": "YulIdentifier", + "src": "877:3:17" + }, + { + "name": "length", + "nativeSrc": "882:6:17", + "nodeType": "YulIdentifier", + "src": "882:6:17" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "818:58:17", + "nodeType": "YulIdentifier", + "src": "818:58:17" + }, + "nativeSrc": "818:71:17", + "nodeType": "YulFunctionCall", + "src": "818:71:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "811:3:17", + "nodeType": "YulIdentifier", + "src": "811:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "937:5:17", + "nodeType": "YulIdentifier", + "src": "937:5:17" + }, + { + "kind": "number", + "nativeSrc": "944:4:17", + "nodeType": "YulLiteral", + "src": "944:4:17", + "type": "", + "value": "0x20" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "933:3:17", + "nodeType": "YulIdentifier", + "src": "933:3:17" + }, + "nativeSrc": "933:16:17", + "nodeType": "YulFunctionCall", + "src": "933:16:17" + }, + { + "name": "pos", + "nativeSrc": "951:3:17", + "nodeType": "YulIdentifier", + "src": "951:3:17" + }, + { + "name": "length", + "nativeSrc": "956:6:17", + "nodeType": "YulIdentifier", + "src": "956:6:17" + } + ], + "functionName": { + "name": "copy_memory_to_memory_with_cleanup", + "nativeSrc": "898:34:17", + "nodeType": "YulIdentifier", + "src": "898:34:17" + }, + "nativeSrc": "898:65:17", + "nodeType": "YulFunctionCall", + "src": "898:65:17" + }, + "nativeSrc": "898:65:17", + "nodeType": "YulExpressionStatement", + "src": "898:65:17" + }, + { + "nativeSrc": "972:46:17", + "nodeType": "YulAssignment", + "src": "972:46:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "983:3:17", + "nodeType": "YulIdentifier", + "src": "983:3:17" + }, + { + "arguments": [ + { + "name": "length", + "nativeSrc": "1010:6:17", + "nodeType": "YulIdentifier", + "src": "1010:6:17" + } + ], + "functionName": { + "name": "round_up_to_mul_of_32", + "nativeSrc": "988:21:17", + "nodeType": "YulIdentifier", + "src": "988:21:17" + }, + "nativeSrc": "988:29:17", + "nodeType": "YulFunctionCall", + "src": "988:29:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "979:3:17", + "nodeType": "YulIdentifier", + "src": "979:3:17" + }, + "nativeSrc": "979:39:17", + "nodeType": "YulFunctionCall", + "src": "979:39:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "972:3:17", + "nodeType": "YulIdentifier", + "src": "972:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack", + "nativeSrc": "647:377:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "720:5:17", + "nodeType": "YulTypedName", + "src": "720:5:17", + "type": "" + }, + { + "name": "pos", + "nativeSrc": "727:3:17", + "nodeType": "YulTypedName", + "src": "727:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "735:3:17", + "nodeType": "YulTypedName", + "src": "735:3:17", + "type": "" + } + ], + "src": "647:377:17" + }, + { + "body": { + "nativeSrc": "1148:195:17", + "nodeType": "YulBlock", + "src": "1148:195:17", + "statements": [ + { + "nativeSrc": "1158:26:17", + "nodeType": "YulAssignment", + "src": "1158:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "1170:9:17", + "nodeType": "YulIdentifier", + "src": "1170:9:17" + }, + { + "kind": "number", + "nativeSrc": "1181:2:17", + "nodeType": "YulLiteral", + "src": "1181:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "1166:3:17", + "nodeType": "YulIdentifier", + "src": "1166:3:17" + }, + "nativeSrc": "1166:18:17", + "nodeType": "YulFunctionCall", + "src": "1166:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "1158:4:17", + "nodeType": "YulIdentifier", + "src": "1158:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "1205:9:17", + "nodeType": "YulIdentifier", + "src": "1205:9:17" + }, + { + "kind": "number", + "nativeSrc": "1216:1:17", + "nodeType": "YulLiteral", + "src": "1216:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "1201:3:17", + "nodeType": "YulIdentifier", + "src": "1201:3:17" + }, + "nativeSrc": "1201:17:17", + "nodeType": "YulFunctionCall", + "src": "1201:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "1224:4:17", + "nodeType": "YulIdentifier", + "src": "1224:4:17" + }, + { + "name": "headStart", + "nativeSrc": "1230:9:17", + "nodeType": "YulIdentifier", + "src": "1230:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "1220:3:17", + "nodeType": "YulIdentifier", + "src": "1220:3:17" + }, + "nativeSrc": "1220:20:17", + "nodeType": "YulFunctionCall", + "src": "1220:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "1194:6:17", + "nodeType": "YulIdentifier", + "src": "1194:6:17" + }, + "nativeSrc": "1194:47:17", + "nodeType": "YulFunctionCall", + "src": "1194:47:17" + }, + "nativeSrc": "1194:47:17", + "nodeType": "YulExpressionStatement", + "src": "1194:47:17" + }, + { + "nativeSrc": "1250:86:17", + "nodeType": "YulAssignment", + "src": "1250:86:17", + "value": { + "arguments": [ + { + "name": "value0", + "nativeSrc": "1322:6:17", + "nodeType": "YulIdentifier", + "src": "1322:6:17" + }, + { + "name": "tail", + "nativeSrc": "1331:4:17", + "nodeType": "YulIdentifier", + "src": "1331:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack", + "nativeSrc": "1258:63:17", + "nodeType": "YulIdentifier", + "src": "1258:63:17" + }, + "nativeSrc": "1258:78:17", + "nodeType": "YulFunctionCall", + "src": "1258:78:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "1250:4:17", + "nodeType": "YulIdentifier", + "src": "1250:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "1030:313:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "1120:9:17", + "nodeType": "YulTypedName", + "src": "1120:9:17", + "type": "" + }, + { + "name": "value0", + "nativeSrc": "1132:6:17", + "nodeType": "YulTypedName", + "src": "1132:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "1143:4:17", + "nodeType": "YulTypedName", + "src": "1143:4:17", + "type": "" + } + ], + "src": "1030:313:17" + }, + { + "body": { + "nativeSrc": "1389:35:17", + "nodeType": "YulBlock", + "src": "1389:35:17", + "statements": [ + { + "nativeSrc": "1399:19:17", + "nodeType": "YulAssignment", + "src": "1399:19:17", + "value": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "1415:2:17", + "nodeType": "YulLiteral", + "src": "1415:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "mload", + "nativeSrc": "1409:5:17", + "nodeType": "YulIdentifier", + "src": "1409:5:17" + }, + "nativeSrc": "1409:9:17", + "nodeType": "YulFunctionCall", + "src": "1409:9:17" + }, + "variableNames": [ + { + "name": "memPtr", + "nativeSrc": "1399:6:17", + "nodeType": "YulIdentifier", + "src": "1399:6:17" + } + ] + } + ] + }, + "name": "allocate_unbounded", + "nativeSrc": "1349:75:17", + "nodeType": "YulFunctionDefinition", + "returnVariables": [ + { + "name": "memPtr", + "nativeSrc": "1382:6:17", + "nodeType": "YulTypedName", + "src": "1382:6:17", + "type": "" + } + ], + "src": "1349:75:17" + }, + { + "body": { + "nativeSrc": "1519:28:17", + "nodeType": "YulBlock", + "src": "1519:28:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "1536:1:17", + "nodeType": "YulLiteral", + "src": "1536:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "1539:1:17", + "nodeType": "YulLiteral", + "src": "1539:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "1529:6:17", + "nodeType": "YulIdentifier", + "src": "1529:6:17" + }, + "nativeSrc": "1529:12:17", + "nodeType": "YulFunctionCall", + "src": "1529:12:17" + }, + "nativeSrc": "1529:12:17", + "nodeType": "YulExpressionStatement", + "src": "1529:12:17" + } + ] + }, + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nativeSrc": "1430:117:17", + "nodeType": "YulFunctionDefinition", + "src": "1430:117:17" + }, + { + "body": { + "nativeSrc": "1642:28:17", + "nodeType": "YulBlock", + "src": "1642:28:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "1659:1:17", + "nodeType": "YulLiteral", + "src": "1659:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "1662:1:17", + "nodeType": "YulLiteral", + "src": "1662:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "1652:6:17", + "nodeType": "YulIdentifier", + "src": "1652:6:17" + }, + "nativeSrc": "1652:12:17", + "nodeType": "YulFunctionCall", + "src": "1652:12:17" + }, + "nativeSrc": "1652:12:17", + "nodeType": "YulExpressionStatement", + "src": "1652:12:17" + } + ] + }, + "name": "revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db", + "nativeSrc": "1553:117:17", + "nodeType": "YulFunctionDefinition", + "src": "1553:117:17" + }, + { + "body": { + "nativeSrc": "1721:81:17", + "nodeType": "YulBlock", + "src": "1721:81:17", + "statements": [ + { + "nativeSrc": "1731:65:17", + "nodeType": "YulAssignment", + "src": "1731:65:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "1746:5:17", + "nodeType": "YulIdentifier", + "src": "1746:5:17" + }, + { + "kind": "number", + "nativeSrc": "1753:42:17", + "nodeType": "YulLiteral", + "src": "1753:42:17", + "type": "", + "value": "0xffffffffffffffffffffffffffffffffffffffff" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "1742:3:17", + "nodeType": "YulIdentifier", + "src": "1742:3:17" + }, + "nativeSrc": "1742:54:17", + "nodeType": "YulFunctionCall", + "src": "1742:54:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "1731:7:17", + "nodeType": "YulIdentifier", + "src": "1731:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_uint160", + "nativeSrc": "1676:126:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1703:5:17", + "nodeType": "YulTypedName", + "src": "1703:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "1713:7:17", + "nodeType": "YulTypedName", + "src": "1713:7:17", + "type": "" + } + ], + "src": "1676:126:17" + }, + { + "body": { + "nativeSrc": "1853:51:17", + "nodeType": "YulBlock", + "src": "1853:51:17", + "statements": [ + { + "nativeSrc": "1863:35:17", + "nodeType": "YulAssignment", + "src": "1863:35:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "1892:5:17", + "nodeType": "YulIdentifier", + "src": "1892:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint160", + "nativeSrc": "1874:17:17", + "nodeType": "YulIdentifier", + "src": "1874:17:17" + }, + "nativeSrc": "1874:24:17", + "nodeType": "YulFunctionCall", + "src": "1874:24:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "1863:7:17", + "nodeType": "YulIdentifier", + "src": "1863:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_address", + "nativeSrc": "1808:96:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1835:5:17", + "nodeType": "YulTypedName", + "src": "1835:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "1845:7:17", + "nodeType": "YulTypedName", + "src": "1845:7:17", + "type": "" + } + ], + "src": "1808:96:17" + }, + { + "body": { + "nativeSrc": "1953:79:17", + "nodeType": "YulBlock", + "src": "1953:79:17", + "statements": [ + { + "body": { + "nativeSrc": "2010:16:17", + "nodeType": "YulBlock", + "src": "2010:16:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "2019:1:17", + "nodeType": "YulLiteral", + "src": "2019:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "2022:1:17", + "nodeType": "YulLiteral", + "src": "2022:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "2012:6:17", + "nodeType": "YulIdentifier", + "src": "2012:6:17" + }, + "nativeSrc": "2012:12:17", + "nodeType": "YulFunctionCall", + "src": "2012:12:17" + }, + "nativeSrc": "2012:12:17", + "nodeType": "YulExpressionStatement", + "src": "2012:12:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "1976:5:17", + "nodeType": "YulIdentifier", + "src": "1976:5:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "2001:5:17", + "nodeType": "YulIdentifier", + "src": "2001:5:17" + } + ], + "functionName": { + "name": "cleanup_t_address", + "nativeSrc": "1983:17:17", + "nodeType": "YulIdentifier", + "src": "1983:17:17" + }, + "nativeSrc": "1983:24:17", + "nodeType": "YulFunctionCall", + "src": "1983:24:17" + } + ], + "functionName": { + "name": "eq", + "nativeSrc": "1973:2:17", + "nodeType": "YulIdentifier", + "src": "1973:2:17" + }, + "nativeSrc": "1973:35:17", + "nodeType": "YulFunctionCall", + "src": "1973:35:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "1966:6:17", + "nodeType": "YulIdentifier", + "src": "1966:6:17" + }, + "nativeSrc": "1966:43:17", + "nodeType": "YulFunctionCall", + "src": "1966:43:17" + }, + "nativeSrc": "1963:63:17", + "nodeType": "YulIf", + "src": "1963:63:17" + } + ] + }, + "name": "validator_revert_t_address", + "nativeSrc": "1910:122:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "1946:5:17", + "nodeType": "YulTypedName", + "src": "1946:5:17", + "type": "" + } + ], + "src": "1910:122:17" + }, + { + "body": { + "nativeSrc": "2090:87:17", + "nodeType": "YulBlock", + "src": "2090:87:17", + "statements": [ + { + "nativeSrc": "2100:29:17", + "nodeType": "YulAssignment", + "src": "2100:29:17", + "value": { + "arguments": [ + { + "name": "offset", + "nativeSrc": "2122:6:17", + "nodeType": "YulIdentifier", + "src": "2122:6:17" + } + ], + "functionName": { + "name": "calldataload", + "nativeSrc": "2109:12:17", + "nodeType": "YulIdentifier", + "src": "2109:12:17" + }, + "nativeSrc": "2109:20:17", + "nodeType": "YulFunctionCall", + "src": "2109:20:17" + }, + "variableNames": [ + { + "name": "value", + "nativeSrc": "2100:5:17", + "nodeType": "YulIdentifier", + "src": "2100:5:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value", + "nativeSrc": "2165:5:17", + "nodeType": "YulIdentifier", + "src": "2165:5:17" + } + ], + "functionName": { + "name": "validator_revert_t_address", + "nativeSrc": "2138:26:17", + "nodeType": "YulIdentifier", + "src": "2138:26:17" + }, + "nativeSrc": "2138:33:17", + "nodeType": "YulFunctionCall", + "src": "2138:33:17" + }, + "nativeSrc": "2138:33:17", + "nodeType": "YulExpressionStatement", + "src": "2138:33:17" + } + ] + }, + "name": "abi_decode_t_address", + "nativeSrc": "2038:139:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "offset", + "nativeSrc": "2068:6:17", + "nodeType": "YulTypedName", + "src": "2068:6:17", + "type": "" + }, + { + "name": "end", + "nativeSrc": "2076:3:17", + "nodeType": "YulTypedName", + "src": "2076:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value", + "nativeSrc": "2084:5:17", + "nodeType": "YulTypedName", + "src": "2084:5:17", + "type": "" + } + ], + "src": "2038:139:17" + }, + { + "body": { + "nativeSrc": "2228:32:17", + "nodeType": "YulBlock", + "src": "2228:32:17", + "statements": [ + { + "nativeSrc": "2238:16:17", + "nodeType": "YulAssignment", + "src": "2238:16:17", + "value": { + "name": "value", + "nativeSrc": "2249:5:17", + "nodeType": "YulIdentifier", + "src": "2249:5:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "2238:7:17", + "nodeType": "YulIdentifier", + "src": "2238:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_uint256", + "nativeSrc": "2183:77:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "2210:5:17", + "nodeType": "YulTypedName", + "src": "2210:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "2220:7:17", + "nodeType": "YulTypedName", + "src": "2220:7:17", + "type": "" + } + ], + "src": "2183:77:17" + }, + { + "body": { + "nativeSrc": "2309:79:17", + "nodeType": "YulBlock", + "src": "2309:79:17", + "statements": [ + { + "body": { + "nativeSrc": "2366:16:17", + "nodeType": "YulBlock", + "src": "2366:16:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "2375:1:17", + "nodeType": "YulLiteral", + "src": "2375:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "2378:1:17", + "nodeType": "YulLiteral", + "src": "2378:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "2368:6:17", + "nodeType": "YulIdentifier", + "src": "2368:6:17" + }, + "nativeSrc": "2368:12:17", + "nodeType": "YulFunctionCall", + "src": "2368:12:17" + }, + "nativeSrc": "2368:12:17", + "nodeType": "YulExpressionStatement", + "src": "2368:12:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "2332:5:17", + "nodeType": "YulIdentifier", + "src": "2332:5:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "2357:5:17", + "nodeType": "YulIdentifier", + "src": "2357:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "2339:17:17", + "nodeType": "YulIdentifier", + "src": "2339:17:17" + }, + "nativeSrc": "2339:24:17", + "nodeType": "YulFunctionCall", + "src": "2339:24:17" + } + ], + "functionName": { + "name": "eq", + "nativeSrc": "2329:2:17", + "nodeType": "YulIdentifier", + "src": "2329:2:17" + }, + "nativeSrc": "2329:35:17", + "nodeType": "YulFunctionCall", + "src": "2329:35:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "2322:6:17", + "nodeType": "YulIdentifier", + "src": "2322:6:17" + }, + "nativeSrc": "2322:43:17", + "nodeType": "YulFunctionCall", + "src": "2322:43:17" + }, + "nativeSrc": "2319:63:17", + "nodeType": "YulIf", + "src": "2319:63:17" + } + ] + }, + "name": "validator_revert_t_uint256", + "nativeSrc": "2266:122:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "2302:5:17", + "nodeType": "YulTypedName", + "src": "2302:5:17", + "type": "" + } + ], + "src": "2266:122:17" + }, + { + "body": { + "nativeSrc": "2446:87:17", + "nodeType": "YulBlock", + "src": "2446:87:17", + "statements": [ + { + "nativeSrc": "2456:29:17", + "nodeType": "YulAssignment", + "src": "2456:29:17", + "value": { + "arguments": [ + { + "name": "offset", + "nativeSrc": "2478:6:17", + "nodeType": "YulIdentifier", + "src": "2478:6:17" + } + ], + "functionName": { + "name": "calldataload", + "nativeSrc": "2465:12:17", + "nodeType": "YulIdentifier", + "src": "2465:12:17" + }, + "nativeSrc": "2465:20:17", + "nodeType": "YulFunctionCall", + "src": "2465:20:17" + }, + "variableNames": [ + { + "name": "value", + "nativeSrc": "2456:5:17", + "nodeType": "YulIdentifier", + "src": "2456:5:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value", + "nativeSrc": "2521:5:17", + "nodeType": "YulIdentifier", + "src": "2521:5:17" + } + ], + "functionName": { + "name": "validator_revert_t_uint256", + "nativeSrc": "2494:26:17", + "nodeType": "YulIdentifier", + "src": "2494:26:17" + }, + "nativeSrc": "2494:33:17", + "nodeType": "YulFunctionCall", + "src": "2494:33:17" + }, + "nativeSrc": "2494:33:17", + "nodeType": "YulExpressionStatement", + "src": "2494:33:17" + } + ] + }, + "name": "abi_decode_t_uint256", + "nativeSrc": "2394:139:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "offset", + "nativeSrc": "2424:6:17", + "nodeType": "YulTypedName", + "src": "2424:6:17", + "type": "" + }, + { + "name": "end", + "nativeSrc": "2432:3:17", + "nodeType": "YulTypedName", + "src": "2432:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value", + "nativeSrc": "2440:5:17", + "nodeType": "YulTypedName", + "src": "2440:5:17", + "type": "" + } + ], + "src": "2394:139:17" + }, + { + "body": { + "nativeSrc": "2622:391:17", + "nodeType": "YulBlock", + "src": "2622:391:17", + "statements": [ + { + "body": { + "nativeSrc": "2668:83:17", + "nodeType": "YulBlock", + "src": "2668:83:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nativeSrc": "2670:77:17", + "nodeType": "YulIdentifier", + "src": "2670:77:17" + }, + "nativeSrc": "2670:79:17", + "nodeType": "YulFunctionCall", + "src": "2670:79:17" + }, + "nativeSrc": "2670:79:17", + "nodeType": "YulExpressionStatement", + "src": "2670:79:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "dataEnd", + "nativeSrc": "2643:7:17", + "nodeType": "YulIdentifier", + "src": "2643:7:17" + }, + { + "name": "headStart", + "nativeSrc": "2652:9:17", + "nodeType": "YulIdentifier", + "src": "2652:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "2639:3:17", + "nodeType": "YulIdentifier", + "src": "2639:3:17" + }, + "nativeSrc": "2639:23:17", + "nodeType": "YulFunctionCall", + "src": "2639:23:17" + }, + { + "kind": "number", + "nativeSrc": "2664:2:17", + "nodeType": "YulLiteral", + "src": "2664:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "slt", + "nativeSrc": "2635:3:17", + "nodeType": "YulIdentifier", + "src": "2635:3:17" + }, + "nativeSrc": "2635:32:17", + "nodeType": "YulFunctionCall", + "src": "2635:32:17" + }, + "nativeSrc": "2632:119:17", + "nodeType": "YulIf", + "src": "2632:119:17" + }, + { + "nativeSrc": "2761:117:17", + "nodeType": "YulBlock", + "src": "2761:117:17", + "statements": [ + { + "nativeSrc": "2776:15:17", + "nodeType": "YulVariableDeclaration", + "src": "2776:15:17", + "value": { + "kind": "number", + "nativeSrc": "2790:1:17", + "nodeType": "YulLiteral", + "src": "2790:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "2780:6:17", + "nodeType": "YulTypedName", + "src": "2780:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "2805:63:17", + "nodeType": "YulAssignment", + "src": "2805:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "2840:9:17", + "nodeType": "YulIdentifier", + "src": "2840:9:17" + }, + { + "name": "offset", + "nativeSrc": "2851:6:17", + "nodeType": "YulIdentifier", + "src": "2851:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "2836:3:17", + "nodeType": "YulIdentifier", + "src": "2836:3:17" + }, + "nativeSrc": "2836:22:17", + "nodeType": "YulFunctionCall", + "src": "2836:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "2860:7:17", + "nodeType": "YulIdentifier", + "src": "2860:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "2815:20:17", + "nodeType": "YulIdentifier", + "src": "2815:20:17" + }, + "nativeSrc": "2815:53:17", + "nodeType": "YulFunctionCall", + "src": "2815:53:17" + }, + "variableNames": [ + { + "name": "value0", + "nativeSrc": "2805:6:17", + "nodeType": "YulIdentifier", + "src": "2805:6:17" + } + ] + } + ] + }, + { + "nativeSrc": "2888:118:17", + "nodeType": "YulBlock", + "src": "2888:118:17", + "statements": [ + { + "nativeSrc": "2903:16:17", + "nodeType": "YulVariableDeclaration", + "src": "2903:16:17", + "value": { + "kind": "number", + "nativeSrc": "2917:2:17", + "nodeType": "YulLiteral", + "src": "2917:2:17", + "type": "", + "value": "32" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "2907:6:17", + "nodeType": "YulTypedName", + "src": "2907:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "2933:63:17", + "nodeType": "YulAssignment", + "src": "2933:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "2968:9:17", + "nodeType": "YulIdentifier", + "src": "2968:9:17" + }, + { + "name": "offset", + "nativeSrc": "2979:6:17", + "nodeType": "YulIdentifier", + "src": "2979:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "2964:3:17", + "nodeType": "YulIdentifier", + "src": "2964:3:17" + }, + "nativeSrc": "2964:22:17", + "nodeType": "YulFunctionCall", + "src": "2964:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "2988:7:17", + "nodeType": "YulIdentifier", + "src": "2988:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_uint256", + "nativeSrc": "2943:20:17", + "nodeType": "YulIdentifier", + "src": "2943:20:17" + }, + "nativeSrc": "2943:53:17", + "nodeType": "YulFunctionCall", + "src": "2943:53:17" + }, + "variableNames": [ + { + "name": "value1", + "nativeSrc": "2933:6:17", + "nodeType": "YulIdentifier", + "src": "2933:6:17" + } + ] + } + ] + } + ] + }, + "name": "abi_decode_tuple_t_addresst_uint256", + "nativeSrc": "2539:474:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "2584:9:17", + "nodeType": "YulTypedName", + "src": "2584:9:17", + "type": "" + }, + { + "name": "dataEnd", + "nativeSrc": "2595:7:17", + "nodeType": "YulTypedName", + "src": "2595:7:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value0", + "nativeSrc": "2607:6:17", + "nodeType": "YulTypedName", + "src": "2607:6:17", + "type": "" + }, + { + "name": "value1", + "nativeSrc": "2615:6:17", + "nodeType": "YulTypedName", + "src": "2615:6:17", + "type": "" + } + ], + "src": "2539:474:17" + }, + { + "body": { + "nativeSrc": "3061:48:17", + "nodeType": "YulBlock", + "src": "3061:48:17", + "statements": [ + { + "nativeSrc": "3071:32:17", + "nodeType": "YulAssignment", + "src": "3071:32:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "value", + "nativeSrc": "3096:5:17", + "nodeType": "YulIdentifier", + "src": "3096:5:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "3089:6:17", + "nodeType": "YulIdentifier", + "src": "3089:6:17" + }, + "nativeSrc": "3089:13:17", + "nodeType": "YulFunctionCall", + "src": "3089:13:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "3082:6:17", + "nodeType": "YulIdentifier", + "src": "3082:6:17" + }, + "nativeSrc": "3082:21:17", + "nodeType": "YulFunctionCall", + "src": "3082:21:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "3071:7:17", + "nodeType": "YulIdentifier", + "src": "3071:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_bool", + "nativeSrc": "3019:90:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "3043:5:17", + "nodeType": "YulTypedName", + "src": "3043:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "3053:7:17", + "nodeType": "YulTypedName", + "src": "3053:7:17", + "type": "" + } + ], + "src": "3019:90:17" + }, + { + "body": { + "nativeSrc": "3174:50:17", + "nodeType": "YulBlock", + "src": "3174:50:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "3191:3:17", + "nodeType": "YulIdentifier", + "src": "3191:3:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "3211:5:17", + "nodeType": "YulIdentifier", + "src": "3211:5:17" + } + ], + "functionName": { + "name": "cleanup_t_bool", + "nativeSrc": "3196:14:17", + "nodeType": "YulIdentifier", + "src": "3196:14:17" + }, + "nativeSrc": "3196:21:17", + "nodeType": "YulFunctionCall", + "src": "3196:21:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "3184:6:17", + "nodeType": "YulIdentifier", + "src": "3184:6:17" + }, + "nativeSrc": "3184:34:17", + "nodeType": "YulFunctionCall", + "src": "3184:34:17" + }, + "nativeSrc": "3184:34:17", + "nodeType": "YulExpressionStatement", + "src": "3184:34:17" + } + ] + }, + "name": "abi_encode_t_bool_to_t_bool_fromStack", + "nativeSrc": "3115:109:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "3162:5:17", + "nodeType": "YulTypedName", + "src": "3162:5:17", + "type": "" + }, + { + "name": "pos", + "nativeSrc": "3169:3:17", + "nodeType": "YulTypedName", + "src": "3169:3:17", + "type": "" + } + ], + "src": "3115:109:17" + }, + { + "body": { + "nativeSrc": "3322:118:17", + "nodeType": "YulBlock", + "src": "3322:118:17", + "statements": [ + { + "nativeSrc": "3332:26:17", + "nodeType": "YulAssignment", + "src": "3332:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "3344:9:17", + "nodeType": "YulIdentifier", + "src": "3344:9:17" + }, + { + "kind": "number", + "nativeSrc": "3355:2:17", + "nodeType": "YulLiteral", + "src": "3355:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "3340:3:17", + "nodeType": "YulIdentifier", + "src": "3340:3:17" + }, + "nativeSrc": "3340:18:17", + "nodeType": "YulFunctionCall", + "src": "3340:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "3332:4:17", + "nodeType": "YulIdentifier", + "src": "3332:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value0", + "nativeSrc": "3406:6:17", + "nodeType": "YulIdentifier", + "src": "3406:6:17" + }, + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "3419:9:17", + "nodeType": "YulIdentifier", + "src": "3419:9:17" + }, + { + "kind": "number", + "nativeSrc": "3430:1:17", + "nodeType": "YulLiteral", + "src": "3430:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "3415:3:17", + "nodeType": "YulIdentifier", + "src": "3415:3:17" + }, + "nativeSrc": "3415:17:17", + "nodeType": "YulFunctionCall", + "src": "3415:17:17" + } + ], + "functionName": { + "name": "abi_encode_t_bool_to_t_bool_fromStack", + "nativeSrc": "3368:37:17", + "nodeType": "YulIdentifier", + "src": "3368:37:17" + }, + "nativeSrc": "3368:65:17", + "nodeType": "YulFunctionCall", + "src": "3368:65:17" + }, + "nativeSrc": "3368:65:17", + "nodeType": "YulExpressionStatement", + "src": "3368:65:17" + } + ] + }, + "name": "abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed", + "nativeSrc": "3230:210:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "3294:9:17", + "nodeType": "YulTypedName", + "src": "3294:9:17", + "type": "" + }, + { + "name": "value0", + "nativeSrc": "3306:6:17", + "nodeType": "YulTypedName", + "src": "3306:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "3317:4:17", + "nodeType": "YulTypedName", + "src": "3317:4:17", + "type": "" + } + ], + "src": "3230:210:17" + }, + { + "body": { + "nativeSrc": "3511:53:17", + "nodeType": "YulBlock", + "src": "3511:53:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "3528:3:17", + "nodeType": "YulIdentifier", + "src": "3528:3:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "3551:5:17", + "nodeType": "YulIdentifier", + "src": "3551:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "3533:17:17", + "nodeType": "YulIdentifier", + "src": "3533:17:17" + }, + "nativeSrc": "3533:24:17", + "nodeType": "YulFunctionCall", + "src": "3533:24:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "3521:6:17", + "nodeType": "YulIdentifier", + "src": "3521:6:17" + }, + "nativeSrc": "3521:37:17", + "nodeType": "YulFunctionCall", + "src": "3521:37:17" + }, + "nativeSrc": "3521:37:17", + "nodeType": "YulExpressionStatement", + "src": "3521:37:17" + } + ] + }, + "name": "abi_encode_t_uint256_to_t_uint256_fromStack", + "nativeSrc": "3446:118:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "3499:5:17", + "nodeType": "YulTypedName", + "src": "3499:5:17", + "type": "" + }, + { + "name": "pos", + "nativeSrc": "3506:3:17", + "nodeType": "YulTypedName", + "src": "3506:3:17", + "type": "" + } + ], + "src": "3446:118:17" + }, + { + "body": { + "nativeSrc": "3668:124:17", + "nodeType": "YulBlock", + "src": "3668:124:17", + "statements": [ + { + "nativeSrc": "3678:26:17", + "nodeType": "YulAssignment", + "src": "3678:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "3690:9:17", + "nodeType": "YulIdentifier", + "src": "3690:9:17" + }, + { + "kind": "number", + "nativeSrc": "3701:2:17", + "nodeType": "YulLiteral", + "src": "3701:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "3686:3:17", + "nodeType": "YulIdentifier", + "src": "3686:3:17" + }, + "nativeSrc": "3686:18:17", + "nodeType": "YulFunctionCall", + "src": "3686:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "3678:4:17", + "nodeType": "YulIdentifier", + "src": "3678:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value0", + "nativeSrc": "3758:6:17", + "nodeType": "YulIdentifier", + "src": "3758:6:17" + }, + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "3771:9:17", + "nodeType": "YulIdentifier", + "src": "3771:9:17" + }, + { + "kind": "number", + "nativeSrc": "3782:1:17", + "nodeType": "YulLiteral", + "src": "3782:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "3767:3:17", + "nodeType": "YulIdentifier", + "src": "3767:3:17" + }, + "nativeSrc": "3767:17:17", + "nodeType": "YulFunctionCall", + "src": "3767:17:17" + } + ], + "functionName": { + "name": "abi_encode_t_uint256_to_t_uint256_fromStack", + "nativeSrc": "3714:43:17", + "nodeType": "YulIdentifier", + "src": "3714:43:17" + }, + "nativeSrc": "3714:71:17", + "nodeType": "YulFunctionCall", + "src": "3714:71:17" + }, + "nativeSrc": "3714:71:17", + "nodeType": "YulExpressionStatement", + "src": "3714:71:17" + } + ] + }, + "name": "abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed", + "nativeSrc": "3570:222:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "3640:9:17", + "nodeType": "YulTypedName", + "src": "3640:9:17", + "type": "" + }, + { + "name": "value0", + "nativeSrc": "3652:6:17", + "nodeType": "YulTypedName", + "src": "3652:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "3663:4:17", + "nodeType": "YulTypedName", + "src": "3663:4:17", + "type": "" + } + ], + "src": "3570:222:17" + }, + { + "body": { + "nativeSrc": "3898:519:17", + "nodeType": "YulBlock", + "src": "3898:519:17", + "statements": [ + { + "body": { + "nativeSrc": "3944:83:17", + "nodeType": "YulBlock", + "src": "3944:83:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nativeSrc": "3946:77:17", + "nodeType": "YulIdentifier", + "src": "3946:77:17" + }, + "nativeSrc": "3946:79:17", + "nodeType": "YulFunctionCall", + "src": "3946:79:17" + }, + "nativeSrc": "3946:79:17", + "nodeType": "YulExpressionStatement", + "src": "3946:79:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "dataEnd", + "nativeSrc": "3919:7:17", + "nodeType": "YulIdentifier", + "src": "3919:7:17" + }, + { + "name": "headStart", + "nativeSrc": "3928:9:17", + "nodeType": "YulIdentifier", + "src": "3928:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "3915:3:17", + "nodeType": "YulIdentifier", + "src": "3915:3:17" + }, + "nativeSrc": "3915:23:17", + "nodeType": "YulFunctionCall", + "src": "3915:23:17" + }, + { + "kind": "number", + "nativeSrc": "3940:2:17", + "nodeType": "YulLiteral", + "src": "3940:2:17", + "type": "", + "value": "96" + } + ], + "functionName": { + "name": "slt", + "nativeSrc": "3911:3:17", + "nodeType": "YulIdentifier", + "src": "3911:3:17" + }, + "nativeSrc": "3911:32:17", + "nodeType": "YulFunctionCall", + "src": "3911:32:17" + }, + "nativeSrc": "3908:119:17", + "nodeType": "YulIf", + "src": "3908:119:17" + }, + { + "nativeSrc": "4037:117:17", + "nodeType": "YulBlock", + "src": "4037:117:17", + "statements": [ + { + "nativeSrc": "4052:15:17", + "nodeType": "YulVariableDeclaration", + "src": "4052:15:17", + "value": { + "kind": "number", + "nativeSrc": "4066:1:17", + "nodeType": "YulLiteral", + "src": "4066:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "4056:6:17", + "nodeType": "YulTypedName", + "src": "4056:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4081:63:17", + "nodeType": "YulAssignment", + "src": "4081:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "4116:9:17", + "nodeType": "YulIdentifier", + "src": "4116:9:17" + }, + { + "name": "offset", + "nativeSrc": "4127:6:17", + "nodeType": "YulIdentifier", + "src": "4127:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4112:3:17", + "nodeType": "YulIdentifier", + "src": "4112:3:17" + }, + "nativeSrc": "4112:22:17", + "nodeType": "YulFunctionCall", + "src": "4112:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "4136:7:17", + "nodeType": "YulIdentifier", + "src": "4136:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "4091:20:17", + "nodeType": "YulIdentifier", + "src": "4091:20:17" + }, + "nativeSrc": "4091:53:17", + "nodeType": "YulFunctionCall", + "src": "4091:53:17" + }, + "variableNames": [ + { + "name": "value0", + "nativeSrc": "4081:6:17", + "nodeType": "YulIdentifier", + "src": "4081:6:17" + } + ] + } + ] + }, + { + "nativeSrc": "4164:118:17", + "nodeType": "YulBlock", + "src": "4164:118:17", + "statements": [ + { + "nativeSrc": "4179:16:17", + "nodeType": "YulVariableDeclaration", + "src": "4179:16:17", + "value": { + "kind": "number", + "nativeSrc": "4193:2:17", + "nodeType": "YulLiteral", + "src": "4193:2:17", + "type": "", + "value": "32" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "4183:6:17", + "nodeType": "YulTypedName", + "src": "4183:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4209:63:17", + "nodeType": "YulAssignment", + "src": "4209:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "4244:9:17", + "nodeType": "YulIdentifier", + "src": "4244:9:17" + }, + { + "name": "offset", + "nativeSrc": "4255:6:17", + "nodeType": "YulIdentifier", + "src": "4255:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4240:3:17", + "nodeType": "YulIdentifier", + "src": "4240:3:17" + }, + "nativeSrc": "4240:22:17", + "nodeType": "YulFunctionCall", + "src": "4240:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "4264:7:17", + "nodeType": "YulIdentifier", + "src": "4264:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "4219:20:17", + "nodeType": "YulIdentifier", + "src": "4219:20:17" + }, + "nativeSrc": "4219:53:17", + "nodeType": "YulFunctionCall", + "src": "4219:53:17" + }, + "variableNames": [ + { + "name": "value1", + "nativeSrc": "4209:6:17", + "nodeType": "YulIdentifier", + "src": "4209:6:17" + } + ] + } + ] + }, + { + "nativeSrc": "4292:118:17", + "nodeType": "YulBlock", + "src": "4292:118:17", + "statements": [ + { + "nativeSrc": "4307:16:17", + "nodeType": "YulVariableDeclaration", + "src": "4307:16:17", + "value": { + "kind": "number", + "nativeSrc": "4321:2:17", + "nodeType": "YulLiteral", + "src": "4321:2:17", + "type": "", + "value": "64" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "4311:6:17", + "nodeType": "YulTypedName", + "src": "4311:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "4337:63:17", + "nodeType": "YulAssignment", + "src": "4337:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "4372:9:17", + "nodeType": "YulIdentifier", + "src": "4372:9:17" + }, + { + "name": "offset", + "nativeSrc": "4383:6:17", + "nodeType": "YulIdentifier", + "src": "4383:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4368:3:17", + "nodeType": "YulIdentifier", + "src": "4368:3:17" + }, + "nativeSrc": "4368:22:17", + "nodeType": "YulFunctionCall", + "src": "4368:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "4392:7:17", + "nodeType": "YulIdentifier", + "src": "4392:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_uint256", + "nativeSrc": "4347:20:17", + "nodeType": "YulIdentifier", + "src": "4347:20:17" + }, + "nativeSrc": "4347:53:17", + "nodeType": "YulFunctionCall", + "src": "4347:53:17" + }, + "variableNames": [ + { + "name": "value2", + "nativeSrc": "4337:6:17", + "nodeType": "YulIdentifier", + "src": "4337:6:17" + } + ] + } + ] + } + ] + }, + "name": "abi_decode_tuple_t_addresst_addresst_uint256", + "nativeSrc": "3798:619:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "3852:9:17", + "nodeType": "YulTypedName", + "src": "3852:9:17", + "type": "" + }, + { + "name": "dataEnd", + "nativeSrc": "3863:7:17", + "nodeType": "YulTypedName", + "src": "3863:7:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value0", + "nativeSrc": "3875:6:17", + "nodeType": "YulTypedName", + "src": "3875:6:17", + "type": "" + }, + { + "name": "value1", + "nativeSrc": "3883:6:17", + "nodeType": "YulTypedName", + "src": "3883:6:17", + "type": "" + }, + { + "name": "value2", + "nativeSrc": "3891:6:17", + "nodeType": "YulTypedName", + "src": "3891:6:17", + "type": "" + } + ], + "src": "3798:619:17" + }, + { + "body": { + "nativeSrc": "4466:43:17", + "nodeType": "YulBlock", + "src": "4466:43:17", + "statements": [ + { + "nativeSrc": "4476:27:17", + "nodeType": "YulAssignment", + "src": "4476:27:17", + "value": { + "arguments": [ + { + "name": "value", + "nativeSrc": "4491:5:17", + "nodeType": "YulIdentifier", + "src": "4491:5:17" + }, + { + "kind": "number", + "nativeSrc": "4498:4:17", + "nodeType": "YulLiteral", + "src": "4498:4:17", + "type": "", + "value": "0xff" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "4487:3:17", + "nodeType": "YulIdentifier", + "src": "4487:3:17" + }, + "nativeSrc": "4487:16:17", + "nodeType": "YulFunctionCall", + "src": "4487:16:17" + }, + "variableNames": [ + { + "name": "cleaned", + "nativeSrc": "4476:7:17", + "nodeType": "YulIdentifier", + "src": "4476:7:17" + } + ] + } + ] + }, + "name": "cleanup_t_uint8", + "nativeSrc": "4423:86:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "4448:5:17", + "nodeType": "YulTypedName", + "src": "4448:5:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "cleaned", + "nativeSrc": "4458:7:17", + "nodeType": "YulTypedName", + "src": "4458:7:17", + "type": "" + } + ], + "src": "4423:86:17" + }, + { + "body": { + "nativeSrc": "4576:51:17", + "nodeType": "YulBlock", + "src": "4576:51:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "4593:3:17", + "nodeType": "YulIdentifier", + "src": "4593:3:17" + }, + { + "arguments": [ + { + "name": "value", + "nativeSrc": "4614:5:17", + "nodeType": "YulIdentifier", + "src": "4614:5:17" + } + ], + "functionName": { + "name": "cleanup_t_uint8", + "nativeSrc": "4598:15:17", + "nodeType": "YulIdentifier", + "src": "4598:15:17" + }, + "nativeSrc": "4598:22:17", + "nodeType": "YulFunctionCall", + "src": "4598:22:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "4586:6:17", + "nodeType": "YulIdentifier", + "src": "4586:6:17" + }, + "nativeSrc": "4586:35:17", + "nodeType": "YulFunctionCall", + "src": "4586:35:17" + }, + "nativeSrc": "4586:35:17", + "nodeType": "YulExpressionStatement", + "src": "4586:35:17" + } + ] + }, + "name": "abi_encode_t_uint8_to_t_uint8_fromStack", + "nativeSrc": "4515:112:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "value", + "nativeSrc": "4564:5:17", + "nodeType": "YulTypedName", + "src": "4564:5:17", + "type": "" + }, + { + "name": "pos", + "nativeSrc": "4571:3:17", + "nodeType": "YulTypedName", + "src": "4571:3:17", + "type": "" + } + ], + "src": "4515:112:17" + }, + { + "body": { + "nativeSrc": "4727:120:17", + "nodeType": "YulBlock", + "src": "4727:120:17", + "statements": [ + { + "nativeSrc": "4737:26:17", + "nodeType": "YulAssignment", + "src": "4737:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "4749:9:17", + "nodeType": "YulIdentifier", + "src": "4749:9:17" + }, + { + "kind": "number", + "nativeSrc": "4760:2:17", + "nodeType": "YulLiteral", + "src": "4760:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4745:3:17", + "nodeType": "YulIdentifier", + "src": "4745:3:17" + }, + "nativeSrc": "4745:18:17", + "nodeType": "YulFunctionCall", + "src": "4745:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "4737:4:17", + "nodeType": "YulIdentifier", + "src": "4737:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "value0", + "nativeSrc": "4813:6:17", + "nodeType": "YulIdentifier", + "src": "4813:6:17" + }, + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "4826:9:17", + "nodeType": "YulIdentifier", + "src": "4826:9:17" + }, + { + "kind": "number", + "nativeSrc": "4837:1:17", + "nodeType": "YulLiteral", + "src": "4837:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "4822:3:17", + "nodeType": "YulIdentifier", + "src": "4822:3:17" + }, + "nativeSrc": "4822:17:17", + "nodeType": "YulFunctionCall", + "src": "4822:17:17" + } + ], + "functionName": { + "name": "abi_encode_t_uint8_to_t_uint8_fromStack", + "nativeSrc": "4773:39:17", + "nodeType": "YulIdentifier", + "src": "4773:39:17" + }, + "nativeSrc": "4773:67:17", + "nodeType": "YulFunctionCall", + "src": "4773:67:17" + }, + "nativeSrc": "4773:67:17", + "nodeType": "YulExpressionStatement", + "src": "4773:67:17" + } + ] + }, + "name": "abi_encode_tuple_t_uint8__to_t_uint8__fromStack_reversed", + "nativeSrc": "4633:214:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "4699:9:17", + "nodeType": "YulTypedName", + "src": "4699:9:17", + "type": "" + }, + { + "name": "value0", + "nativeSrc": "4711:6:17", + "nodeType": "YulTypedName", + "src": "4711:6:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "4722:4:17", + "nodeType": "YulTypedName", + "src": "4722:4:17", + "type": "" + } + ], + "src": "4633:214:17" + }, + { + "body": { + "nativeSrc": "4919:263:17", + "nodeType": "YulBlock", + "src": "4919:263:17", + "statements": [ + { + "body": { + "nativeSrc": "4965:83:17", + "nodeType": "YulBlock", + "src": "4965:83:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nativeSrc": "4967:77:17", + "nodeType": "YulIdentifier", + "src": "4967:77:17" + }, + "nativeSrc": "4967:79:17", + "nodeType": "YulFunctionCall", + "src": "4967:79:17" + }, + "nativeSrc": "4967:79:17", + "nodeType": "YulExpressionStatement", + "src": "4967:79:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "dataEnd", + "nativeSrc": "4940:7:17", + "nodeType": "YulIdentifier", + "src": "4940:7:17" + }, + { + "name": "headStart", + "nativeSrc": "4949:9:17", + "nodeType": "YulIdentifier", + "src": "4949:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "4936:3:17", + "nodeType": "YulIdentifier", + "src": "4936:3:17" + }, + "nativeSrc": "4936:23:17", + "nodeType": "YulFunctionCall", + "src": "4936:23:17" + }, + { + "kind": "number", + "nativeSrc": "4961:2:17", + "nodeType": "YulLiteral", + "src": "4961:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "slt", + "nativeSrc": "4932:3:17", + "nodeType": "YulIdentifier", + "src": "4932:3:17" + }, + "nativeSrc": "4932:32:17", + "nodeType": "YulFunctionCall", + "src": "4932:32:17" + }, + "nativeSrc": "4929:119:17", + "nodeType": "YulIf", + "src": "4929:119:17" + }, + { + "nativeSrc": "5058:117:17", + "nodeType": "YulBlock", + "src": "5058:117:17", + "statements": [ + { + "nativeSrc": "5073:15:17", + "nodeType": "YulVariableDeclaration", + "src": "5073:15:17", + "value": { + "kind": "number", + "nativeSrc": "5087:1:17", + "nodeType": "YulLiteral", + "src": "5087:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "5077:6:17", + "nodeType": "YulTypedName", + "src": "5077:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "5102:63:17", + "nodeType": "YulAssignment", + "src": "5102:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "5137:9:17", + "nodeType": "YulIdentifier", + "src": "5137:9:17" + }, + { + "name": "offset", + "nativeSrc": "5148:6:17", + "nodeType": "YulIdentifier", + "src": "5148:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5133:3:17", + "nodeType": "YulIdentifier", + "src": "5133:3:17" + }, + "nativeSrc": "5133:22:17", + "nodeType": "YulFunctionCall", + "src": "5133:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "5157:7:17", + "nodeType": "YulIdentifier", + "src": "5157:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "5112:20:17", + "nodeType": "YulIdentifier", + "src": "5112:20:17" + }, + "nativeSrc": "5112:53:17", + "nodeType": "YulFunctionCall", + "src": "5112:53:17" + }, + "variableNames": [ + { + "name": "value0", + "nativeSrc": "5102:6:17", + "nodeType": "YulIdentifier", + "src": "5102:6:17" + } + ] + } + ] + } + ] + }, + "name": "abi_decode_tuple_t_address", + "nativeSrc": "4853:329:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "4889:9:17", + "nodeType": "YulTypedName", + "src": "4889:9:17", + "type": "" + }, + { + "name": "dataEnd", + "nativeSrc": "4900:7:17", + "nodeType": "YulTypedName", + "src": "4900:7:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value0", + "nativeSrc": "4912:6:17", + "nodeType": "YulTypedName", + "src": "4912:6:17", + "type": "" + } + ], + "src": "4853:329:17" + }, + { + "body": { + "nativeSrc": "5271:391:17", + "nodeType": "YulBlock", + "src": "5271:391:17", + "statements": [ + { + "body": { + "nativeSrc": "5317:83:17", + "nodeType": "YulBlock", + "src": "5317:83:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nativeSrc": "5319:77:17", + "nodeType": "YulIdentifier", + "src": "5319:77:17" + }, + "nativeSrc": "5319:79:17", + "nodeType": "YulFunctionCall", + "src": "5319:79:17" + }, + "nativeSrc": "5319:79:17", + "nodeType": "YulExpressionStatement", + "src": "5319:79:17" + } + ] + }, + "condition": { + "arguments": [ + { + "arguments": [ + { + "name": "dataEnd", + "nativeSrc": "5292:7:17", + "nodeType": "YulIdentifier", + "src": "5292:7:17" + }, + { + "name": "headStart", + "nativeSrc": "5301:9:17", + "nodeType": "YulIdentifier", + "src": "5301:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "5288:3:17", + "nodeType": "YulIdentifier", + "src": "5288:3:17" + }, + "nativeSrc": "5288:23:17", + "nodeType": "YulFunctionCall", + "src": "5288:23:17" + }, + { + "kind": "number", + "nativeSrc": "5313:2:17", + "nodeType": "YulLiteral", + "src": "5313:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "slt", + "nativeSrc": "5284:3:17", + "nodeType": "YulIdentifier", + "src": "5284:3:17" + }, + "nativeSrc": "5284:32:17", + "nodeType": "YulFunctionCall", + "src": "5284:32:17" + }, + "nativeSrc": "5281:119:17", + "nodeType": "YulIf", + "src": "5281:119:17" + }, + { + "nativeSrc": "5410:117:17", + "nodeType": "YulBlock", + "src": "5410:117:17", + "statements": [ + { + "nativeSrc": "5425:15:17", + "nodeType": "YulVariableDeclaration", + "src": "5425:15:17", + "value": { + "kind": "number", + "nativeSrc": "5439:1:17", + "nodeType": "YulLiteral", + "src": "5439:1:17", + "type": "", + "value": "0" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "5429:6:17", + "nodeType": "YulTypedName", + "src": "5429:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "5454:63:17", + "nodeType": "YulAssignment", + "src": "5454:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "5489:9:17", + "nodeType": "YulIdentifier", + "src": "5489:9:17" + }, + { + "name": "offset", + "nativeSrc": "5500:6:17", + "nodeType": "YulIdentifier", + "src": "5500:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5485:3:17", + "nodeType": "YulIdentifier", + "src": "5485:3:17" + }, + "nativeSrc": "5485:22:17", + "nodeType": "YulFunctionCall", + "src": "5485:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "5509:7:17", + "nodeType": "YulIdentifier", + "src": "5509:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "5464:20:17", + "nodeType": "YulIdentifier", + "src": "5464:20:17" + }, + "nativeSrc": "5464:53:17", + "nodeType": "YulFunctionCall", + "src": "5464:53:17" + }, + "variableNames": [ + { + "name": "value0", + "nativeSrc": "5454:6:17", + "nodeType": "YulIdentifier", + "src": "5454:6:17" + } + ] + } + ] + }, + { + "nativeSrc": "5537:118:17", + "nodeType": "YulBlock", + "src": "5537:118:17", + "statements": [ + { + "nativeSrc": "5552:16:17", + "nodeType": "YulVariableDeclaration", + "src": "5552:16:17", + "value": { + "kind": "number", + "nativeSrc": "5566:2:17", + "nodeType": "YulLiteral", + "src": "5566:2:17", + "type": "", + "value": "32" + }, + "variables": [ + { + "name": "offset", + "nativeSrc": "5556:6:17", + "nodeType": "YulTypedName", + "src": "5556:6:17", + "type": "" + } + ] + }, + { + "nativeSrc": "5582:63:17", + "nodeType": "YulAssignment", + "src": "5582:63:17", + "value": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "5617:9:17", + "nodeType": "YulIdentifier", + "src": "5617:9:17" + }, + { + "name": "offset", + "nativeSrc": "5628:6:17", + "nodeType": "YulIdentifier", + "src": "5628:6:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "5613:3:17", + "nodeType": "YulIdentifier", + "src": "5613:3:17" + }, + "nativeSrc": "5613:22:17", + "nodeType": "YulFunctionCall", + "src": "5613:22:17" + }, + { + "name": "dataEnd", + "nativeSrc": "5637:7:17", + "nodeType": "YulIdentifier", + "src": "5637:7:17" + } + ], + "functionName": { + "name": "abi_decode_t_address", + "nativeSrc": "5592:20:17", + "nodeType": "YulIdentifier", + "src": "5592:20:17" + }, + "nativeSrc": "5592:53:17", + "nodeType": "YulFunctionCall", + "src": "5592:53:17" + }, + "variableNames": [ + { + "name": "value1", + "nativeSrc": "5582:6:17", + "nodeType": "YulIdentifier", + "src": "5582:6:17" + } + ] + } + ] + } + ] + }, + "name": "abi_decode_tuple_t_addresst_address", + "nativeSrc": "5188:474:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "5233:9:17", + "nodeType": "YulTypedName", + "src": "5233:9:17", + "type": "" + }, + { + "name": "dataEnd", + "nativeSrc": "5244:7:17", + "nodeType": "YulTypedName", + "src": "5244:7:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "value0", + "nativeSrc": "5256:6:17", + "nodeType": "YulTypedName", + "src": "5256:6:17", + "type": "" + }, + { + "name": "value1", + "nativeSrc": "5264:6:17", + "nodeType": "YulTypedName", + "src": "5264:6:17", + "type": "" + } + ], + "src": "5188:474:17" + }, + { + "body": { + "nativeSrc": "5696:152:17", + "nodeType": "YulBlock", + "src": "5696:152:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "5713:1:17", + "nodeType": "YulLiteral", + "src": "5713:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "5716:77:17", + "nodeType": "YulLiteral", + "src": "5716:77:17", + "type": "", + "value": "35408467139433450592217433187231851964531694900788300625387963629091585785856" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "5706:6:17", + "nodeType": "YulIdentifier", + "src": "5706:6:17" + }, + "nativeSrc": "5706:88:17", + "nodeType": "YulFunctionCall", + "src": "5706:88:17" + }, + "nativeSrc": "5706:88:17", + "nodeType": "YulExpressionStatement", + "src": "5706:88:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "5810:1:17", + "nodeType": "YulLiteral", + "src": "5810:1:17", + "type": "", + "value": "4" + }, + { + "kind": "number", + "nativeSrc": "5813:4:17", + "nodeType": "YulLiteral", + "src": "5813:4:17", + "type": "", + "value": "0x22" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "5803:6:17", + "nodeType": "YulIdentifier", + "src": "5803:6:17" + }, + "nativeSrc": "5803:15:17", + "nodeType": "YulFunctionCall", + "src": "5803:15:17" + }, + "nativeSrc": "5803:15:17", + "nodeType": "YulExpressionStatement", + "src": "5803:15:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "5834:1:17", + "nodeType": "YulLiteral", + "src": "5834:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "5837:4:17", + "nodeType": "YulLiteral", + "src": "5837:4:17", + "type": "", + "value": "0x24" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "5827:6:17", + "nodeType": "YulIdentifier", + "src": "5827:6:17" + }, + "nativeSrc": "5827:15:17", + "nodeType": "YulFunctionCall", + "src": "5827:15:17" + }, + "nativeSrc": "5827:15:17", + "nodeType": "YulExpressionStatement", + "src": "5827:15:17" + } + ] + }, + "name": "panic_error_0x22", + "nativeSrc": "5668:180:17", + "nodeType": "YulFunctionDefinition", + "src": "5668:180:17" + }, + { + "body": { + "nativeSrc": "5905:269:17", + "nodeType": "YulBlock", + "src": "5905:269:17", + "statements": [ + { + "nativeSrc": "5915:22:17", + "nodeType": "YulAssignment", + "src": "5915:22:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "5929:4:17", + "nodeType": "YulIdentifier", + "src": "5929:4:17" + }, + { + "kind": "number", + "nativeSrc": "5935:1:17", + "nodeType": "YulLiteral", + "src": "5935:1:17", + "type": "", + "value": "2" + } + ], + "functionName": { + "name": "div", + "nativeSrc": "5925:3:17", + "nodeType": "YulIdentifier", + "src": "5925:3:17" + }, + "nativeSrc": "5925:12:17", + "nodeType": "YulFunctionCall", + "src": "5925:12:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "5915:6:17", + "nodeType": "YulIdentifier", + "src": "5915:6:17" + } + ] + }, + { + "nativeSrc": "5946:38:17", + "nodeType": "YulVariableDeclaration", + "src": "5946:38:17", + "value": { + "arguments": [ + { + "name": "data", + "nativeSrc": "5976:4:17", + "nodeType": "YulIdentifier", + "src": "5976:4:17" + }, + { + "kind": "number", + "nativeSrc": "5982:1:17", + "nodeType": "YulLiteral", + "src": "5982:1:17", + "type": "", + "value": "1" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "5972:3:17", + "nodeType": "YulIdentifier", + "src": "5972:3:17" + }, + "nativeSrc": "5972:12:17", + "nodeType": "YulFunctionCall", + "src": "5972:12:17" + }, + "variables": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "5950:18:17", + "nodeType": "YulTypedName", + "src": "5950:18:17", + "type": "" + } + ] + }, + { + "body": { + "nativeSrc": "6023:51:17", + "nodeType": "YulBlock", + "src": "6023:51:17", + "statements": [ + { + "nativeSrc": "6037:27:17", + "nodeType": "YulAssignment", + "src": "6037:27:17", + "value": { + "arguments": [ + { + "name": "length", + "nativeSrc": "6051:6:17", + "nodeType": "YulIdentifier", + "src": "6051:6:17" + }, + { + "kind": "number", + "nativeSrc": "6059:4:17", + "nodeType": "YulLiteral", + "src": "6059:4:17", + "type": "", + "value": "0x7f" + } + ], + "functionName": { + "name": "and", + "nativeSrc": "6047:3:17", + "nodeType": "YulIdentifier", + "src": "6047:3:17" + }, + "nativeSrc": "6047:17:17", + "nodeType": "YulFunctionCall", + "src": "6047:17:17" + }, + "variableNames": [ + { + "name": "length", + "nativeSrc": "6037:6:17", + "nodeType": "YulIdentifier", + "src": "6037:6:17" + } + ] + } + ] + }, + "condition": { + "arguments": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "6003:18:17", + "nodeType": "YulIdentifier", + "src": "6003:18:17" + } + ], + "functionName": { + "name": "iszero", + "nativeSrc": "5996:6:17", + "nodeType": "YulIdentifier", + "src": "5996:6:17" + }, + "nativeSrc": "5996:26:17", + "nodeType": "YulFunctionCall", + "src": "5996:26:17" + }, + "nativeSrc": "5993:81:17", + "nodeType": "YulIf", + "src": "5993:81:17" + }, + { + "body": { + "nativeSrc": "6126:42:17", + "nodeType": "YulBlock", + "src": "6126:42:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "panic_error_0x22", + "nativeSrc": "6140:16:17", + "nodeType": "YulIdentifier", + "src": "6140:16:17" + }, + "nativeSrc": "6140:18:17", + "nodeType": "YulFunctionCall", + "src": "6140:18:17" + }, + "nativeSrc": "6140:18:17", + "nodeType": "YulExpressionStatement", + "src": "6140:18:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "outOfPlaceEncoding", + "nativeSrc": "6090:18:17", + "nodeType": "YulIdentifier", + "src": "6090:18:17" + }, + { + "arguments": [ + { + "name": "length", + "nativeSrc": "6113:6:17", + "nodeType": "YulIdentifier", + "src": "6113:6:17" + }, + { + "kind": "number", + "nativeSrc": "6121:2:17", + "nodeType": "YulLiteral", + "src": "6121:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "lt", + "nativeSrc": "6110:2:17", + "nodeType": "YulIdentifier", + "src": "6110:2:17" + }, + "nativeSrc": "6110:14:17", + "nodeType": "YulFunctionCall", + "src": "6110:14:17" + } + ], + "functionName": { + "name": "eq", + "nativeSrc": "6087:2:17", + "nodeType": "YulIdentifier", + "src": "6087:2:17" + }, + "nativeSrc": "6087:38:17", + "nodeType": "YulFunctionCall", + "src": "6087:38:17" + }, + "nativeSrc": "6084:84:17", + "nodeType": "YulIf", + "src": "6084:84:17" + } + ] + }, + "name": "extract_byte_array_length", + "nativeSrc": "5854:320:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "data", + "nativeSrc": "5889:4:17", + "nodeType": "YulTypedName", + "src": "5889:4:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "length", + "nativeSrc": "5898:6:17", + "nodeType": "YulTypedName", + "src": "5898:6:17", + "type": "" + } + ], + "src": "5854:320:17" + }, + { + "body": { + "nativeSrc": "6208:152:17", + "nodeType": "YulBlock", + "src": "6208:152:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6225:1:17", + "nodeType": "YulLiteral", + "src": "6225:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "6228:77:17", + "nodeType": "YulLiteral", + "src": "6228:77:17", + "type": "", + "value": "35408467139433450592217433187231851964531694900788300625387963629091585785856" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6218:6:17", + "nodeType": "YulIdentifier", + "src": "6218:6:17" + }, + "nativeSrc": "6218:88:17", + "nodeType": "YulFunctionCall", + "src": "6218:88:17" + }, + "nativeSrc": "6218:88:17", + "nodeType": "YulExpressionStatement", + "src": "6218:88:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6322:1:17", + "nodeType": "YulLiteral", + "src": "6322:1:17", + "type": "", + "value": "4" + }, + { + "kind": "number", + "nativeSrc": "6325:4:17", + "nodeType": "YulLiteral", + "src": "6325:4:17", + "type": "", + "value": "0x11" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6315:6:17", + "nodeType": "YulIdentifier", + "src": "6315:6:17" + }, + "nativeSrc": "6315:15:17", + "nodeType": "YulFunctionCall", + "src": "6315:15:17" + }, + "nativeSrc": "6315:15:17", + "nodeType": "YulExpressionStatement", + "src": "6315:15:17" + }, + { + "expression": { + "arguments": [ + { + "kind": "number", + "nativeSrc": "6346:1:17", + "nodeType": "YulLiteral", + "src": "6346:1:17", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nativeSrc": "6349:4:17", + "nodeType": "YulLiteral", + "src": "6349:4:17", + "type": "", + "value": "0x24" + } + ], + "functionName": { + "name": "revert", + "nativeSrc": "6339:6:17", + "nodeType": "YulIdentifier", + "src": "6339:6:17" + }, + "nativeSrc": "6339:15:17", + "nodeType": "YulFunctionCall", + "src": "6339:15:17" + }, + "nativeSrc": "6339:15:17", + "nodeType": "YulExpressionStatement", + "src": "6339:15:17" + } + ] + }, + "name": "panic_error_0x11", + "nativeSrc": "6180:180:17", + "nodeType": "YulFunctionDefinition", + "src": "6180:180:17" + }, + { + "body": { + "nativeSrc": "6410:147:17", + "nodeType": "YulBlock", + "src": "6410:147:17", + "statements": [ + { + "nativeSrc": "6420:25:17", + "nodeType": "YulAssignment", + "src": "6420:25:17", + "value": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6443:1:17", + "nodeType": "YulIdentifier", + "src": "6443:1:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "6425:17:17", + "nodeType": "YulIdentifier", + "src": "6425:17:17" + }, + "nativeSrc": "6425:20:17", + "nodeType": "YulFunctionCall", + "src": "6425:20:17" + }, + "variableNames": [ + { + "name": "x", + "nativeSrc": "6420:1:17", + "nodeType": "YulIdentifier", + "src": "6420:1:17" + } + ] + }, + { + "nativeSrc": "6454:25:17", + "nodeType": "YulAssignment", + "src": "6454:25:17", + "value": { + "arguments": [ + { + "name": "y", + "nativeSrc": "6477:1:17", + "nodeType": "YulIdentifier", + "src": "6477:1:17" + } + ], + "functionName": { + "name": "cleanup_t_uint256", + "nativeSrc": "6459:17:17", + "nodeType": "YulIdentifier", + "src": "6459:17:17" + }, + "nativeSrc": "6459:20:17", + "nodeType": "YulFunctionCall", + "src": "6459:20:17" + }, + "variableNames": [ + { + "name": "y", + "nativeSrc": "6454:1:17", + "nodeType": "YulIdentifier", + "src": "6454:1:17" + } + ] + }, + { + "nativeSrc": "6488:16:17", + "nodeType": "YulAssignment", + "src": "6488:16:17", + "value": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6499:1:17", + "nodeType": "YulIdentifier", + "src": "6499:1:17" + }, + { + "name": "y", + "nativeSrc": "6502:1:17", + "nodeType": "YulIdentifier", + "src": "6502:1:17" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6495:3:17", + "nodeType": "YulIdentifier", + "src": "6495:3:17" + }, + "nativeSrc": "6495:9:17", + "nodeType": "YulFunctionCall", + "src": "6495:9:17" + }, + "variableNames": [ + { + "name": "sum", + "nativeSrc": "6488:3:17", + "nodeType": "YulIdentifier", + "src": "6488:3:17" + } + ] + }, + { + "body": { + "nativeSrc": "6528:22:17", + "nodeType": "YulBlock", + "src": "6528:22:17", + "statements": [ + { + "expression": { + "arguments": [], + "functionName": { + "name": "panic_error_0x11", + "nativeSrc": "6530:16:17", + "nodeType": "YulIdentifier", + "src": "6530:16:17" + }, + "nativeSrc": "6530:18:17", + "nodeType": "YulFunctionCall", + "src": "6530:18:17" + }, + "nativeSrc": "6530:18:17", + "nodeType": "YulExpressionStatement", + "src": "6530:18:17" + } + ] + }, + "condition": { + "arguments": [ + { + "name": "x", + "nativeSrc": "6520:1:17", + "nodeType": "YulIdentifier", + "src": "6520:1:17" + }, + { + "name": "sum", + "nativeSrc": "6523:3:17", + "nodeType": "YulIdentifier", + "src": "6523:3:17" + } + ], + "functionName": { + "name": "gt", + "nativeSrc": "6517:2:17", + "nodeType": "YulIdentifier", + "src": "6517:2:17" + }, + "nativeSrc": "6517:10:17", + "nodeType": "YulFunctionCall", + "src": "6517:10:17" + }, + "nativeSrc": "6514:36:17", + "nodeType": "YulIf", + "src": "6514:36:17" + } + ] + }, + "name": "checked_add_t_uint256", + "nativeSrc": "6366:191:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "x", + "nativeSrc": "6397:1:17", + "nodeType": "YulTypedName", + "src": "6397:1:17", + "type": "" + }, + { + "name": "y", + "nativeSrc": "6400:1:17", + "nodeType": "YulTypedName", + "src": "6400:1:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "sum", + "nativeSrc": "6406:3:17", + "nodeType": "YulTypedName", + "src": "6406:3:17", + "type": "" + } + ], + "src": "6366:191:17" + }, + { + "body": { + "nativeSrc": "6669:118:17", + "nodeType": "YulBlock", + "src": "6669:118:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "6691:6:17", + "nodeType": "YulIdentifier", + "src": "6691:6:17" + }, + { + "kind": "number", + "nativeSrc": "6699:1:17", + "nodeType": "YulLiteral", + "src": "6699:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6687:3:17", + "nodeType": "YulIdentifier", + "src": "6687:3:17" + }, + "nativeSrc": "6687:14:17", + "nodeType": "YulFunctionCall", + "src": "6687:14:17" + }, + { + "hexValue": "45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77", + "kind": "string", + "nativeSrc": "6703:34:17", + "nodeType": "YulLiteral", + "src": "6703:34:17", + "type": "", + "value": "ERC20: decreased allowance below" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6680:6:17", + "nodeType": "YulIdentifier", + "src": "6680:6:17" + }, + "nativeSrc": "6680:58:17", + "nodeType": "YulFunctionCall", + "src": "6680:58:17" + }, + "nativeSrc": "6680:58:17", + "nodeType": "YulExpressionStatement", + "src": "6680:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "6759:6:17", + "nodeType": "YulIdentifier", + "src": "6759:6:17" + }, + { + "kind": "number", + "nativeSrc": "6767:2:17", + "nodeType": "YulLiteral", + "src": "6767:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "6755:3:17", + "nodeType": "YulIdentifier", + "src": "6755:3:17" + }, + "nativeSrc": "6755:15:17", + "nodeType": "YulFunctionCall", + "src": "6755:15:17" + }, + { + "hexValue": "207a65726f", + "kind": "string", + "nativeSrc": "6772:7:17", + "nodeType": "YulLiteral", + "src": "6772:7:17", + "type": "", + "value": " zero" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "6748:6:17", + "nodeType": "YulIdentifier", + "src": "6748:6:17" + }, + "nativeSrc": "6748:32:17", + "nodeType": "YulFunctionCall", + "src": "6748:32:17" + }, + "nativeSrc": "6748:32:17", + "nodeType": "YulExpressionStatement", + "src": "6748:32:17" + } + ] + }, + "name": "store_literal_in_memory_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8", + "nativeSrc": "6563:224:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "6661:6:17", + "nodeType": "YulTypedName", + "src": "6661:6:17", + "type": "" + } + ], + "src": "6563:224:17" + }, + { + "body": { + "nativeSrc": "6939:220:17", + "nodeType": "YulBlock", + "src": "6939:220:17", + "statements": [ + { + "nativeSrc": "6949:74:17", + "nodeType": "YulAssignment", + "src": "6949:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "7015:3:17", + "nodeType": "YulIdentifier", + "src": "7015:3:17" + }, + { + "kind": "number", + "nativeSrc": "7020:2:17", + "nodeType": "YulLiteral", + "src": "7020:2:17", + "type": "", + "value": "37" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "6956:58:17", + "nodeType": "YulIdentifier", + "src": "6956:58:17" + }, + "nativeSrc": "6956:67:17", + "nodeType": "YulFunctionCall", + "src": "6956:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "6949:3:17", + "nodeType": "YulIdentifier", + "src": "6949:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "7121:3:17", + "nodeType": "YulIdentifier", + "src": "7121:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8", + "nativeSrc": "7032:88:17", + "nodeType": "YulIdentifier", + "src": "7032:88:17" + }, + "nativeSrc": "7032:93:17", + "nodeType": "YulFunctionCall", + "src": "7032:93:17" + }, + "nativeSrc": "7032:93:17", + "nodeType": "YulExpressionStatement", + "src": "7032:93:17" + }, + { + "nativeSrc": "7134:19:17", + "nodeType": "YulAssignment", + "src": "7134:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "7145:3:17", + "nodeType": "YulIdentifier", + "src": "7145:3:17" + }, + { + "kind": "number", + "nativeSrc": "7150:2:17", + "nodeType": "YulLiteral", + "src": "7150:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7141:3:17", + "nodeType": "YulIdentifier", + "src": "7141:3:17" + }, + "nativeSrc": "7141:12:17", + "nodeType": "YulFunctionCall", + "src": "7141:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "7134:3:17", + "nodeType": "YulIdentifier", + "src": "7134:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8_to_t_string_memory_ptr_fromStack", + "nativeSrc": "6793:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "6927:3:17", + "nodeType": "YulTypedName", + "src": "6927:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "6935:3:17", + "nodeType": "YulTypedName", + "src": "6935:3:17", + "type": "" + } + ], + "src": "6793:366:17" + }, + { + "body": { + "nativeSrc": "7336:248:17", + "nodeType": "YulBlock", + "src": "7336:248:17", + "statements": [ + { + "nativeSrc": "7346:26:17", + "nodeType": "YulAssignment", + "src": "7346:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "7358:9:17", + "nodeType": "YulIdentifier", + "src": "7358:9:17" + }, + { + "kind": "number", + "nativeSrc": "7369:2:17", + "nodeType": "YulLiteral", + "src": "7369:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7354:3:17", + "nodeType": "YulIdentifier", + "src": "7354:3:17" + }, + "nativeSrc": "7354:18:17", + "nodeType": "YulFunctionCall", + "src": "7354:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "7346:4:17", + "nodeType": "YulIdentifier", + "src": "7346:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "7393:9:17", + "nodeType": "YulIdentifier", + "src": "7393:9:17" + }, + { + "kind": "number", + "nativeSrc": "7404:1:17", + "nodeType": "YulLiteral", + "src": "7404:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7389:3:17", + "nodeType": "YulIdentifier", + "src": "7389:3:17" + }, + "nativeSrc": "7389:17:17", + "nodeType": "YulFunctionCall", + "src": "7389:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "7412:4:17", + "nodeType": "YulIdentifier", + "src": "7412:4:17" + }, + { + "name": "headStart", + "nativeSrc": "7418:9:17", + "nodeType": "YulIdentifier", + "src": "7418:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "7408:3:17", + "nodeType": "YulIdentifier", + "src": "7408:3:17" + }, + "nativeSrc": "7408:20:17", + "nodeType": "YulFunctionCall", + "src": "7408:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "7382:6:17", + "nodeType": "YulIdentifier", + "src": "7382:6:17" + }, + "nativeSrc": "7382:47:17", + "nodeType": "YulFunctionCall", + "src": "7382:47:17" + }, + "nativeSrc": "7382:47:17", + "nodeType": "YulExpressionStatement", + "src": "7382:47:17" + }, + { + "nativeSrc": "7438:139:17", + "nodeType": "YulAssignment", + "src": "7438:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "7572:4:17", + "nodeType": "YulIdentifier", + "src": "7572:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8_to_t_string_memory_ptr_fromStack", + "nativeSrc": "7446:124:17", + "nodeType": "YulIdentifier", + "src": "7446:124:17" + }, + "nativeSrc": "7446:131:17", + "nodeType": "YulFunctionCall", + "src": "7446:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "7438:4:17", + "nodeType": "YulIdentifier", + "src": "7438:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "7165:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "7316:9:17", + "nodeType": "YulTypedName", + "src": "7316:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "7331:4:17", + "nodeType": "YulTypedName", + "src": "7331:4:17", + "type": "" + } + ], + "src": "7165:419:17" + }, + { + "body": { + "nativeSrc": "7696:117:17", + "nodeType": "YulBlock", + "src": "7696:117:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "7718:6:17", + "nodeType": "YulIdentifier", + "src": "7718:6:17" + }, + { + "kind": "number", + "nativeSrc": "7726:1:17", + "nodeType": "YulLiteral", + "src": "7726:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7714:3:17", + "nodeType": "YulIdentifier", + "src": "7714:3:17" + }, + "nativeSrc": "7714:14:17", + "nodeType": "YulFunctionCall", + "src": "7714:14:17" + }, + { + "hexValue": "45524332303a20617070726f76652066726f6d20746865207a65726f20616464", + "kind": "string", + "nativeSrc": "7730:34:17", + "nodeType": "YulLiteral", + "src": "7730:34:17", + "type": "", + "value": "ERC20: approve from the zero add" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "7707:6:17", + "nodeType": "YulIdentifier", + "src": "7707:6:17" + }, + "nativeSrc": "7707:58:17", + "nodeType": "YulFunctionCall", + "src": "7707:58:17" + }, + "nativeSrc": "7707:58:17", + "nodeType": "YulExpressionStatement", + "src": "7707:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "7786:6:17", + "nodeType": "YulIdentifier", + "src": "7786:6:17" + }, + { + "kind": "number", + "nativeSrc": "7794:2:17", + "nodeType": "YulLiteral", + "src": "7794:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "7782:3:17", + "nodeType": "YulIdentifier", + "src": "7782:3:17" + }, + "nativeSrc": "7782:15:17", + "nodeType": "YulFunctionCall", + "src": "7782:15:17" + }, + { + "hexValue": "72657373", + "kind": "string", + "nativeSrc": "7799:6:17", + "nodeType": "YulLiteral", + "src": "7799:6:17", + "type": "", + "value": "ress" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "7775:6:17", + "nodeType": "YulIdentifier", + "src": "7775:6:17" + }, + "nativeSrc": "7775:31:17", + "nodeType": "YulFunctionCall", + "src": "7775:31:17" + }, + "nativeSrc": "7775:31:17", + "nodeType": "YulExpressionStatement", + "src": "7775:31:17" + } + ] + }, + "name": "store_literal_in_memory_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208", + "nativeSrc": "7590:223:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "7688:6:17", + "nodeType": "YulTypedName", + "src": "7688:6:17", + "type": "" + } + ], + "src": "7590:223:17" + }, + { + "body": { + "nativeSrc": "7965:220:17", + "nodeType": "YulBlock", + "src": "7965:220:17", + "statements": [ + { + "nativeSrc": "7975:74:17", + "nodeType": "YulAssignment", + "src": "7975:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "8041:3:17", + "nodeType": "YulIdentifier", + "src": "8041:3:17" + }, + { + "kind": "number", + "nativeSrc": "8046:2:17", + "nodeType": "YulLiteral", + "src": "8046:2:17", + "type": "", + "value": "36" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "7982:58:17", + "nodeType": "YulIdentifier", + "src": "7982:58:17" + }, + "nativeSrc": "7982:67:17", + "nodeType": "YulFunctionCall", + "src": "7982:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "7975:3:17", + "nodeType": "YulIdentifier", + "src": "7975:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "8147:3:17", + "nodeType": "YulIdentifier", + "src": "8147:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208", + "nativeSrc": "8058:88:17", + "nodeType": "YulIdentifier", + "src": "8058:88:17" + }, + "nativeSrc": "8058:93:17", + "nodeType": "YulFunctionCall", + "src": "8058:93:17" + }, + "nativeSrc": "8058:93:17", + "nodeType": "YulExpressionStatement", + "src": "8058:93:17" + }, + { + "nativeSrc": "8160:19:17", + "nodeType": "YulAssignment", + "src": "8160:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "8171:3:17", + "nodeType": "YulIdentifier", + "src": "8171:3:17" + }, + { + "kind": "number", + "nativeSrc": "8176:2:17", + "nodeType": "YulLiteral", + "src": "8176:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "8167:3:17", + "nodeType": "YulIdentifier", + "src": "8167:3:17" + }, + "nativeSrc": "8167:12:17", + "nodeType": "YulFunctionCall", + "src": "8167:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "8160:3:17", + "nodeType": "YulIdentifier", + "src": "8160:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208_to_t_string_memory_ptr_fromStack", + "nativeSrc": "7819:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "7953:3:17", + "nodeType": "YulTypedName", + "src": "7953:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "7961:3:17", + "nodeType": "YulTypedName", + "src": "7961:3:17", + "type": "" + } + ], + "src": "7819:366:17" + }, + { + "body": { + "nativeSrc": "8362:248:17", + "nodeType": "YulBlock", + "src": "8362:248:17", + "statements": [ + { + "nativeSrc": "8372:26:17", + "nodeType": "YulAssignment", + "src": "8372:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "8384:9:17", + "nodeType": "YulIdentifier", + "src": "8384:9:17" + }, + { + "kind": "number", + "nativeSrc": "8395:2:17", + "nodeType": "YulLiteral", + "src": "8395:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "8380:3:17", + "nodeType": "YulIdentifier", + "src": "8380:3:17" + }, + "nativeSrc": "8380:18:17", + "nodeType": "YulFunctionCall", + "src": "8380:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "8372:4:17", + "nodeType": "YulIdentifier", + "src": "8372:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "8419:9:17", + "nodeType": "YulIdentifier", + "src": "8419:9:17" + }, + { + "kind": "number", + "nativeSrc": "8430:1:17", + "nodeType": "YulLiteral", + "src": "8430:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "8415:3:17", + "nodeType": "YulIdentifier", + "src": "8415:3:17" + }, + "nativeSrc": "8415:17:17", + "nodeType": "YulFunctionCall", + "src": "8415:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "8438:4:17", + "nodeType": "YulIdentifier", + "src": "8438:4:17" + }, + { + "name": "headStart", + "nativeSrc": "8444:9:17", + "nodeType": "YulIdentifier", + "src": "8444:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "8434:3:17", + "nodeType": "YulIdentifier", + "src": "8434:3:17" + }, + "nativeSrc": "8434:20:17", + "nodeType": "YulFunctionCall", + "src": "8434:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "8408:6:17", + "nodeType": "YulIdentifier", + "src": "8408:6:17" + }, + "nativeSrc": "8408:47:17", + "nodeType": "YulFunctionCall", + "src": "8408:47:17" + }, + "nativeSrc": "8408:47:17", + "nodeType": "YulExpressionStatement", + "src": "8408:47:17" + }, + { + "nativeSrc": "8464:139:17", + "nodeType": "YulAssignment", + "src": "8464:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "8598:4:17", + "nodeType": "YulIdentifier", + "src": "8598:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208_to_t_string_memory_ptr_fromStack", + "nativeSrc": "8472:124:17", + "nodeType": "YulIdentifier", + "src": "8472:124:17" + }, + "nativeSrc": "8472:131:17", + "nodeType": "YulFunctionCall", + "src": "8472:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "8464:4:17", + "nodeType": "YulIdentifier", + "src": "8464:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "8191:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "8342:9:17", + "nodeType": "YulTypedName", + "src": "8342:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "8357:4:17", + "nodeType": "YulTypedName", + "src": "8357:4:17", + "type": "" + } + ], + "src": "8191:419:17" + }, + { + "body": { + "nativeSrc": "8722:115:17", + "nodeType": "YulBlock", + "src": "8722:115:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "8744:6:17", + "nodeType": "YulIdentifier", + "src": "8744:6:17" + }, + { + "kind": "number", + "nativeSrc": "8752:1:17", + "nodeType": "YulLiteral", + "src": "8752:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "8740:3:17", + "nodeType": "YulIdentifier", + "src": "8740:3:17" + }, + "nativeSrc": "8740:14:17", + "nodeType": "YulFunctionCall", + "src": "8740:14:17" + }, + { + "hexValue": "45524332303a20617070726f766520746f20746865207a65726f206164647265", + "kind": "string", + "nativeSrc": "8756:34:17", + "nodeType": "YulLiteral", + "src": "8756:34:17", + "type": "", + "value": "ERC20: approve to the zero addre" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "8733:6:17", + "nodeType": "YulIdentifier", + "src": "8733:6:17" + }, + "nativeSrc": "8733:58:17", + "nodeType": "YulFunctionCall", + "src": "8733:58:17" + }, + "nativeSrc": "8733:58:17", + "nodeType": "YulExpressionStatement", + "src": "8733:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "8812:6:17", + "nodeType": "YulIdentifier", + "src": "8812:6:17" + }, + { + "kind": "number", + "nativeSrc": "8820:2:17", + "nodeType": "YulLiteral", + "src": "8820:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "8808:3:17", + "nodeType": "YulIdentifier", + "src": "8808:3:17" + }, + "nativeSrc": "8808:15:17", + "nodeType": "YulFunctionCall", + "src": "8808:15:17" + }, + { + "hexValue": "7373", + "kind": "string", + "nativeSrc": "8825:4:17", + "nodeType": "YulLiteral", + "src": "8825:4:17", + "type": "", + "value": "ss" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "8801:6:17", + "nodeType": "YulIdentifier", + "src": "8801:6:17" + }, + "nativeSrc": "8801:29:17", + "nodeType": "YulFunctionCall", + "src": "8801:29:17" + }, + "nativeSrc": "8801:29:17", + "nodeType": "YulExpressionStatement", + "src": "8801:29:17" + } + ] + }, + "name": "store_literal_in_memory_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029", + "nativeSrc": "8616:221:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "8714:6:17", + "nodeType": "YulTypedName", + "src": "8714:6:17", + "type": "" + } + ], + "src": "8616:221:17" + }, + { + "body": { + "nativeSrc": "8989:220:17", + "nodeType": "YulBlock", + "src": "8989:220:17", + "statements": [ + { + "nativeSrc": "8999:74:17", + "nodeType": "YulAssignment", + "src": "8999:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "9065:3:17", + "nodeType": "YulIdentifier", + "src": "9065:3:17" + }, + { + "kind": "number", + "nativeSrc": "9070:2:17", + "nodeType": "YulLiteral", + "src": "9070:2:17", + "type": "", + "value": "34" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "9006:58:17", + "nodeType": "YulIdentifier", + "src": "9006:58:17" + }, + "nativeSrc": "9006:67:17", + "nodeType": "YulFunctionCall", + "src": "9006:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "8999:3:17", + "nodeType": "YulIdentifier", + "src": "8999:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "9171:3:17", + "nodeType": "YulIdentifier", + "src": "9171:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029", + "nativeSrc": "9082:88:17", + "nodeType": "YulIdentifier", + "src": "9082:88:17" + }, + "nativeSrc": "9082:93:17", + "nodeType": "YulFunctionCall", + "src": "9082:93:17" + }, + "nativeSrc": "9082:93:17", + "nodeType": "YulExpressionStatement", + "src": "9082:93:17" + }, + { + "nativeSrc": "9184:19:17", + "nodeType": "YulAssignment", + "src": "9184:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "9195:3:17", + "nodeType": "YulIdentifier", + "src": "9195:3:17" + }, + { + "kind": "number", + "nativeSrc": "9200:2:17", + "nodeType": "YulLiteral", + "src": "9200:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "9191:3:17", + "nodeType": "YulIdentifier", + "src": "9191:3:17" + }, + "nativeSrc": "9191:12:17", + "nodeType": "YulFunctionCall", + "src": "9191:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "9184:3:17", + "nodeType": "YulIdentifier", + "src": "9184:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029_to_t_string_memory_ptr_fromStack", + "nativeSrc": "8843:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "8977:3:17", + "nodeType": "YulTypedName", + "src": "8977:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "8985:3:17", + "nodeType": "YulTypedName", + "src": "8985:3:17", + "type": "" + } + ], + "src": "8843:366:17" + }, + { + "body": { + "nativeSrc": "9386:248:17", + "nodeType": "YulBlock", + "src": "9386:248:17", + "statements": [ + { + "nativeSrc": "9396:26:17", + "nodeType": "YulAssignment", + "src": "9396:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "9408:9:17", + "nodeType": "YulIdentifier", + "src": "9408:9:17" + }, + { + "kind": "number", + "nativeSrc": "9419:2:17", + "nodeType": "YulLiteral", + "src": "9419:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "9404:3:17", + "nodeType": "YulIdentifier", + "src": "9404:3:17" + }, + "nativeSrc": "9404:18:17", + "nodeType": "YulFunctionCall", + "src": "9404:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "9396:4:17", + "nodeType": "YulIdentifier", + "src": "9396:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "9443:9:17", + "nodeType": "YulIdentifier", + "src": "9443:9:17" + }, + { + "kind": "number", + "nativeSrc": "9454:1:17", + "nodeType": "YulLiteral", + "src": "9454:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "9439:3:17", + "nodeType": "YulIdentifier", + "src": "9439:3:17" + }, + "nativeSrc": "9439:17:17", + "nodeType": "YulFunctionCall", + "src": "9439:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "9462:4:17", + "nodeType": "YulIdentifier", + "src": "9462:4:17" + }, + { + "name": "headStart", + "nativeSrc": "9468:9:17", + "nodeType": "YulIdentifier", + "src": "9468:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "9458:3:17", + "nodeType": "YulIdentifier", + "src": "9458:3:17" + }, + "nativeSrc": "9458:20:17", + "nodeType": "YulFunctionCall", + "src": "9458:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "9432:6:17", + "nodeType": "YulIdentifier", + "src": "9432:6:17" + }, + "nativeSrc": "9432:47:17", + "nodeType": "YulFunctionCall", + "src": "9432:47:17" + }, + "nativeSrc": "9432:47:17", + "nodeType": "YulExpressionStatement", + "src": "9432:47:17" + }, + { + "nativeSrc": "9488:139:17", + "nodeType": "YulAssignment", + "src": "9488:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "9622:4:17", + "nodeType": "YulIdentifier", + "src": "9622:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029_to_t_string_memory_ptr_fromStack", + "nativeSrc": "9496:124:17", + "nodeType": "YulIdentifier", + "src": "9496:124:17" + }, + "nativeSrc": "9496:131:17", + "nodeType": "YulFunctionCall", + "src": "9496:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "9488:4:17", + "nodeType": "YulIdentifier", + "src": "9488:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "9215:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "9366:9:17", + "nodeType": "YulTypedName", + "src": "9366:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "9381:4:17", + "nodeType": "YulTypedName", + "src": "9381:4:17", + "type": "" + } + ], + "src": "9215:419:17" + }, + { + "body": { + "nativeSrc": "9746:73:17", + "nodeType": "YulBlock", + "src": "9746:73:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "9768:6:17", + "nodeType": "YulIdentifier", + "src": "9768:6:17" + }, + { + "kind": "number", + "nativeSrc": "9776:1:17", + "nodeType": "YulLiteral", + "src": "9776:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "9764:3:17", + "nodeType": "YulIdentifier", + "src": "9764:3:17" + }, + "nativeSrc": "9764:14:17", + "nodeType": "YulFunctionCall", + "src": "9764:14:17" + }, + { + "hexValue": "45524332303a20696e73756666696369656e7420616c6c6f77616e6365", + "kind": "string", + "nativeSrc": "9780:31:17", + "nodeType": "YulLiteral", + "src": "9780:31:17", + "type": "", + "value": "ERC20: insufficient allowance" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "9757:6:17", + "nodeType": "YulIdentifier", + "src": "9757:6:17" + }, + "nativeSrc": "9757:55:17", + "nodeType": "YulFunctionCall", + "src": "9757:55:17" + }, + "nativeSrc": "9757:55:17", + "nodeType": "YulExpressionStatement", + "src": "9757:55:17" + } + ] + }, + "name": "store_literal_in_memory_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe", + "nativeSrc": "9640:179:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "9738:6:17", + "nodeType": "YulTypedName", + "src": "9738:6:17", + "type": "" + } + ], + "src": "9640:179:17" + }, + { + "body": { + "nativeSrc": "9971:220:17", + "nodeType": "YulBlock", + "src": "9971:220:17", + "statements": [ + { + "nativeSrc": "9981:74:17", + "nodeType": "YulAssignment", + "src": "9981:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "10047:3:17", + "nodeType": "YulIdentifier", + "src": "10047:3:17" + }, + { + "kind": "number", + "nativeSrc": "10052:2:17", + "nodeType": "YulLiteral", + "src": "10052:2:17", + "type": "", + "value": "29" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "9988:58:17", + "nodeType": "YulIdentifier", + "src": "9988:58:17" + }, + "nativeSrc": "9988:67:17", + "nodeType": "YulFunctionCall", + "src": "9988:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "9981:3:17", + "nodeType": "YulIdentifier", + "src": "9981:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "10153:3:17", + "nodeType": "YulIdentifier", + "src": "10153:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe", + "nativeSrc": "10064:88:17", + "nodeType": "YulIdentifier", + "src": "10064:88:17" + }, + "nativeSrc": "10064:93:17", + "nodeType": "YulFunctionCall", + "src": "10064:93:17" + }, + "nativeSrc": "10064:93:17", + "nodeType": "YulExpressionStatement", + "src": "10064:93:17" + }, + { + "nativeSrc": "10166:19:17", + "nodeType": "YulAssignment", + "src": "10166:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "10177:3:17", + "nodeType": "YulIdentifier", + "src": "10177:3:17" + }, + { + "kind": "number", + "nativeSrc": "10182:2:17", + "nodeType": "YulLiteral", + "src": "10182:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "10173:3:17", + "nodeType": "YulIdentifier", + "src": "10173:3:17" + }, + "nativeSrc": "10173:12:17", + "nodeType": "YulFunctionCall", + "src": "10173:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "10166:3:17", + "nodeType": "YulIdentifier", + "src": "10166:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe_to_t_string_memory_ptr_fromStack", + "nativeSrc": "9825:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "9959:3:17", + "nodeType": "YulTypedName", + "src": "9959:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "9967:3:17", + "nodeType": "YulTypedName", + "src": "9967:3:17", + "type": "" + } + ], + "src": "9825:366:17" + }, + { + "body": { + "nativeSrc": "10368:248:17", + "nodeType": "YulBlock", + "src": "10368:248:17", + "statements": [ + { + "nativeSrc": "10378:26:17", + "nodeType": "YulAssignment", + "src": "10378:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "10390:9:17", + "nodeType": "YulIdentifier", + "src": "10390:9:17" + }, + { + "kind": "number", + "nativeSrc": "10401:2:17", + "nodeType": "YulLiteral", + "src": "10401:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "10386:3:17", + "nodeType": "YulIdentifier", + "src": "10386:3:17" + }, + "nativeSrc": "10386:18:17", + "nodeType": "YulFunctionCall", + "src": "10386:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "10378:4:17", + "nodeType": "YulIdentifier", + "src": "10378:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "10425:9:17", + "nodeType": "YulIdentifier", + "src": "10425:9:17" + }, + { + "kind": "number", + "nativeSrc": "10436:1:17", + "nodeType": "YulLiteral", + "src": "10436:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "10421:3:17", + "nodeType": "YulIdentifier", + "src": "10421:3:17" + }, + "nativeSrc": "10421:17:17", + "nodeType": "YulFunctionCall", + "src": "10421:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "10444:4:17", + "nodeType": "YulIdentifier", + "src": "10444:4:17" + }, + { + "name": "headStart", + "nativeSrc": "10450:9:17", + "nodeType": "YulIdentifier", + "src": "10450:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "10440:3:17", + "nodeType": "YulIdentifier", + "src": "10440:3:17" + }, + "nativeSrc": "10440:20:17", + "nodeType": "YulFunctionCall", + "src": "10440:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "10414:6:17", + "nodeType": "YulIdentifier", + "src": "10414:6:17" + }, + "nativeSrc": "10414:47:17", + "nodeType": "YulFunctionCall", + "src": "10414:47:17" + }, + "nativeSrc": "10414:47:17", + "nodeType": "YulExpressionStatement", + "src": "10414:47:17" + }, + { + "nativeSrc": "10470:139:17", + "nodeType": "YulAssignment", + "src": "10470:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "10604:4:17", + "nodeType": "YulIdentifier", + "src": "10604:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe_to_t_string_memory_ptr_fromStack", + "nativeSrc": "10478:124:17", + "nodeType": "YulIdentifier", + "src": "10478:124:17" + }, + "nativeSrc": "10478:131:17", + "nodeType": "YulFunctionCall", + "src": "10478:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "10470:4:17", + "nodeType": "YulIdentifier", + "src": "10470:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "10197:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "10348:9:17", + "nodeType": "YulTypedName", + "src": "10348:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "10363:4:17", + "nodeType": "YulTypedName", + "src": "10363:4:17", + "type": "" + } + ], + "src": "10197:419:17" + }, + { + "body": { + "nativeSrc": "10728:118:17", + "nodeType": "YulBlock", + "src": "10728:118:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "10750:6:17", + "nodeType": "YulIdentifier", + "src": "10750:6:17" + }, + { + "kind": "number", + "nativeSrc": "10758:1:17", + "nodeType": "YulLiteral", + "src": "10758:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "10746:3:17", + "nodeType": "YulIdentifier", + "src": "10746:3:17" + }, + "nativeSrc": "10746:14:17", + "nodeType": "YulFunctionCall", + "src": "10746:14:17" + }, + { + "hexValue": "45524332303a207472616e736665722066726f6d20746865207a65726f206164", + "kind": "string", + "nativeSrc": "10762:34:17", + "nodeType": "YulLiteral", + "src": "10762:34:17", + "type": "", + "value": "ERC20: transfer from the zero ad" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "10739:6:17", + "nodeType": "YulIdentifier", + "src": "10739:6:17" + }, + "nativeSrc": "10739:58:17", + "nodeType": "YulFunctionCall", + "src": "10739:58:17" + }, + "nativeSrc": "10739:58:17", + "nodeType": "YulExpressionStatement", + "src": "10739:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "10818:6:17", + "nodeType": "YulIdentifier", + "src": "10818:6:17" + }, + { + "kind": "number", + "nativeSrc": "10826:2:17", + "nodeType": "YulLiteral", + "src": "10826:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "10814:3:17", + "nodeType": "YulIdentifier", + "src": "10814:3:17" + }, + "nativeSrc": "10814:15:17", + "nodeType": "YulFunctionCall", + "src": "10814:15:17" + }, + { + "hexValue": "6472657373", + "kind": "string", + "nativeSrc": "10831:7:17", + "nodeType": "YulLiteral", + "src": "10831:7:17", + "type": "", + "value": "dress" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "10807:6:17", + "nodeType": "YulIdentifier", + "src": "10807:6:17" + }, + "nativeSrc": "10807:32:17", + "nodeType": "YulFunctionCall", + "src": "10807:32:17" + }, + "nativeSrc": "10807:32:17", + "nodeType": "YulExpressionStatement", + "src": "10807:32:17" + } + ] + }, + "name": "store_literal_in_memory_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea", + "nativeSrc": "10622:224:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "10720:6:17", + "nodeType": "YulTypedName", + "src": "10720:6:17", + "type": "" + } + ], + "src": "10622:224:17" + }, + { + "body": { + "nativeSrc": "10998:220:17", + "nodeType": "YulBlock", + "src": "10998:220:17", + "statements": [ + { + "nativeSrc": "11008:74:17", + "nodeType": "YulAssignment", + "src": "11008:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "11074:3:17", + "nodeType": "YulIdentifier", + "src": "11074:3:17" + }, + { + "kind": "number", + "nativeSrc": "11079:2:17", + "nodeType": "YulLiteral", + "src": "11079:2:17", + "type": "", + "value": "37" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "11015:58:17", + "nodeType": "YulIdentifier", + "src": "11015:58:17" + }, + "nativeSrc": "11015:67:17", + "nodeType": "YulFunctionCall", + "src": "11015:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "11008:3:17", + "nodeType": "YulIdentifier", + "src": "11008:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "11180:3:17", + "nodeType": "YulIdentifier", + "src": "11180:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea", + "nativeSrc": "11091:88:17", + "nodeType": "YulIdentifier", + "src": "11091:88:17" + }, + "nativeSrc": "11091:93:17", + "nodeType": "YulFunctionCall", + "src": "11091:93:17" + }, + "nativeSrc": "11091:93:17", + "nodeType": "YulExpressionStatement", + "src": "11091:93:17" + }, + { + "nativeSrc": "11193:19:17", + "nodeType": "YulAssignment", + "src": "11193:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "11204:3:17", + "nodeType": "YulIdentifier", + "src": "11204:3:17" + }, + { + "kind": "number", + "nativeSrc": "11209:2:17", + "nodeType": "YulLiteral", + "src": "11209:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11200:3:17", + "nodeType": "YulIdentifier", + "src": "11200:3:17" + }, + "nativeSrc": "11200:12:17", + "nodeType": "YulFunctionCall", + "src": "11200:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "11193:3:17", + "nodeType": "YulIdentifier", + "src": "11193:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea_to_t_string_memory_ptr_fromStack", + "nativeSrc": "10852:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "10986:3:17", + "nodeType": "YulTypedName", + "src": "10986:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "10994:3:17", + "nodeType": "YulTypedName", + "src": "10994:3:17", + "type": "" + } + ], + "src": "10852:366:17" + }, + { + "body": { + "nativeSrc": "11395:248:17", + "nodeType": "YulBlock", + "src": "11395:248:17", + "statements": [ + { + "nativeSrc": "11405:26:17", + "nodeType": "YulAssignment", + "src": "11405:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "11417:9:17", + "nodeType": "YulIdentifier", + "src": "11417:9:17" + }, + { + "kind": "number", + "nativeSrc": "11428:2:17", + "nodeType": "YulLiteral", + "src": "11428:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11413:3:17", + "nodeType": "YulIdentifier", + "src": "11413:3:17" + }, + "nativeSrc": "11413:18:17", + "nodeType": "YulFunctionCall", + "src": "11413:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "11405:4:17", + "nodeType": "YulIdentifier", + "src": "11405:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "11452:9:17", + "nodeType": "YulIdentifier", + "src": "11452:9:17" + }, + { + "kind": "number", + "nativeSrc": "11463:1:17", + "nodeType": "YulLiteral", + "src": "11463:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11448:3:17", + "nodeType": "YulIdentifier", + "src": "11448:3:17" + }, + "nativeSrc": "11448:17:17", + "nodeType": "YulFunctionCall", + "src": "11448:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "11471:4:17", + "nodeType": "YulIdentifier", + "src": "11471:4:17" + }, + { + "name": "headStart", + "nativeSrc": "11477:9:17", + "nodeType": "YulIdentifier", + "src": "11477:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "11467:3:17", + "nodeType": "YulIdentifier", + "src": "11467:3:17" + }, + "nativeSrc": "11467:20:17", + "nodeType": "YulFunctionCall", + "src": "11467:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "11441:6:17", + "nodeType": "YulIdentifier", + "src": "11441:6:17" + }, + "nativeSrc": "11441:47:17", + "nodeType": "YulFunctionCall", + "src": "11441:47:17" + }, + "nativeSrc": "11441:47:17", + "nodeType": "YulExpressionStatement", + "src": "11441:47:17" + }, + { + "nativeSrc": "11497:139:17", + "nodeType": "YulAssignment", + "src": "11497:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "11631:4:17", + "nodeType": "YulIdentifier", + "src": "11631:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea_to_t_string_memory_ptr_fromStack", + "nativeSrc": "11505:124:17", + "nodeType": "YulIdentifier", + "src": "11505:124:17" + }, + "nativeSrc": "11505:131:17", + "nodeType": "YulFunctionCall", + "src": "11505:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "11497:4:17", + "nodeType": "YulIdentifier", + "src": "11497:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "11224:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "11375:9:17", + "nodeType": "YulTypedName", + "src": "11375:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "11390:4:17", + "nodeType": "YulTypedName", + "src": "11390:4:17", + "type": "" + } + ], + "src": "11224:419:17" + }, + { + "body": { + "nativeSrc": "11755:116:17", + "nodeType": "YulBlock", + "src": "11755:116:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "11777:6:17", + "nodeType": "YulIdentifier", + "src": "11777:6:17" + }, + { + "kind": "number", + "nativeSrc": "11785:1:17", + "nodeType": "YulLiteral", + "src": "11785:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11773:3:17", + "nodeType": "YulIdentifier", + "src": "11773:3:17" + }, + "nativeSrc": "11773:14:17", + "nodeType": "YulFunctionCall", + "src": "11773:14:17" + }, + { + "hexValue": "45524332303a207472616e7366657220746f20746865207a65726f2061646472", + "kind": "string", + "nativeSrc": "11789:34:17", + "nodeType": "YulLiteral", + "src": "11789:34:17", + "type": "", + "value": "ERC20: transfer to the zero addr" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "11766:6:17", + "nodeType": "YulIdentifier", + "src": "11766:6:17" + }, + "nativeSrc": "11766:58:17", + "nodeType": "YulFunctionCall", + "src": "11766:58:17" + }, + "nativeSrc": "11766:58:17", + "nodeType": "YulExpressionStatement", + "src": "11766:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "11845:6:17", + "nodeType": "YulIdentifier", + "src": "11845:6:17" + }, + { + "kind": "number", + "nativeSrc": "11853:2:17", + "nodeType": "YulLiteral", + "src": "11853:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "11841:3:17", + "nodeType": "YulIdentifier", + "src": "11841:3:17" + }, + "nativeSrc": "11841:15:17", + "nodeType": "YulFunctionCall", + "src": "11841:15:17" + }, + { + "hexValue": "657373", + "kind": "string", + "nativeSrc": "11858:5:17", + "nodeType": "YulLiteral", + "src": "11858:5:17", + "type": "", + "value": "ess" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "11834:6:17", + "nodeType": "YulIdentifier", + "src": "11834:6:17" + }, + "nativeSrc": "11834:30:17", + "nodeType": "YulFunctionCall", + "src": "11834:30:17" + }, + "nativeSrc": "11834:30:17", + "nodeType": "YulExpressionStatement", + "src": "11834:30:17" + } + ] + }, + "name": "store_literal_in_memory_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f", + "nativeSrc": "11649:222:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "11747:6:17", + "nodeType": "YulTypedName", + "src": "11747:6:17", + "type": "" + } + ], + "src": "11649:222:17" + }, + { + "body": { + "nativeSrc": "12023:220:17", + "nodeType": "YulBlock", + "src": "12023:220:17", + "statements": [ + { + "nativeSrc": "12033:74:17", + "nodeType": "YulAssignment", + "src": "12033:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "12099:3:17", + "nodeType": "YulIdentifier", + "src": "12099:3:17" + }, + { + "kind": "number", + "nativeSrc": "12104:2:17", + "nodeType": "YulLiteral", + "src": "12104:2:17", + "type": "", + "value": "35" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "12040:58:17", + "nodeType": "YulIdentifier", + "src": "12040:58:17" + }, + "nativeSrc": "12040:67:17", + "nodeType": "YulFunctionCall", + "src": "12040:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "12033:3:17", + "nodeType": "YulIdentifier", + "src": "12033:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "12205:3:17", + "nodeType": "YulIdentifier", + "src": "12205:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f", + "nativeSrc": "12116:88:17", + "nodeType": "YulIdentifier", + "src": "12116:88:17" + }, + "nativeSrc": "12116:93:17", + "nodeType": "YulFunctionCall", + "src": "12116:93:17" + }, + "nativeSrc": "12116:93:17", + "nodeType": "YulExpressionStatement", + "src": "12116:93:17" + }, + { + "nativeSrc": "12218:19:17", + "nodeType": "YulAssignment", + "src": "12218:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "12229:3:17", + "nodeType": "YulIdentifier", + "src": "12229:3:17" + }, + { + "kind": "number", + "nativeSrc": "12234:2:17", + "nodeType": "YulLiteral", + "src": "12234:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12225:3:17", + "nodeType": "YulIdentifier", + "src": "12225:3:17" + }, + "nativeSrc": "12225:12:17", + "nodeType": "YulFunctionCall", + "src": "12225:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "12218:3:17", + "nodeType": "YulIdentifier", + "src": "12218:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f_to_t_string_memory_ptr_fromStack", + "nativeSrc": "11877:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "12011:3:17", + "nodeType": "YulTypedName", + "src": "12011:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "12019:3:17", + "nodeType": "YulTypedName", + "src": "12019:3:17", + "type": "" + } + ], + "src": "11877:366:17" + }, + { + "body": { + "nativeSrc": "12420:248:17", + "nodeType": "YulBlock", + "src": "12420:248:17", + "statements": [ + { + "nativeSrc": "12430:26:17", + "nodeType": "YulAssignment", + "src": "12430:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "12442:9:17", + "nodeType": "YulIdentifier", + "src": "12442:9:17" + }, + { + "kind": "number", + "nativeSrc": "12453:2:17", + "nodeType": "YulLiteral", + "src": "12453:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12438:3:17", + "nodeType": "YulIdentifier", + "src": "12438:3:17" + }, + "nativeSrc": "12438:18:17", + "nodeType": "YulFunctionCall", + "src": "12438:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "12430:4:17", + "nodeType": "YulIdentifier", + "src": "12430:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "12477:9:17", + "nodeType": "YulIdentifier", + "src": "12477:9:17" + }, + { + "kind": "number", + "nativeSrc": "12488:1:17", + "nodeType": "YulLiteral", + "src": "12488:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12473:3:17", + "nodeType": "YulIdentifier", + "src": "12473:3:17" + }, + "nativeSrc": "12473:17:17", + "nodeType": "YulFunctionCall", + "src": "12473:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "12496:4:17", + "nodeType": "YulIdentifier", + "src": "12496:4:17" + }, + { + "name": "headStart", + "nativeSrc": "12502:9:17", + "nodeType": "YulIdentifier", + "src": "12502:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "12492:3:17", + "nodeType": "YulIdentifier", + "src": "12492:3:17" + }, + "nativeSrc": "12492:20:17", + "nodeType": "YulFunctionCall", + "src": "12492:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "12466:6:17", + "nodeType": "YulIdentifier", + "src": "12466:6:17" + }, + "nativeSrc": "12466:47:17", + "nodeType": "YulFunctionCall", + "src": "12466:47:17" + }, + "nativeSrc": "12466:47:17", + "nodeType": "YulExpressionStatement", + "src": "12466:47:17" + }, + { + "nativeSrc": "12522:139:17", + "nodeType": "YulAssignment", + "src": "12522:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "12656:4:17", + "nodeType": "YulIdentifier", + "src": "12656:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f_to_t_string_memory_ptr_fromStack", + "nativeSrc": "12530:124:17", + "nodeType": "YulIdentifier", + "src": "12530:124:17" + }, + "nativeSrc": "12530:131:17", + "nodeType": "YulFunctionCall", + "src": "12530:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "12522:4:17", + "nodeType": "YulIdentifier", + "src": "12522:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "12249:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "12400:9:17", + "nodeType": "YulTypedName", + "src": "12400:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "12415:4:17", + "nodeType": "YulTypedName", + "src": "12415:4:17", + "type": "" + } + ], + "src": "12249:419:17" + }, + { + "body": { + "nativeSrc": "12780:119:17", + "nodeType": "YulBlock", + "src": "12780:119:17", + "statements": [ + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "12802:6:17", + "nodeType": "YulIdentifier", + "src": "12802:6:17" + }, + { + "kind": "number", + "nativeSrc": "12810:1:17", + "nodeType": "YulLiteral", + "src": "12810:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12798:3:17", + "nodeType": "YulIdentifier", + "src": "12798:3:17" + }, + "nativeSrc": "12798:14:17", + "nodeType": "YulFunctionCall", + "src": "12798:14:17" + }, + { + "hexValue": "45524332303a207472616e7366657220616d6f756e7420657863656564732062", + "kind": "string", + "nativeSrc": "12814:34:17", + "nodeType": "YulLiteral", + "src": "12814:34:17", + "type": "", + "value": "ERC20: transfer amount exceeds b" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "12791:6:17", + "nodeType": "YulIdentifier", + "src": "12791:6:17" + }, + "nativeSrc": "12791:58:17", + "nodeType": "YulFunctionCall", + "src": "12791:58:17" + }, + "nativeSrc": "12791:58:17", + "nodeType": "YulExpressionStatement", + "src": "12791:58:17" + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "memPtr", + "nativeSrc": "12870:6:17", + "nodeType": "YulIdentifier", + "src": "12870:6:17" + }, + { + "kind": "number", + "nativeSrc": "12878:2:17", + "nodeType": "YulLiteral", + "src": "12878:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "12866:3:17", + "nodeType": "YulIdentifier", + "src": "12866:3:17" + }, + "nativeSrc": "12866:15:17", + "nodeType": "YulFunctionCall", + "src": "12866:15:17" + }, + { + "hexValue": "616c616e6365", + "kind": "string", + "nativeSrc": "12883:8:17", + "nodeType": "YulLiteral", + "src": "12883:8:17", + "type": "", + "value": "alance" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "12859:6:17", + "nodeType": "YulIdentifier", + "src": "12859:6:17" + }, + "nativeSrc": "12859:33:17", + "nodeType": "YulFunctionCall", + "src": "12859:33:17" + }, + "nativeSrc": "12859:33:17", + "nodeType": "YulExpressionStatement", + "src": "12859:33:17" + } + ] + }, + "name": "store_literal_in_memory_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6", + "nativeSrc": "12674:225:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "memPtr", + "nativeSrc": "12772:6:17", + "nodeType": "YulTypedName", + "src": "12772:6:17", + "type": "" + } + ], + "src": "12674:225:17" + }, + { + "body": { + "nativeSrc": "13051:220:17", + "nodeType": "YulBlock", + "src": "13051:220:17", + "statements": [ + { + "nativeSrc": "13061:74:17", + "nodeType": "YulAssignment", + "src": "13061:74:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "13127:3:17", + "nodeType": "YulIdentifier", + "src": "13127:3:17" + }, + { + "kind": "number", + "nativeSrc": "13132:2:17", + "nodeType": "YulLiteral", + "src": "13132:2:17", + "type": "", + "value": "38" + } + ], + "functionName": { + "name": "array_storeLengthForEncoding_t_string_memory_ptr_fromStack", + "nativeSrc": "13068:58:17", + "nodeType": "YulIdentifier", + "src": "13068:58:17" + }, + "nativeSrc": "13068:67:17", + "nodeType": "YulFunctionCall", + "src": "13068:67:17" + }, + "variableNames": [ + { + "name": "pos", + "nativeSrc": "13061:3:17", + "nodeType": "YulIdentifier", + "src": "13061:3:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "13233:3:17", + "nodeType": "YulIdentifier", + "src": "13233:3:17" + } + ], + "functionName": { + "name": "store_literal_in_memory_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6", + "nativeSrc": "13144:88:17", + "nodeType": "YulIdentifier", + "src": "13144:88:17" + }, + "nativeSrc": "13144:93:17", + "nodeType": "YulFunctionCall", + "src": "13144:93:17" + }, + "nativeSrc": "13144:93:17", + "nodeType": "YulExpressionStatement", + "src": "13144:93:17" + }, + { + "nativeSrc": "13246:19:17", + "nodeType": "YulAssignment", + "src": "13246:19:17", + "value": { + "arguments": [ + { + "name": "pos", + "nativeSrc": "13257:3:17", + "nodeType": "YulIdentifier", + "src": "13257:3:17" + }, + { + "kind": "number", + "nativeSrc": "13262:2:17", + "nodeType": "YulLiteral", + "src": "13262:2:17", + "type": "", + "value": "64" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "13253:3:17", + "nodeType": "YulIdentifier", + "src": "13253:3:17" + }, + "nativeSrc": "13253:12:17", + "nodeType": "YulFunctionCall", + "src": "13253:12:17" + }, + "variableNames": [ + { + "name": "end", + "nativeSrc": "13246:3:17", + "nodeType": "YulIdentifier", + "src": "13246:3:17" + } + ] + } + ] + }, + "name": "abi_encode_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6_to_t_string_memory_ptr_fromStack", + "nativeSrc": "12905:366:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "pos", + "nativeSrc": "13039:3:17", + "nodeType": "YulTypedName", + "src": "13039:3:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "end", + "nativeSrc": "13047:3:17", + "nodeType": "YulTypedName", + "src": "13047:3:17", + "type": "" + } + ], + "src": "12905:366:17" + }, + { + "body": { + "nativeSrc": "13448:248:17", + "nodeType": "YulBlock", + "src": "13448:248:17", + "statements": [ + { + "nativeSrc": "13458:26:17", + "nodeType": "YulAssignment", + "src": "13458:26:17", + "value": { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "13470:9:17", + "nodeType": "YulIdentifier", + "src": "13470:9:17" + }, + { + "kind": "number", + "nativeSrc": "13481:2:17", + "nodeType": "YulLiteral", + "src": "13481:2:17", + "type": "", + "value": "32" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "13466:3:17", + "nodeType": "YulIdentifier", + "src": "13466:3:17" + }, + "nativeSrc": "13466:18:17", + "nodeType": "YulFunctionCall", + "src": "13466:18:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "13458:4:17", + "nodeType": "YulIdentifier", + "src": "13458:4:17" + } + ] + }, + { + "expression": { + "arguments": [ + { + "arguments": [ + { + "name": "headStart", + "nativeSrc": "13505:9:17", + "nodeType": "YulIdentifier", + "src": "13505:9:17" + }, + { + "kind": "number", + "nativeSrc": "13516:1:17", + "nodeType": "YulLiteral", + "src": "13516:1:17", + "type": "", + "value": "0" + } + ], + "functionName": { + "name": "add", + "nativeSrc": "13501:3:17", + "nodeType": "YulIdentifier", + "src": "13501:3:17" + }, + "nativeSrc": "13501:17:17", + "nodeType": "YulFunctionCall", + "src": "13501:17:17" + }, + { + "arguments": [ + { + "name": "tail", + "nativeSrc": "13524:4:17", + "nodeType": "YulIdentifier", + "src": "13524:4:17" + }, + { + "name": "headStart", + "nativeSrc": "13530:9:17", + "nodeType": "YulIdentifier", + "src": "13530:9:17" + } + ], + "functionName": { + "name": "sub", + "nativeSrc": "13520:3:17", + "nodeType": "YulIdentifier", + "src": "13520:3:17" + }, + "nativeSrc": "13520:20:17", + "nodeType": "YulFunctionCall", + "src": "13520:20:17" + } + ], + "functionName": { + "name": "mstore", + "nativeSrc": "13494:6:17", + "nodeType": "YulIdentifier", + "src": "13494:6:17" + }, + "nativeSrc": "13494:47:17", + "nodeType": "YulFunctionCall", + "src": "13494:47:17" + }, + "nativeSrc": "13494:47:17", + "nodeType": "YulExpressionStatement", + "src": "13494:47:17" + }, + { + "nativeSrc": "13550:139:17", + "nodeType": "YulAssignment", + "src": "13550:139:17", + "value": { + "arguments": [ + { + "name": "tail", + "nativeSrc": "13684:4:17", + "nodeType": "YulIdentifier", + "src": "13684:4:17" + } + ], + "functionName": { + "name": "abi_encode_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6_to_t_string_memory_ptr_fromStack", + "nativeSrc": "13558:124:17", + "nodeType": "YulIdentifier", + "src": "13558:124:17" + }, + "nativeSrc": "13558:131:17", + "nodeType": "YulFunctionCall", + "src": "13558:131:17" + }, + "variableNames": [ + { + "name": "tail", + "nativeSrc": "13550:4:17", + "nodeType": "YulIdentifier", + "src": "13550:4:17" + } + ] + } + ] + }, + "name": "abi_encode_tuple_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6__to_t_string_memory_ptr__fromStack_reversed", + "nativeSrc": "13277:419:17", + "nodeType": "YulFunctionDefinition", + "parameters": [ + { + "name": "headStart", + "nativeSrc": "13428:9:17", + "nodeType": "YulTypedName", + "src": "13428:9:17", + "type": "" + } + ], + "returnVariables": [ + { + "name": "tail", + "nativeSrc": "13443:4:17", + "nodeType": "YulTypedName", + "src": "13443:4:17", + "type": "" + } + ], + "src": "13277:419:17" + } + ] + }, + "contents": "{\n\n function array_length_t_string_memory_ptr(value) -> length {\n\n length := mload(value)\n\n }\n\n function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos {\n mstore(pos, length)\n updated_pos := add(pos, 0x20)\n }\n\n function copy_memory_to_memory_with_cleanup(src, dst, length) {\n let i := 0\n for { } lt(i, length) { i := add(i, 32) }\n {\n mstore(add(dst, i), mload(add(src, i)))\n }\n mstore(add(dst, length), 0)\n }\n\n function round_up_to_mul_of_32(value) -> result {\n result := and(add(value, 31), not(31))\n }\n\n function abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value, pos) -> end {\n let length := array_length_t_string_memory_ptr(value)\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length)\n copy_memory_to_memory_with_cleanup(add(value, 0x20), pos, length)\n end := add(pos, round_up_to_mul_of_32(length))\n }\n\n function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack_reversed(headStart , value0) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value0, tail)\n\n }\n\n function allocate_unbounded() -> memPtr {\n memPtr := mload(64)\n }\n\n function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() {\n revert(0, 0)\n }\n\n function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() {\n revert(0, 0)\n }\n\n function cleanup_t_uint160(value) -> cleaned {\n cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff)\n }\n\n function cleanup_t_address(value) -> cleaned {\n cleaned := cleanup_t_uint160(value)\n }\n\n function validator_revert_t_address(value) {\n if iszero(eq(value, cleanup_t_address(value))) { revert(0, 0) }\n }\n\n function abi_decode_t_address(offset, end) -> value {\n value := calldataload(offset)\n validator_revert_t_address(value)\n }\n\n function cleanup_t_uint256(value) -> cleaned {\n cleaned := value\n }\n\n function validator_revert_t_uint256(value) {\n if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) }\n }\n\n function abi_decode_t_uint256(offset, end) -> value {\n value := calldataload(offset)\n validator_revert_t_uint256(value)\n }\n\n function abi_decode_tuple_t_addresst_uint256(headStart, dataEnd) -> value0, value1 {\n if slt(sub(dataEnd, headStart), 64) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := 0\n\n value0 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n {\n\n let offset := 32\n\n value1 := abi_decode_t_uint256(add(headStart, offset), dataEnd)\n }\n\n }\n\n function cleanup_t_bool(value) -> cleaned {\n cleaned := iszero(iszero(value))\n }\n\n function abi_encode_t_bool_to_t_bool_fromStack(value, pos) {\n mstore(pos, cleanup_t_bool(value))\n }\n\n function abi_encode_tuple_t_bool__to_t_bool__fromStack_reversed(headStart , value0) -> tail {\n tail := add(headStart, 32)\n\n abi_encode_t_bool_to_t_bool_fromStack(value0, add(headStart, 0))\n\n }\n\n function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) {\n mstore(pos, cleanup_t_uint256(value))\n }\n\n function abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed(headStart , value0) -> tail {\n tail := add(headStart, 32)\n\n abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0))\n\n }\n\n function abi_decode_tuple_t_addresst_addresst_uint256(headStart, dataEnd) -> value0, value1, value2 {\n if slt(sub(dataEnd, headStart), 96) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := 0\n\n value0 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n {\n\n let offset := 32\n\n value1 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n {\n\n let offset := 64\n\n value2 := abi_decode_t_uint256(add(headStart, offset), dataEnd)\n }\n\n }\n\n function cleanup_t_uint8(value) -> cleaned {\n cleaned := and(value, 0xff)\n }\n\n function abi_encode_t_uint8_to_t_uint8_fromStack(value, pos) {\n mstore(pos, cleanup_t_uint8(value))\n }\n\n function abi_encode_tuple_t_uint8__to_t_uint8__fromStack_reversed(headStart , value0) -> tail {\n tail := add(headStart, 32)\n\n abi_encode_t_uint8_to_t_uint8_fromStack(value0, add(headStart, 0))\n\n }\n\n function abi_decode_tuple_t_address(headStart, dataEnd) -> value0 {\n if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := 0\n\n value0 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n }\n\n function abi_decode_tuple_t_addresst_address(headStart, dataEnd) -> value0, value1 {\n if slt(sub(dataEnd, headStart), 64) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := 0\n\n value0 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n {\n\n let offset := 32\n\n value1 := abi_decode_t_address(add(headStart, offset), dataEnd)\n }\n\n }\n\n function panic_error_0x22() {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x22)\n revert(0, 0x24)\n }\n\n function extract_byte_array_length(data) -> length {\n length := div(data, 2)\n let outOfPlaceEncoding := and(data, 1)\n if iszero(outOfPlaceEncoding) {\n length := and(length, 0x7f)\n }\n\n if eq(outOfPlaceEncoding, lt(length, 32)) {\n panic_error_0x22()\n }\n }\n\n function panic_error_0x11() {\n mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)\n mstore(4, 0x11)\n revert(0, 0x24)\n }\n\n function checked_add_t_uint256(x, y) -> sum {\n x := cleanup_t_uint256(x)\n y := cleanup_t_uint256(y)\n sum := add(x, y)\n\n if gt(x, sum) { panic_error_0x11() }\n\n }\n\n function store_literal_in_memory_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: decreased allowance below\")\n\n mstore(add(memPtr, 32), \" zero\")\n\n }\n\n function abi_encode_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 37)\n store_literal_in_memory_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_f8b476f7d28209d77d4a4ac1fe36b9f8259aa1bb6bddfa6e89de7e51615cf8a8_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: approve from the zero add\")\n\n mstore(add(memPtr, 32), \"ress\")\n\n }\n\n function abi_encode_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 36)\n store_literal_in_memory_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_c953f4879035ed60e766b34720f656aab5c697b141d924c283124ecedb91c208_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: approve to the zero addre\")\n\n mstore(add(memPtr, 32), \"ss\")\n\n }\n\n function abi_encode_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 34)\n store_literal_in_memory_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_24883cc5fe64ace9d0df1893501ecb93c77180f0ff69cca79affb3c316dc8029_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: insufficient allowance\")\n\n }\n\n function abi_encode_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 29)\n store_literal_in_memory_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe(pos)\n end := add(pos, 32)\n }\n\n function abi_encode_tuple_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_3b6607e091cba9325f958656d2b5e0622ab7dc0eac71a26ac788cb25bc19f4fe_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: transfer from the zero ad\")\n\n mstore(add(memPtr, 32), \"dress\")\n\n }\n\n function abi_encode_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 37)\n store_literal_in_memory_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_baecc556b46f4ed0f2b4cb599d60785ac8563dd2dc0a5bf12edea1c39e5e1fea_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: transfer to the zero addr\")\n\n mstore(add(memPtr, 32), \"ess\")\n\n }\n\n function abi_encode_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 35)\n store_literal_in_memory_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_0557e210f7a69a685100a7e4e3d0a7024c546085cee28910fd17d0b081d9516f_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n function store_literal_in_memory_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6(memPtr) {\n\n mstore(add(memPtr, 0), \"ERC20: transfer amount exceeds b\")\n\n mstore(add(memPtr, 32), \"alance\")\n\n }\n\n function abi_encode_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6_to_t_string_memory_ptr_fromStack(pos) -> end {\n pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, 38)\n store_literal_in_memory_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6(pos)\n end := add(pos, 64)\n }\n\n function abi_encode_tuple_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6__to_t_string_memory_ptr__fromStack_reversed(headStart ) -> tail {\n tail := add(headStart, 32)\n\n mstore(add(headStart, 0), sub(tail, headStart))\n tail := abi_encode_t_stringliteral_4107e8a8b9e94bf8ff83080ddec1c0bffe897ebc2241b89d44f66b3d274088b6_to_t_string_memory_ptr_fromStack( tail)\n\n }\n\n}\n", + "id": 17, + "language": "Yul", + "name": "#utility.yul" + } + ], + "immutableReferences": {}, + "linkReferences": {}, + "object": "608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063395093511161006f578063395093511461016557806370a082311461019557806395d89b41146101c5578063a457c2d7146101e3578063a9059cbb14610213578063dd62ed3e14610243576100a7565b806306fdde03146100ab578063095ea7b3146100c957806318160ddd146100f957806323b872dd14610117578063313ce56714610147575b5f80fd5b6100b3610273565b6040516100c09190610add565b60405180910390f35b6100e360048036038101906100de9190610b8e565b610303565b6040516100f09190610be6565b60405180910390f35b610101610325565b60405161010e9190610c0e565b60405180910390f35b610131600480360381019061012c9190610c27565b61032e565b60405161013e9190610be6565b60405180910390f35b61014f61035c565b60405161015c9190610c92565b60405180910390f35b61017f600480360381019061017a9190610b8e565b610364565b60405161018c9190610be6565b60405180910390f35b6101af60048036038101906101aa9190610cab565b61039a565b6040516101bc9190610c0e565b60405180910390f35b6101cd6103df565b6040516101da9190610add565b60405180910390f35b6101fd60048036038101906101f89190610b8e565b61046f565b60405161020a9190610be6565b60405180910390f35b61022d60048036038101906102289190610b8e565b6104e4565b60405161023a9190610be6565b60405180910390f35b61025d60048036038101906102589190610cd6565b610506565b60405161026a9190610c0e565b60405180910390f35b60606003805461028290610d41565b80601f01602080910402602001604051908101604052809291908181526020018280546102ae90610d41565b80156102f95780601f106102d0576101008083540402835291602001916102f9565b820191905f5260205f20905b8154815290600101906020018083116102dc57829003601f168201915b5050505050905090565b5f8061030d610588565b905061031a81858561058f565b600191505092915050565b5f600254905090565b5f80610338610588565b9050610345858285610752565b6103508585856107dd565b60019150509392505050565b5f6011905090565b5f8061036e610588565b905061038f8185856103808589610506565b61038a9190610d9e565b61058f565b600191505092915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6060600480546103ee90610d41565b80601f016020809104026020016040519081016040528092919081815260200182805461041a90610d41565b80156104655780601f1061043c57610100808354040283529160200191610465565b820191905f5260205f20905b81548152906001019060200180831161044857829003601f168201915b5050505050905090565b5f80610479610588565b90505f6104868286610506565b9050838110156104cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c290610e41565b60405180910390fd5b6104d8828686840361058f565b60019250505092915050565b5f806104ee610588565b90506104fb8185856107dd565b600191505092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036105fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f490610ecf565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361066b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066290610f5d565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107459190610c0e565b60405180910390a3505050565b5f61075d8484610506565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107d757818110156107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090610fc5565b60405180910390fd5b6107d6848484840361058f565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084290611053565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b0906110e1565b60405180910390fd5b6108c4838383610a49565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610947576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093e9061116f565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a309190610c0e565b60405180910390a3610a43848484610a4e565b50505050565b505050565b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a8a578082015181840152602081019050610a6f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aaf82610a53565b610ab98185610a5d565b9350610ac9818560208601610a6d565b610ad281610a95565b840191505092915050565b5f6020820190508181035f830152610af58184610aa5565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b2a82610b01565b9050919050565b610b3a81610b20565b8114610b44575f80fd5b50565b5f81359050610b5581610b31565b92915050565b5f819050919050565b610b6d81610b5b565b8114610b77575f80fd5b50565b5f81359050610b8881610b64565b92915050565b5f8060408385031215610ba457610ba3610afd565b5b5f610bb185828601610b47565b9250506020610bc285828601610b7a565b9150509250929050565b5f8115159050919050565b610be081610bcc565b82525050565b5f602082019050610bf95f830184610bd7565b92915050565b610c0881610b5b565b82525050565b5f602082019050610c215f830184610bff565b92915050565b5f805f60608486031215610c3e57610c3d610afd565b5b5f610c4b86828701610b47565b9350506020610c5c86828701610b47565b9250506040610c6d86828701610b7a565b9150509250925092565b5f60ff82169050919050565b610c8c81610c77565b82525050565b5f602082019050610ca55f830184610c83565b92915050565b5f60208284031215610cc057610cbf610afd565b5b5f610ccd84828501610b47565b91505092915050565b5f8060408385031215610cec57610ceb610afd565b5b5f610cf985828601610b47565b9250506020610d0a85828601610b47565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d5857607f821691505b602082108103610d6b57610d6a610d14565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610da882610b5b565b9150610db383610b5b565b9250828201905080821115610dcb57610dca610d71565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f775f8201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b5f610e2b602583610a5d565b9150610e3682610dd1565b604082019050919050565b5f6020820190508181035f830152610e5881610e1f565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f610eb9602483610a5d565b9150610ec482610e5f565b604082019050919050565b5f6020820190508181035f830152610ee681610ead565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f2061646472655f8201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b5f610f47602283610a5d565b9150610f5282610eed565b604082019050919050565b5f6020820190508181035f830152610f7481610f3b565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000005f82015250565b5f610faf601d83610a5d565b9150610fba82610f7b565b602082019050919050565b5f6020820190508181035f830152610fdc81610fa3565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f2061645f8201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b5f61103d602583610a5d565b915061104882610fe3565b604082019050919050565b5f6020820190508181035f83015261106a81611031565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6110cb602383610a5d565b91506110d682611071565b604082019050919050565b5f6020820190508181035f8301526110f8816110bf565b9050919050565b7f45524332303a207472616e7366657220616d6f756e74206578636565647320625f8201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b5f611159602683610a5d565b9150611164826110ff565b604082019050919050565b5f6020820190508181035f8301526111868161114d565b905091905056fea264697066735822122062680aa81bd47e484462a2becb3aeaae50eade823ecfad3c2cf3d21b8ba9f39a64736f6c63430008180033", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0xF JUMPI PUSH0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0xA7 JUMPI PUSH0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x39509351 GT PUSH2 0x6F JUMPI DUP1 PUSH4 0x39509351 EQ PUSH2 0x165 JUMPI DUP1 PUSH4 0x70A08231 EQ PUSH2 0x195 JUMPI DUP1 PUSH4 0x95D89B41 EQ PUSH2 0x1C5 JUMPI DUP1 PUSH4 0xA457C2D7 EQ PUSH2 0x1E3 JUMPI DUP1 PUSH4 0xA9059CBB EQ PUSH2 0x213 JUMPI DUP1 PUSH4 0xDD62ED3E EQ PUSH2 0x243 JUMPI PUSH2 0xA7 JUMP JUMPDEST DUP1 PUSH4 0x6FDDE03 EQ PUSH2 0xAB JUMPI DUP1 PUSH4 0x95EA7B3 EQ PUSH2 0xC9 JUMPI DUP1 PUSH4 0x18160DDD EQ PUSH2 0xF9 JUMPI DUP1 PUSH4 0x23B872DD EQ PUSH2 0x117 JUMPI DUP1 PUSH4 0x313CE567 EQ PUSH2 0x147 JUMPI JUMPDEST PUSH0 DUP1 REVERT JUMPDEST PUSH2 0xB3 PUSH2 0x273 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xC0 SWAP2 SWAP1 PUSH2 0xADD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0xE3 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0xDE SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x303 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0xF0 SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x101 PUSH2 0x325 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x10E SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x131 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x12C SWAP2 SWAP1 PUSH2 0xC27 JUMP JUMPDEST PUSH2 0x32E JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x13E SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x14F PUSH2 0x35C JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xC92 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x17F PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x17A SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x364 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x18C SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1AF PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x1AA SWAP2 SWAP1 PUSH2 0xCAB JUMP JUMPDEST PUSH2 0x39A JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x1BC SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1CD PUSH2 0x3DF JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x1DA SWAP2 SWAP1 PUSH2 0xADD JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1FD PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x1F8 SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x46F JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x20A SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x22D PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x228 SWAP2 SWAP1 PUSH2 0xB8E JUMP JUMPDEST PUSH2 0x4E4 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x23A SWAP2 SWAP1 PUSH2 0xBE6 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x25D PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x258 SWAP2 SWAP1 PUSH2 0xCD6 JUMP JUMPDEST PUSH2 0x506 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x26A SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 PUSH1 0x3 DUP1 SLOAD PUSH2 0x282 SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x2AE SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x2F9 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x2D0 JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x2F9 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH0 MSTORE PUSH1 0x20 PUSH0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x2DC JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x30D PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x31A DUP2 DUP6 DUP6 PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x2 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x338 PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x345 DUP6 DUP3 DUP6 PUSH2 0x752 JUMP JUMPDEST PUSH2 0x350 DUP6 DUP6 DUP6 PUSH2 0x7DD JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH0 PUSH1 0x11 SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x36E PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x38F DUP2 DUP6 DUP6 PUSH2 0x380 DUP6 DUP10 PUSH2 0x506 JUMP JUMPDEST PUSH2 0x38A SWAP2 SWAP1 PUSH2 0xD9E JUMP JUMPDEST PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x60 PUSH1 0x4 DUP1 SLOAD PUSH2 0x3EE SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 PUSH1 0x1F ADD PUSH1 0x20 DUP1 SWAP2 DIV MUL PUSH1 0x20 ADD PUSH1 0x40 MLOAD SWAP1 DUP2 ADD PUSH1 0x40 MSTORE DUP1 SWAP3 SWAP2 SWAP1 DUP2 DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP1 SLOAD PUSH2 0x41A SWAP1 PUSH2 0xD41 JUMP JUMPDEST DUP1 ISZERO PUSH2 0x465 JUMPI DUP1 PUSH1 0x1F LT PUSH2 0x43C JUMPI PUSH2 0x100 DUP1 DUP4 SLOAD DIV MUL DUP4 MSTORE SWAP2 PUSH1 0x20 ADD SWAP2 PUSH2 0x465 JUMP JUMPDEST DUP3 ADD SWAP2 SWAP1 PUSH0 MSTORE PUSH1 0x20 PUSH0 KECCAK256 SWAP1 JUMPDEST DUP2 SLOAD DUP2 MSTORE SWAP1 PUSH1 0x1 ADD SWAP1 PUSH1 0x20 ADD DUP1 DUP4 GT PUSH2 0x448 JUMPI DUP3 SWAP1 SUB PUSH1 0x1F AND DUP3 ADD SWAP2 JUMPDEST POP POP POP POP POP SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x479 PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH0 PUSH2 0x486 DUP3 DUP7 PUSH2 0x506 JUMP JUMPDEST SWAP1 POP DUP4 DUP2 LT ISZERO PUSH2 0x4CB JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x4C2 SWAP1 PUSH2 0xE41 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x4D8 DUP3 DUP7 DUP7 DUP5 SUB PUSH2 0x58F JUMP JUMPDEST PUSH1 0x1 SWAP3 POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH2 0x4EE PUSH2 0x588 JUMP JUMPDEST SWAP1 POP PUSH2 0x4FB DUP2 DUP6 DUP6 PUSH2 0x7DD JUMP JUMPDEST PUSH1 0x1 SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x1 PUSH0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 CALLER SWAP1 POP SWAP1 JUMP JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x5FD JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x5F4 SWAP1 PUSH2 0xECF JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x66B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x662 SWAP1 PUSH2 0xF5D JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP1 PUSH1 0x1 PUSH0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x8C5BE1E5EBEC7D5BD14F71427D1E84F3DD0314C0F7B2291E5B200AC8C7C3B925 DUP4 PUSH1 0x40 MLOAD PUSH2 0x745 SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 POP POP POP JUMP JUMPDEST PUSH0 PUSH2 0x75D DUP5 DUP5 PUSH2 0x506 JUMP JUMPDEST SWAP1 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 EQ PUSH2 0x7D7 JUMPI DUP2 DUP2 LT ISZERO PUSH2 0x7C9 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x7C0 SWAP1 PUSH2 0xFC5 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x7D6 DUP5 DUP5 DUP5 DUP5 SUB PUSH2 0x58F JUMP JUMPDEST JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x84B JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x842 SWAP1 PUSH2 0x1053 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SUB PUSH2 0x8B9 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x8B0 SWAP1 PUSH2 0x10E1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST PUSH2 0x8C4 DUP4 DUP4 DUP4 PUSH2 0xA49 JUMP JUMPDEST PUSH0 DUP1 PUSH0 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 SLOAD SWAP1 POP DUP2 DUP2 LT ISZERO PUSH2 0x947 JUMPI PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x93E SWAP1 PUSH2 0x116F JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST DUP2 DUP2 SUB PUSH0 DUP1 DUP7 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 DUP2 SWAP1 SSTORE POP DUP2 PUSH0 DUP1 DUP6 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH0 KECCAK256 PUSH0 DUP3 DUP3 SLOAD ADD SWAP3 POP POP DUP2 SWAP1 SSTORE POP DUP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP5 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0xDDF252AD1BE2C89B69C2B068FC378DAA952BA7F163C4A11628F55A4DF523B3EF DUP5 PUSH1 0x40 MLOAD PUSH2 0xA30 SWAP2 SWAP1 PUSH2 0xC0E JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG3 PUSH2 0xA43 DUP5 DUP5 DUP5 PUSH2 0xA4E JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST POP POP POP JUMP JUMPDEST PUSH0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xA8A JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0xA6F JUMP JUMPDEST PUSH0 DUP5 DUP5 ADD MSTORE POP POP POP POP JUMP JUMPDEST PUSH0 PUSH1 0x1F NOT PUSH1 0x1F DUP4 ADD AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH2 0xAAF DUP3 PUSH2 0xA53 JUMP JUMPDEST PUSH2 0xAB9 DUP2 DUP6 PUSH2 0xA5D JUMP JUMPDEST SWAP4 POP PUSH2 0xAC9 DUP2 DUP6 PUSH1 0x20 DUP7 ADD PUSH2 0xA6D JUMP JUMPDEST PUSH2 0xAD2 DUP2 PUSH2 0xA95 JUMP JUMPDEST DUP5 ADD SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xAF5 DUP2 DUP5 PUSH2 0xAA5 JUMP JUMPDEST SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 REVERT JUMPDEST PUSH0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH2 0xB2A DUP3 PUSH2 0xB01 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xB3A DUP2 PUSH2 0xB20 JUMP JUMPDEST DUP2 EQ PUSH2 0xB44 JUMPI PUSH0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xB55 DUP2 PUSH2 0xB31 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xB6D DUP2 PUSH2 0xB5B JUMP JUMPDEST DUP2 EQ PUSH2 0xB77 JUMPI PUSH0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xB88 DUP2 PUSH2 0xB64 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0xBA4 JUMPI PUSH2 0xBA3 PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xBB1 DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x20 PUSH2 0xBC2 DUP6 DUP3 DUP7 ADD PUSH2 0xB7A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH0 DUP2 ISZERO ISZERO SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xBE0 DUP2 PUSH2 0xBCC JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xBF9 PUSH0 DUP4 ADD DUP5 PUSH2 0xBD7 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xC08 DUP2 PUSH2 0xB5B JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xC21 PUSH0 DUP4 ADD DUP5 PUSH2 0xBFF JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH0 PUSH1 0x60 DUP5 DUP7 SUB SLT ISZERO PUSH2 0xC3E JUMPI PUSH2 0xC3D PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xC4B DUP7 DUP3 DUP8 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP4 POP POP PUSH1 0x20 PUSH2 0xC5C DUP7 DUP3 DUP8 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x40 PUSH2 0xC6D DUP7 DUP3 DUP8 ADD PUSH2 0xB7A JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 POP SWAP3 JUMP JUMPDEST PUSH0 PUSH1 0xFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xC8C DUP2 PUSH2 0xC77 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xCA5 PUSH0 DUP4 ADD DUP5 PUSH2 0xC83 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCC0 JUMPI PUSH2 0xCBF PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xCCD DUP5 DUP3 DUP6 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0xCEC JUMPI PUSH2 0xCEB PUSH2 0xAFD JUMP JUMPDEST JUMPDEST PUSH0 PUSH2 0xCF9 DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP3 POP POP PUSH1 0x20 PUSH2 0xD0A DUP6 DUP3 DUP7 ADD PUSH2 0xB47 JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x22 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH1 0x2 DUP3 DIV SWAP1 POP PUSH1 0x1 DUP3 AND DUP1 PUSH2 0xD58 JUMPI PUSH1 0x7F DUP3 AND SWAP2 POP JUMPDEST PUSH1 0x20 DUP3 LT DUP2 SUB PUSH2 0xD6B JUMPI PUSH2 0xD6A PUSH2 0xD14 JUMP JUMPDEST JUMPDEST POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH0 MSTORE PUSH1 0x11 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH0 REVERT JUMPDEST PUSH0 PUSH2 0xDA8 DUP3 PUSH2 0xB5B JUMP JUMPDEST SWAP2 POP PUSH2 0xDB3 DUP4 PUSH2 0xB5B JUMP JUMPDEST SWAP3 POP DUP3 DUP3 ADD SWAP1 POP DUP1 DUP3 GT ISZERO PUSH2 0xDCB JUMPI PUSH2 0xDCA PUSH2 0xD71 JUMP JUMPDEST JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH32 0x45524332303A2064656372656173656420616C6C6F77616E63652062656C6F77 PUSH0 DUP3 ADD MSTORE PUSH32 0x207A65726F000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xE2B PUSH1 0x25 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xE36 DUP3 PUSH2 0xDD1 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xE58 DUP2 PUSH2 0xE1F JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20617070726F76652066726F6D20746865207A65726F20616464 PUSH0 DUP3 ADD MSTORE PUSH32 0x7265737300000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xEB9 PUSH1 0x24 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xEC4 DUP3 PUSH2 0xE5F JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xEE6 DUP2 PUSH2 0xEAD JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20617070726F766520746F20746865207A65726F206164647265 PUSH0 DUP3 ADD MSTORE PUSH32 0x7373000000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xF47 PUSH1 0x22 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xF52 DUP3 PUSH2 0xEED JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xF74 DUP2 PUSH2 0xF3B JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A20696E73756666696369656E7420616C6C6F77616E6365000000 PUSH0 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0xFAF PUSH1 0x1D DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0xFBA DUP3 PUSH2 0xF7B JUMP JUMPDEST PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0xFDC DUP2 PUSH2 0xFA3 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E736665722066726F6D20746865207A65726F206164 PUSH0 DUP3 ADD MSTORE PUSH32 0x6472657373000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x103D PUSH1 0x25 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x1048 DUP3 PUSH2 0xFE3 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x106A DUP2 PUSH2 0x1031 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E7366657220746F20746865207A65726F2061646472 PUSH0 DUP3 ADD MSTORE PUSH32 0x6573730000000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x10CB PUSH1 0x23 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x10D6 DUP3 PUSH2 0x1071 JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x10F8 DUP2 PUSH2 0x10BF JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x45524332303A207472616E7366657220616D6F756E7420657863656564732062 PUSH0 DUP3 ADD MSTORE PUSH32 0x616C616E63650000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE POP JUMP JUMPDEST PUSH0 PUSH2 0x1159 PUSH1 0x26 DUP4 PUSH2 0xA5D JUMP JUMPDEST SWAP2 POP PUSH2 0x1164 DUP3 PUSH2 0x10FF JUMP JUMPDEST PUSH1 0x40 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH0 DUP4 ADD MSTORE PUSH2 0x1186 DUP2 PUSH2 0x114D JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 PUSH3 0x680AA8 SHL 0xD4 PUSH31 0x484462A2BECB3AEAAE50EADE823ECFAD3C2CF3D21B8BA9F39A64736F6C6343 STOP ADDMOD XOR STOP CALLER ", + "sourceMap": "128:420:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2158:98:0;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;4444:197;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;3255:106;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5203:256;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;455:91:9;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5854:234:0;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;3419:125;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2369:102;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;6575:427;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;3740:189;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;3987:149;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;2158:98;2212:13;2244:5;2237:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2158:98;:::o;4444:197::-;4527:4;4543:13;4559:12;:10;:12::i;:::-;4543:28;;4581:32;4590:5;4597:7;4606:6;4581:8;:32::i;:::-;4630:4;4623:11;;;4444:197;;;;:::o;3255:106::-;3316:7;3342:12;;3335:19;;3255:106;:::o;5203:256::-;5300:4;5316:15;5334:12;:10;:12::i;:::-;5316:30;;5356:38;5372:4;5378:7;5387:6;5356:15;:38::i;:::-;5404:27;5414:4;5420:2;5424:6;5404:9;:27::i;:::-;5448:4;5441:11;;;5203:256;;;;;:::o;455:91:9:-;513:5;537:2;530:9;;455:91;:::o;5854:234:0:-;5942:4;5958:13;5974:12;:10;:12::i;:::-;5958:28;;5996:64;6005:5;6012:7;6049:10;6021:25;6031:5;6038:7;6021:9;:25::i;:::-;:38;;;;:::i;:::-;5996:8;:64::i;:::-;6077:4;6070:11;;;5854:234;;;;:::o;3419:125::-;3493:7;3519:9;:18;3529:7;3519:18;;;;;;;;;;;;;;;;3512:25;;3419:125;;;:::o;2369:102::-;2425:13;2457:7;2450:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2369:102;:::o;6575:427::-;6668:4;6684:13;6700:12;:10;:12::i;:::-;6684:28;;6722:24;6749:25;6759:5;6766:7;6749:9;:25::i;:::-;6722:52;;6812:15;6792:16;:35;;6784:85;;;;;;;;;;;;:::i;:::-;;;;;;;;;6903:60;6912:5;6919:7;6947:15;6928:16;:34;6903:8;:60::i;:::-;6991:4;6984:11;;;;6575:427;;;;:::o;3740:189::-;3819:4;3835:13;3851:12;:10;:12::i;:::-;3835:28;;3873;3883:5;3890:2;3894:6;3873:9;:28::i;:::-;3918:4;3911:11;;;3740:189;;;;:::o;3987:149::-;4076:7;4102:11;:18;4114:5;4102:18;;;;;;;;;;;;;;;:27;4121:7;4102:27;;;;;;;;;;;;;;;;4095:34;;3987:149;;;;:::o;655:96:3:-;708:7;734:10;727:17;;655:96;:::o;10457:340:0:-;10575:1;10558:19;;:5;:19;;;10550:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;10655:1;10636:21;;:7;:21;;;10628:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;10737:6;10707:11;:18;10719:5;10707:18;;;;;;;;;;;;;;;:27;10726:7;10707:27;;;;;;;;;;;;;;;:36;;;;10774:7;10758:32;;10767:5;10758:32;;;10783:6;10758:32;;;;;;:::i;:::-;;;;;;;;10457:340;;;:::o;11078:411::-;11178:24;11205:25;11215:5;11222:7;11205:9;:25::i;:::-;11178:52;;11264:17;11244:16;:37;11240:243;;11325:6;11305:16;:26;;11297:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;11407:51;11416:5;11423:7;11451:6;11432:16;:25;11407:8;:51::i;:::-;11240:243;11168:321;11078:411;;;:::o;7456:788::-;7568:1;7552:18;;:4;:18;;;7544:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;7644:1;7630:16;;:2;:16;;;7622:64;;;;;;;;;;;;:::i;:::-;;;;;;;;;7697:38;7718:4;7724:2;7728:6;7697:20;:38::i;:::-;7746:19;7768:9;:15;7778:4;7768:15;;;;;;;;;;;;;;;;7746:37;;7816:6;7801:11;:21;;7793:72;;;;;;;;;;;;:::i;:::-;;;;;;;;;7931:6;7917:11;:20;7899:9;:15;7909:4;7899:15;;;;;;;;;;;;;;;:38;;;;8131:6;8114:9;:13;8124:2;8114:13;;;;;;;;;;;;;;;;:23;;;;;;;;;;;8178:2;8163:26;;8172:4;8163:26;;;8182:6;8163:26;;;;;;:::i;:::-;;;;;;;;8200:37;8220:4;8226:2;8230:6;8200:19;:37::i;:::-;7534:710;7456:788;;;:::o;12073:91::-;;;;:::o;12752:90::-;;;;:::o;7:99:17:-;59:6;93:5;87:12;77:22;;7:99;;;:::o;112:169::-;196:11;230:6;225:3;218:19;270:4;265:3;261:14;246:29;;112:169;;;;:::o;287:246::-;368:1;378:113;392:6;389:1;386:13;378:113;;;477:1;472:3;468:11;462:18;458:1;453:3;449:11;442:39;414:2;411:1;407:10;402:15;;378:113;;;525:1;516:6;511:3;507:16;500:27;349:184;287:246;;;:::o;539:102::-;580:6;631:2;627:7;622:2;615:5;611:14;607:28;597:38;;539:102;;;:::o;647:377::-;735:3;763:39;796:5;763:39;:::i;:::-;818:71;882:6;877:3;818:71;:::i;:::-;811:78;;898:65;956:6;951:3;944:4;937:5;933:16;898:65;:::i;:::-;988:29;1010:6;988:29;:::i;:::-;983:3;979:39;972:46;;739:285;647:377;;;;:::o;1030:313::-;1143:4;1181:2;1170:9;1166:18;1158:26;;1230:9;1224:4;1220:20;1216:1;1205:9;1201:17;1194:47;1258:78;1331:4;1322:6;1258:78;:::i;:::-;1250:86;;1030:313;;;;:::o;1430:117::-;1539:1;1536;1529:12;1676:126;1713:7;1753:42;1746:5;1742:54;1731:65;;1676:126;;;:::o;1808:96::-;1845:7;1874:24;1892:5;1874:24;:::i;:::-;1863:35;;1808:96;;;:::o;1910:122::-;1983:24;2001:5;1983:24;:::i;:::-;1976:5;1973:35;1963:63;;2022:1;2019;2012:12;1963:63;1910:122;:::o;2038:139::-;2084:5;2122:6;2109:20;2100:29;;2138:33;2165:5;2138:33;:::i;:::-;2038:139;;;;:::o;2183:77::-;2220:7;2249:5;2238:16;;2183:77;;;:::o;2266:122::-;2339:24;2357:5;2339:24;:::i;:::-;2332:5;2329:35;2319:63;;2378:1;2375;2368:12;2319:63;2266:122;:::o;2394:139::-;2440:5;2478:6;2465:20;2456:29;;2494:33;2521:5;2494:33;:::i;:::-;2394:139;;;;:::o;2539:474::-;2607:6;2615;2664:2;2652:9;2643:7;2639:23;2635:32;2632:119;;;2670:79;;:::i;:::-;2632:119;2790:1;2815:53;2860:7;2851:6;2840:9;2836:22;2815:53;:::i;:::-;2805:63;;2761:117;2917:2;2943:53;2988:7;2979:6;2968:9;2964:22;2943:53;:::i;:::-;2933:63;;2888:118;2539:474;;;;;:::o;3019:90::-;3053:7;3096:5;3089:13;3082:21;3071:32;;3019:90;;;:::o;3115:109::-;3196:21;3211:5;3196:21;:::i;:::-;3191:3;3184:34;3115:109;;:::o;3230:210::-;3317:4;3355:2;3344:9;3340:18;3332:26;;3368:65;3430:1;3419:9;3415:17;3406:6;3368:65;:::i;:::-;3230:210;;;;:::o;3446:118::-;3533:24;3551:5;3533:24;:::i;:::-;3528:3;3521:37;3446:118;;:::o;3570:222::-;3663:4;3701:2;3690:9;3686:18;3678:26;;3714:71;3782:1;3771:9;3767:17;3758:6;3714:71;:::i;:::-;3570:222;;;;:::o;3798:619::-;3875:6;3883;3891;3940:2;3928:9;3919:7;3915:23;3911:32;3908:119;;;3946:79;;:::i;:::-;3908:119;4066:1;4091:53;4136:7;4127:6;4116:9;4112:22;4091:53;:::i;:::-;4081:63;;4037:117;4193:2;4219:53;4264:7;4255:6;4244:9;4240:22;4219:53;:::i;:::-;4209:63;;4164:118;4321:2;4347:53;4392:7;4383:6;4372:9;4368:22;4347:53;:::i;:::-;4337:63;;4292:118;3798:619;;;;;:::o;4423:86::-;4458:7;4498:4;4491:5;4487:16;4476:27;;4423:86;;;:::o;4515:112::-;4598:22;4614:5;4598:22;:::i;:::-;4593:3;4586:35;4515:112;;:::o;4633:214::-;4722:4;4760:2;4749:9;4745:18;4737:26;;4773:67;4837:1;4826:9;4822:17;4813:6;4773:67;:::i;:::-;4633:214;;;;:::o;4853:329::-;4912:6;4961:2;4949:9;4940:7;4936:23;4932:32;4929:119;;;4967:79;;:::i;:::-;4929:119;5087:1;5112:53;5157:7;5148:6;5137:9;5133:22;5112:53;:::i;:::-;5102:63;;5058:117;4853:329;;;;:::o;5188:474::-;5256:6;5264;5313:2;5301:9;5292:7;5288:23;5284:32;5281:119;;;5319:79;;:::i;:::-;5281:119;5439:1;5464:53;5509:7;5500:6;5489:9;5485:22;5464:53;:::i;:::-;5454:63;;5410:117;5566:2;5592:53;5637:7;5628:6;5617:9;5613:22;5592:53;:::i;:::-;5582:63;;5537:118;5188:474;;;;;:::o;5668:180::-;5716:77;5713:1;5706:88;5813:4;5810:1;5803:15;5837:4;5834:1;5827:15;5854:320;5898:6;5935:1;5929:4;5925:12;5915:22;;5982:1;5976:4;5972:12;6003:18;5993:81;;6059:4;6051:6;6047:17;6037:27;;5993:81;6121:2;6113:6;6110:14;6090:18;6087:38;6084:84;;6140:18;;:::i;:::-;6084:84;5905:269;5854:320;;;:::o;6180:180::-;6228:77;6225:1;6218:88;6325:4;6322:1;6315:15;6349:4;6346:1;6339:15;6366:191;6406:3;6425:20;6443:1;6425:20;:::i;:::-;6420:25;;6459:20;6477:1;6459:20;:::i;:::-;6454:25;;6502:1;6499;6495:9;6488:16;;6523:3;6520:1;6517:10;6514:36;;;6530:18;;:::i;:::-;6514:36;6366:191;;;;:::o;6563:224::-;6703:34;6699:1;6691:6;6687:14;6680:58;6772:7;6767:2;6759:6;6755:15;6748:32;6563:224;:::o;6793:366::-;6935:3;6956:67;7020:2;7015:3;6956:67;:::i;:::-;6949:74;;7032:93;7121:3;7032:93;:::i;:::-;7150:2;7145:3;7141:12;7134:19;;6793:366;;;:::o;7165:419::-;7331:4;7369:2;7358:9;7354:18;7346:26;;7418:9;7412:4;7408:20;7404:1;7393:9;7389:17;7382:47;7446:131;7572:4;7446:131;:::i;:::-;7438:139;;7165:419;;;:::o;7590:223::-;7730:34;7726:1;7718:6;7714:14;7707:58;7799:6;7794:2;7786:6;7782:15;7775:31;7590:223;:::o;7819:366::-;7961:3;7982:67;8046:2;8041:3;7982:67;:::i;:::-;7975:74;;8058:93;8147:3;8058:93;:::i;:::-;8176:2;8171:3;8167:12;8160:19;;7819:366;;;:::o;8191:419::-;8357:4;8395:2;8384:9;8380:18;8372:26;;8444:9;8438:4;8434:20;8430:1;8419:9;8415:17;8408:47;8472:131;8598:4;8472:131;:::i;:::-;8464:139;;8191:419;;;:::o;8616:221::-;8756:34;8752:1;8744:6;8740:14;8733:58;8825:4;8820:2;8812:6;8808:15;8801:29;8616:221;:::o;8843:366::-;8985:3;9006:67;9070:2;9065:3;9006:67;:::i;:::-;8999:74;;9082:93;9171:3;9082:93;:::i;:::-;9200:2;9195:3;9191:12;9184:19;;8843:366;;;:::o;9215:419::-;9381:4;9419:2;9408:9;9404:18;9396:26;;9468:9;9462:4;9458:20;9454:1;9443:9;9439:17;9432:47;9496:131;9622:4;9496:131;:::i;:::-;9488:139;;9215:419;;;:::o;9640:179::-;9780:31;9776:1;9768:6;9764:14;9757:55;9640:179;:::o;9825:366::-;9967:3;9988:67;10052:2;10047:3;9988:67;:::i;:::-;9981:74;;10064:93;10153:3;10064:93;:::i;:::-;10182:2;10177:3;10173:12;10166:19;;9825:366;;;:::o;10197:419::-;10363:4;10401:2;10390:9;10386:18;10378:26;;10450:9;10444:4;10440:20;10436:1;10425:9;10421:17;10414:47;10478:131;10604:4;10478:131;:::i;:::-;10470:139;;10197:419;;;:::o;10622:224::-;10762:34;10758:1;10750:6;10746:14;10739:58;10831:7;10826:2;10818:6;10814:15;10807:32;10622:224;:::o;10852:366::-;10994:3;11015:67;11079:2;11074:3;11015:67;:::i;:::-;11008:74;;11091:93;11180:3;11091:93;:::i;:::-;11209:2;11204:3;11200:12;11193:19;;10852:366;;;:::o;11224:419::-;11390:4;11428:2;11417:9;11413:18;11405:26;;11477:9;11471:4;11467:20;11463:1;11452:9;11448:17;11441:47;11505:131;11631:4;11505:131;:::i;:::-;11497:139;;11224:419;;;:::o;11649:222::-;11789:34;11785:1;11777:6;11773:14;11766:58;11858:5;11853:2;11845:6;11841:15;11834:30;11649:222;:::o;11877:366::-;12019:3;12040:67;12104:2;12099:3;12040:67;:::i;:::-;12033:74;;12116:93;12205:3;12116:93;:::i;:::-;12234:2;12229:3;12225:12;12218:19;;11877:366;;;:::o;12249:419::-;12415:4;12453:2;12442:9;12438:18;12430:26;;12502:9;12496:4;12492:20;12488:1;12477:9;12473:17;12466:47;12530:131;12656:4;12530:131;:::i;:::-;12522:139;;12249:419;;;:::o;12674:225::-;12814:34;12810:1;12802:6;12798:14;12791:58;12883:8;12878:2;12870:6;12866:15;12859:33;12674:225;:::o;12905:366::-;13047:3;13068:67;13132:2;13127:3;13068:67;:::i;:::-;13061:74;;13144:93;13233:3;13144:93;:::i;:::-;13262:2;13257:3;13253:12;13246:19;;12905:366;;;:::o;13277:419::-;13443:4;13481:2;13470:9;13466:18;13458:26;;13530:9;13524:4;13520:20;13516:1;13505:9;13501:17;13494:47;13558:131;13684:4;13558:131;:::i;:::-;13550:139;;13277:419;;;:::o" + } + }, + "bytecode": "608060405234801562000010575f80fd5b5060405180608001604052806058815260200162001856605891396040518060400160405280600981526020017f54657374546f6b656e0000000000000000000000000000000000000000000000815250816003908162000072919062000490565b50806004908162000084919062000490565b505050620000b773100000000000000000000000000000000000000169152d02c7e14af6800000620000bd60201b60201c565b62000685565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036200012e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200012590620005d2565b60405180910390fd5b620001415f83836200022260201b60201c565b8060025f8282546200015491906200061f565b92505081905550805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508173ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516200020391906200066a565b60405180910390a36200021e5f83836200022760201b60201c565b5050565b505050565b505050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002a857607f821691505b602082108103620002be57620002bd62000263565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003227fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002e5565b6200032e8683620002e5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000378620003726200036c8462000346565b6200034f565b62000346565b9050919050565b5f819050919050565b620003938362000358565b620003ab620003a2826200037f565b848454620002f1565b825550505050565b5f90565b620003c1620003b3565b620003ce81848462000388565b505050565b5b81811015620003f557620003e95f82620003b7565b600181019050620003d4565b5050565b601f82111562000444576200040e81620002c4565b6200041984620002d6565b8101602085101562000429578190505b620004416200043885620002d6565b830182620003d3565b50505b505050565b5f82821c905092915050565b5f620004665f198460080262000449565b1980831691505092915050565b5f62000480838362000455565b9150826002028217905092915050565b6200049b826200022c565b67ffffffffffffffff811115620004b757620004b662000236565b5b620004c3825462000290565b620004d0828285620003f9565b5f60209050601f83116001811462000506575f8415620004f1578287015190505b620004fd858262000473565b8655506200056c565b601f1984166200051686620002c4565b5f5b828110156200053f5784890151825560018201915060208501945060208101905062000518565b868310156200055f57848901516200055b601f89168262000455565b8355505b6001600288020188555050505b505050505050565b5f82825260208201905092915050565b7f45524332303a206d696e7420746f20746865207a65726f2061646472657373005f82015250565b5f620005ba601f8362000574565b9150620005c78262000584565b602082019050919050565b5f6020820190508181035f830152620005eb81620005ac565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6200062b8262000346565b9150620006388362000346565b9250828201905080821115620006535762000652620005f2565b5b92915050565b620006648162000346565b82525050565b5f6020820190506200067f5f83018462000659565b92915050565b6111c380620006935f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063395093511161006f578063395093511461016557806370a082311461019557806395d89b41146101c5578063a457c2d7146101e3578063a9059cbb14610213578063dd62ed3e14610243576100a7565b806306fdde03146100ab578063095ea7b3146100c957806318160ddd146100f957806323b872dd14610117578063313ce56714610147575b5f80fd5b6100b3610273565b6040516100c09190610add565b60405180910390f35b6100e360048036038101906100de9190610b8e565b610303565b6040516100f09190610be6565b60405180910390f35b610101610325565b60405161010e9190610c0e565b60405180910390f35b610131600480360381019061012c9190610c27565b61032e565b60405161013e9190610be6565b60405180910390f35b61014f61035c565b60405161015c9190610c92565b60405180910390f35b61017f600480360381019061017a9190610b8e565b610364565b60405161018c9190610be6565b60405180910390f35b6101af60048036038101906101aa9190610cab565b61039a565b6040516101bc9190610c0e565b60405180910390f35b6101cd6103df565b6040516101da9190610add565b60405180910390f35b6101fd60048036038101906101f89190610b8e565b61046f565b60405161020a9190610be6565b60405180910390f35b61022d60048036038101906102289190610b8e565b6104e4565b60405161023a9190610be6565b60405180910390f35b61025d60048036038101906102589190610cd6565b610506565b60405161026a9190610c0e565b60405180910390f35b60606003805461028290610d41565b80601f01602080910402602001604051908101604052809291908181526020018280546102ae90610d41565b80156102f95780601f106102d0576101008083540402835291602001916102f9565b820191905f5260205f20905b8154815290600101906020018083116102dc57829003601f168201915b5050505050905090565b5f8061030d610588565b905061031a81858561058f565b600191505092915050565b5f600254905090565b5f80610338610588565b9050610345858285610752565b6103508585856107dd565b60019150509392505050565b5f6011905090565b5f8061036e610588565b905061038f8185856103808589610506565b61038a9190610d9e565b61058f565b600191505092915050565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6060600480546103ee90610d41565b80601f016020809104026020016040519081016040528092919081815260200182805461041a90610d41565b80156104655780601f1061043c57610100808354040283529160200191610465565b820191905f5260205f20905b81548152906001019060200180831161044857829003601f168201915b5050505050905090565b5f80610479610588565b90505f6104868286610506565b9050838110156104cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104c290610e41565b60405180910390fd5b6104d8828686840361058f565b60019250505092915050565b5f806104ee610588565b90506104fb8185856107dd565b600191505092915050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036105fd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105f490610ecf565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361066b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161066290610f5d565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516107459190610c0e565b60405180910390a3505050565b5f61075d8484610506565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146107d757818110156107c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c090610fc5565b60405180910390fd5b6107d6848484840361058f565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361084b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084290611053565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b0906110e1565b60405180910390fd5b6108c4838383610a49565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610947576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093e9061116f565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550815f808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610a309190610c0e565b60405180910390a3610a43848484610a4e565b50505050565b505050565b505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a8a578082015181840152602081019050610a6f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aaf82610a53565b610ab98185610a5d565b9350610ac9818560208601610a6d565b610ad281610a95565b840191505092915050565b5f6020820190508181035f830152610af58184610aa5565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b2a82610b01565b9050919050565b610b3a81610b20565b8114610b44575f80fd5b50565b5f81359050610b5581610b31565b92915050565b5f819050919050565b610b6d81610b5b565b8114610b77575f80fd5b50565b5f81359050610b8881610b64565b92915050565b5f8060408385031215610ba457610ba3610afd565b5b5f610bb185828601610b47565b9250506020610bc285828601610b7a565b9150509250929050565b5f8115159050919050565b610be081610bcc565b82525050565b5f602082019050610bf95f830184610bd7565b92915050565b610c0881610b5b565b82525050565b5f602082019050610c215f830184610bff565b92915050565b5f805f60608486031215610c3e57610c3d610afd565b5b5f610c4b86828701610b47565b9350506020610c5c86828701610b47565b9250506040610c6d86828701610b7a565b9150509250925092565b5f60ff82169050919050565b610c8c81610c77565b82525050565b5f602082019050610ca55f830184610c83565b92915050565b5f60208284031215610cc057610cbf610afd565b5b5f610ccd84828501610b47565b91505092915050565b5f8060408385031215610cec57610ceb610afd565b5b5f610cf985828601610b47565b9250506020610d0a85828601610b47565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610d5857607f821691505b602082108103610d6b57610d6a610d14565b5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610da882610b5b565b9150610db383610b5b565b9250828201905080821115610dcb57610dca610d71565b5b92915050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f775f8201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b5f610e2b602583610a5d565b9150610e3682610dd1565b604082019050919050565b5f6020820190508181035f830152610e5881610e1f565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164645f8201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b5f610eb9602483610a5d565b9150610ec482610e5f565b604082019050919050565b5f6020820190508181035f830152610ee681610ead565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f2061646472655f8201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b5f610f47602283610a5d565b9150610f5282610eed565b604082019050919050565b5f6020820190508181035f830152610f7481610f3b565b9050919050565b7f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000005f82015250565b5f610faf601d83610a5d565b9150610fba82610f7b565b602082019050919050565b5f6020820190508181035f830152610fdc81610fa3565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f2061645f8201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b5f61103d602583610a5d565b915061104882610fe3565b604082019050919050565b5f6020820190508181035f83015261106a81611031565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f6110cb602383610a5d565b91506110d682611071565b604082019050919050565b5f6020820190508181035f8301526110f8816110bf565b9050919050565b7f45524332303a207472616e7366657220616d6f756e74206578636565647320625f8201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b5f611159602683610a5d565b9150611164826110ff565b604082019050919050565b5f6020820190508181035f8301526111868161114d565b905091905056fea264697066735822122062680aa81bd47e484462a2becb3aeaae50eade823ecfad3c2cf3d21b8ba9f39a64736f6c634300081800336c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d652c206c6f6e6720737472696e67206e616d65" +} \ No newline at end of file diff --git a/node/tests/data/Erc20DemoContract2.sol b/node/tests/data/Erc20DemoContract2.sol new file mode 100644 index 00000000..57149d6a --- /dev/null +++ b/node/tests/data/Erc20DemoContract2.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +pragma solidity ^0.8.2; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract Erc20DemoContract2 is ERC20 { + constructor() ERC20("long string name, long string name, long string name, long string name, long string name", "TestToken") { + // mint alice 100_000_000_000_000_000_000_000 + _mint(0x1000000000000000000000000000000000000001, 100_000_000_000_000_000_000_000); + } + + function decimals() public view virtual override returns (uint8) { + return 17; + } +} From 130cc873b1c18a7ce96a6d9dc363e117ec91c837 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Thu, 30 May 2024 16:54:55 +0800 Subject: [PATCH 26/27] clean code --- pallet/currencies/src/lib.rs | 34 ---------------------------------- pallet/erc-20/src/lib.rs | 22 ++++++---------------- primitives/src/currency.rs | 5 +++-- primitives/src/evm.rs | 18 ++---------------- 4 files changed, 11 insertions(+), 68 deletions(-) diff --git a/pallet/currencies/src/lib.rs b/pallet/currencies/src/lib.rs index f6fbb13e..dd1fad47 100644 --- a/pallet/currencies/src/lib.rs +++ b/pallet/currencies/src/lib.rs @@ -115,10 +115,6 @@ pub mod module { /// Weight information for extrinsics in this module. type WeightInfo: WeightInfo; - /// Used as temporary account for ERC20 token `withdraw` and `deposit`. - // #[pallet::constant] - // type Erc20HoldingAccount: Get; - /// Mapping from address to account id. type AddressMapping: AccountMapping; type EVMBridge: EVMBridgeTrait>; @@ -138,36 +134,6 @@ pub mod module { DepositFailed, } - // #[pallet::event] - // #[pallet::generate_deposit(pub(super) fn deposit_event)] - // pub enum Event { - // /// Currency transfer success. - // Transferred { - // currency_id: CurrencyId, - // from: T::AccountId, - // to: T::AccountId, - // amount: BalanceOf, - // }, - // /// Withdrawn some balances from an account - // Withdrawn { - // currency_id: CurrencyId, - // who: T::AccountId, - // amount: BalanceOf, - // }, - // /// Deposited some balance into an account - // Deposited { - // currency_id: CurrencyId, - // who: T::AccountId, - // amount: BalanceOf, - // }, - // /// Dust swept. - // DustSwept { - // currency_id: CurrencyId, - // who: T::AccountId, - // amount: BalanceOf, - // }, - // } - #[pallet::pallet] pub struct Pallet(_); diff --git a/pallet/erc-20/src/lib.rs b/pallet/erc-20/src/lib.rs index 3b4e8e82..f9074725 100644 --- a/pallet/erc-20/src/lib.rs +++ b/pallet/erc-20/src/lib.rs @@ -19,19 +19,15 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::unused_unit)] -use astar_primitives::xvm::{CallResult, FailureReason}; +use astar_primitives::xvm::{CallResult, Context, FailureReason, VmId, XvmCall}; use ethereum_types::BigEndianHash; use frame_support::{ - dispatch::DispatchResult, pallet_prelude::*, traits::ReservableCurrency, PalletId, + dispatch::DispatchResult, + pallet_prelude::*, + traits::{Currency, ReservableCurrency}, + PalletId, }; use frame_system::pallet_prelude::*; -// use module_evm::{ExitReason, ExitSucceed}; -// use module_support::{ -// evm::limits::{erc20, liquidation}, -// EVMBridge as EVMBridgeTrait, ExecutionMode, Context, LiquidationEvmBridge as LiquidationEvmBridgeT, EVM, -// }; -use astar_primitives::xvm::{Context, VmId, XvmCall}; -use frame_support::traits::Currency; use ggx_primitives::evm::EVMBridgeTrait; use hex_literal::hex; use sp_core::{H160, H256, U256}; @@ -39,7 +35,6 @@ use sp_runtime::{ArithmeticError, DispatchError, SaturatedConversion}; use sp_std::{vec, vec::Vec}; type AccountIdOf = ::AccountId; -//type BalanceOf = <::EVM as EVM>>::Balance; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -55,7 +50,7 @@ pub mod module { /// EvmBridge module trait #[pallet::config] pub trait Config: frame_system::Config { - /// The currency mechanism. //todo need replace to EVM> + /// The currency mechanism. type Currency: ReservableCurrency; #[pallet::constant] @@ -143,11 +138,6 @@ impl EVMBridgeTrait, BalanceOf> for EVMBridge { Some(storage_limit), ); - let _used_weight = match &call_result { - Ok(s) => s.used_weight, - Err(f) => f.used_weight, - }; - Pallet::::handle_exit_reason(call_result.clone())?; if let Ok(call_output) = call_result { diff --git a/primitives/src/currency.rs b/primitives/src/currency.rs index fa10eec6..c6dbb194 100644 --- a/primitives/src/currency.rs +++ b/primitives/src/currency.rs @@ -1,15 +1,16 @@ #![allow(clippy::from_over_into)] +use crate::evm::EvmAddress; use bstringify::bstringify; use core::ops::Range; use num_enum::{IntoPrimitive, TryFromPrimitive}; use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_core::U256; use sp_runtime::RuntimeDebug; use sp_std::prelude::*; use serde::{Deserialize, Serialize}; -pub type EvmAddress = sp_core::H160; pub type ForeignAssetId = u16; pub type Erc20Id = u32; pub type TokenId = u8; @@ -171,7 +172,7 @@ pub trait TokenInfo { pub enum CurrencyId { Token(TokenSymbol), Erc20(EvmAddress), - Erc1155(EvmAddress, u128), + Erc1155(EvmAddress, U256), ForeignAsset(ForeignAssetId), } diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index 5ccde676..7c4fbc18 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -20,29 +20,15 @@ pub trait EVMBridgeTrait { fn balance_of( context: Context, contract: EvmAddress, - from: AccountId, + caller: AccountId, address: EvmAddress, ) -> Result; /// Execute ERC20.transfer(address, uint256) to transfer value to `to` fn transfer( context: Context, contract: EvmAddress, - from: AccountId, + caller: AccountId, to: EvmAddress, value: Balance, ) -> DispatchResult; - // /// Get the real origin account and charge storage rent from the origin. - // fn get_origin() -> Option; - // /// Set the EVM origin - // fn set_origin(origin: AccountId); - // /// Kill the EVM origin - // fn kill_origin(); - // /// Push new EVM origin in xcm - // fn push_xcm_origin(origin: AccountId); - // /// Pop EVM origin in xcm - // fn pop_xcm_origin(); - // /// Kill the EVM origin in xcm - // fn kill_xcm_origin(); - // /// Get the real origin account or xcm origin and charge storage rent from the origin. - // fn get_real_or_xcm_origin() -> Option; } From 3a7625e64090c256685569db2c555fcb20b626e9 Mon Sep 17 00:00:00 2001 From: Li Smith Date: Thu, 30 May 2024 18:59:56 +0800 Subject: [PATCH 27/27] update test metadata --- .../scale/eth_light_client_brooklyn.scale | Bin 372253 -> 372254 bytes .../data/scale/eth_light_client_sydney.scale | Bin 372239 -> 372240 bytes pallet/dex/src/mock.rs | 1 + pallet/dex/src/tests.rs | 2 ++ pallet/erc-20/src/lib.rs | 14 +++++++++++++- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/node/tests/data/scale/eth_light_client_brooklyn.scale b/node/tests/data/scale/eth_light_client_brooklyn.scale index 8b0abb6bf0bbacefe132a08a9a3d470b61b98b87..2f52286665fa9f7707ec5657f56a03abe0e4570a 100644 GIT binary patch delta 36 rcmbPxM{M35v4$4LEld~gaTu~N3WOS&nzdiQ#{|U8+pphaaXSwH7<>=Q delta 35 qcmbPtM{MpLv4$4LEld~gu}d%tlo}dYwBNYL1jNkSZ`@;XI}ZR6eh EVMBridgeTrait, BalanceOf> for EVMBridge { Some(storage_limit), ); - Pallet::::handle_exit_reason(call_result)?; + Pallet::::handle_exit_reason(call_result.clone())?; + + // return value is true. + let mut bytes = [0u8; 32]; + U256::from(1).to_big_endian(&mut bytes); + + if let Ok(call_output) = call_result { + // Check return value to make sure not calling on empty contracts. + ensure!( + !call_output.output.is_empty() && call_output.output == bytes, + Error::::InvalidReturnValue + ); + } Ok(()) }