diff --git a/Cargo.lock b/Cargo.lock index 7fc3c12..ec5c708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1011,6 +1011,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "common-path" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" + [[package]] name = "concurrent-queue" version = "2.3.0" @@ -1367,6 +1373,24 @@ dependencies = [ "xcm", ] +[[package]] +name = "cumulus-primitives-utility" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v1.0.0#0d17cf6bef320f156f2859d6d2b0abd4154ae1d5" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "log", + "parity-scale-codec", + "polkadot-runtime-common", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -1735,6 +1759,32 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "docify" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1b04e6ef3d21119d3eb7b032bca17f99fe041e9c072f30f32cc0e1a2b1f3c4" +dependencies = [ + "docify_macros", +] + +[[package]] +name = "docify_macros" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5610df7f2acf89a1bb5d1a66ae56b1c7fcdcfe3948856fb3ace3f644d70eb7" +dependencies = [ + "common-path", + "derive-syn-parse", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "syn 2.0.38", + "termcolor", + "walkdir", +] + [[package]] name = "downcast" version = "0.11.0" @@ -1924,6 +1974,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "enumn" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -2276,6 +2337,34 @@ dependencies = [ "thousands", ] +[[package]] +name = "frame-election-provider-solution-type" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "frame-election-provider-support" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-election-provider-solution-type", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-npos-elections", + "sp-runtime", + "sp-std", +] + [[package]] name = "frame-executive" version = "4.0.0-dev" @@ -4830,6 +4919,22 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "pallet-asset-tx-payment" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-assets" version = "4.0.0-dev" @@ -4861,6 +4966,22 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-authority-discovery" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-authority-discovery", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-authorship" version = "4.0.0-dev" @@ -4875,6 +4996,30 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-babe" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" @@ -4890,6 +5035,80 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-collator-selection" +version = "3.0.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v1.0.0#0d17cf6bef320f156f2859d6d2b0abd4154ae1d5" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-election-provider-multi-phase" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-election-provider-support-benchmarking", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std", + "strum", +] + +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-system", + "parity-scale-codec", + "sp-npos-elections", + "sp-runtime", +] + +[[package]] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + [[package]] name = "pallet-grandpa" version = "4.0.0-dev" @@ -4927,6 +5146,25 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-message-queue" +version = "7.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-weights", +] + [[package]] name = "pallet-parachain-info" version = "0.1.0" @@ -4960,6 +5198,37 @@ dependencies = [ "sp-trie", ] +[[package]] +name = "pallet-staking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", +] + +[[package]] +name = "pallet-staking-reward-fn" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "log", + "sp-arithmetic", +] + [[package]] name = "pallet-sudo" version = "4.0.0-dev" @@ -5037,6 +5306,67 @@ dependencies = [ "sp-weights", ] +[[package]] +name = "pallet-treasury" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "pallet-vesting" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "parachains-common" +version = "1.0.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v1.0.0#0d17cf6bef320f156f2859d6d2b0abd4154ae1d5" +dependencies = [ + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-support", + "frame-system", + "num-traits", + "pallet-asset-tx-payment", + "pallet-assets", + "pallet-authorship", + "pallet-balances", + "pallet-collator-selection", + "parity-scale-codec", + "polkadot-primitives", + "scale-info", + "sp-consensus-aura", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "parity-db" version = "0.4.11" @@ -5390,6 +5720,104 @@ dependencies = [ "sp-std", ] +[[package]] +name = "polkadot-runtime-common" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot?branch=release-v1.0.0#c9ec8c5a15959ce711bb60aa79add58f560d61e9" +dependencies = [ + "bitvec", + "frame-election-provider-support", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "libsecp256k1", + "log", + "pallet-authorship", + "pallet-balances", + "pallet-election-provider-multi-phase", + "pallet-fast-unstake", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-fn", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-vesting", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "slot-range-helper", + "sp-api", + "sp-core", + "sp-inherents", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "static_assertions", + "xcm", +] + +[[package]] +name = "polkadot-runtime-metrics" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot?branch=release-v1.0.0#c9ec8c5a15959ce711bb60aa79add58f560d61e9" +dependencies = [ + "bs58", + "parity-scale-codec", + "polkadot-primitives", + "sp-std", + "sp-tracing", +] + +[[package]] +name = "polkadot-runtime-parachains" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot?branch=release-v1.0.0#c9ec8c5a15959ce711bb60aa79add58f560d61e9" +dependencies = [ + "bitflags 1.3.2", + "bitvec", + "derive_more", + "frame-support", + "frame-system", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-message-queue", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "pallet-vesting", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-metrics", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rustc-hex", + "scale-info", + "serde", + "sp-api", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std", + "xcm", + "xcm-executor", +] + [[package]] name = "polling" version = "2.8.0" @@ -7636,6 +8064,18 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" +[[package]] +name = "slot-range-helper" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot?branch=release-v1.0.0#c9ec8c5a15959ce711bb60aa79add58f560d61e9" +dependencies = [ + "enumn", + "parity-scale-codec", + "paste", + "sp-runtime", + "sp-std", +] + [[package]] name = "smallvec" version = "1.11.1" @@ -8067,6 +8507,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "sp-npos-elections" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "sp-offchain" version = "4.0.0-dev" @@ -8656,6 +9110,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-timestamp", + "parachains-common", "parity-scale-codec", "polkadot-parachain", "primitive-types", diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index 26d65ae..7d177c6 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -60,6 +60,8 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "releas xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v1.0.0" } polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "release-v1.0.0"} +parachains-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v1.0.0" } + sygma-basic-feehandler = { path = "../basic-fee-handler" } sygma-traits = { path = "../traits" } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index faade35..2e943d9 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -47,6 +47,7 @@ pub mod pallet { use xcm_executor::traits::TransactAsset; use crate::eip712; + use sp_std::collections::btree_map::BTreeMap; use sygma_traits::{ ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress, @@ -85,9 +86,9 @@ pub mod pallet { pub trait Config: frame_system::Config + sygma_access_segregator::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Bridge transfer reserve account + /// Bridge transfer reserve accounts mapping with designated assets #[pallet::constant] - type TransferReserveAccount: Get; + type TransferReserveAccounts: Get>; /// EIP712 Verifying contract address /// This is used in EIP712 typed data domain @@ -226,8 +227,10 @@ pub mod pallet { ExtractDestDataFailed, /// Failed on the decimal converter DecimalConversionFail, - /// Deposit nonce has reached max integer qvalue + /// Deposit nonce has reached max integer value DepositNonceOverflow, + /// Asset not bound to a liquidity holder account + NoLiquidityHolderAccountBound, /// Function unimplemented Unimplemented, } @@ -476,16 +479,15 @@ pub mod pallet { let bridge_amount = amount - fee; + let token_reserved_account = Self::get_token_reserved_account(&asset.id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + // Deposit `bridge_amount` of asset to reserve account if asset is reserved in local // chain. if T::IsReserve::contains(&asset, &MultiLocation::here()) { T::AssetTransactor::deposit_asset( &(asset.id, Fungible(bridge_amount)).into(), - &Junction::AccountId32 { - network: None, - id: T::TransferReserveAccount::get().into(), - } - .into(), + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), // Put empty message hash here because we are not sending XCM message &XcmContext::with_message_id([0; 32]), ) @@ -705,6 +707,13 @@ pub mod pallet { } } + /// Return the TokenReservedAccount address by the given token + pub fn get_token_reserved_account(token_id: &AssetId) -> Option<[u8; 32]> { + T::TransferReserveAccounts::get() + .get(token_id) + .map(|account| (*account).clone().into()) + } + /// convert the ECDSA 64-byte uncompressed pubkey to H160 address pub fn public_key_to_address(public_key: &[u8]) -> [u8; 20] { let hash = keccak_256(public_key); @@ -883,15 +892,14 @@ pub mod pallet { T::DecimalConverter::convert_from(&(asset_id, amount).into()) .ok_or(Error::::DecimalConversionFail)?; + let token_reserved_account = Self::get_token_reserved_account(&asset_id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + // Withdraw `decimal_converted_asset` of asset from reserve account if T::IsReserve::contains(&decimal_converted_asset, &MultiLocation::here()) { T::AssetTransactor::withdraw_asset( &decimal_converted_asset, - &Junction::AccountId32 { - network: None, - id: T::TransferReserveAccount::get().into(), - } - .into(), + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), None, ) .map_err(|_| Error::::TransactFailed)?; @@ -932,23 +940,59 @@ pub mod pallet { }; use bridge::mock::{ assert_events, new_test_ext, slice_to_generalkey, AccessSegregator, Assets, Balances, - BridgeAccount, BridgePalletIndex, NativeLocation, NativeResourceId, Runtime, - RuntimeEvent, RuntimeOrigin as Origin, SygmaBasicFeeHandler, SygmaBridge, - SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, UsdcAssetId, - UsdcLocation, UsdcResourceId, ALICE, ASSET_OWNER, BOB, DEST_DOMAIN_ID, ENDOWED_BALANCE, + BridgeAccountNative, BridgeAccountOtherTokens, BridgePalletIndex, NativeLocation, + NativeResourceId, Runtime, RuntimeEvent, RuntimeOrigin as Origin, SygmaBasicFeeHandler, + SygmaBridge, SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, + UsdtAssetId, UsdtLocation, UsdtResourceId, ALICE, ASSET_OWNER, BOB, DEST_DOMAIN_ID, + ENDOWED_BALANCE, }; use codec::{self, Encode}; use frame_support::{ assert_noop, assert_ok, crypto::ecdsa::ECDSAExt, traits::tokens::fungibles::Create as FungibleCerate, }; + use parachains_common::AccountId; use primitive_types::U256; - use sp_core::{ecdsa, Pair}; + use sp_core::{ecdsa, ByteArray, Pair}; use sp_std::{boxed::Box, vec}; use sygma_fee_handler_router::FeeHandlerType; use sygma_traits::{DomainID, MpcAddress, TransferType}; use xcm::latest::prelude::*; + #[test] + fn get_token_reserved_account_test() { + new_test_ext().execute_with(|| { + assert_eq!( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()).unwrap(), + BridgeAccountNative::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + + // unknown token should return None + assert_eq!( + SygmaBridge::get_token_reserved_account( + &MultiLocation::new( + 2, + X3( + Parachain(1000), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"unknown"), + ), + ) + .into() + ), + None + ); + }) + } + #[test] fn set_mpc_address() { new_test_ext().execute_with(|| { @@ -1235,7 +1279,13 @@ pub mod pallet { )); // Check balances assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!(Balances::free_balance(BridgeAccount::get()), amount - fee); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); // Check event assert_events(vec![ @@ -1313,13 +1363,13 @@ pub mod pallet { assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, - Box::new(UsdcLocation::get().into()), + Box::new(UsdtLocation::get().into()), fee )); assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, - Box::new(UsdcLocation::get().into()), + Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); assert_ok!(SygmaBridge::register_domain( @@ -1329,23 +1379,23 @@ pub mod pallet { )); assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // Register foreign asset (USDC) with asset id 0 + // Register foreign asset (USDT) with asset id 0 assert_ok!( as FungibleCerate< ::AccountId, - >>::create(UsdcAssetId::get(), ASSET_OWNER, true, 1,)); + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some USDC to ALICE for test + // Mint some USDT to ALICE for test assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); - assert_eq!(Assets::balance(UsdcAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), - Box::new((Concrete(UsdcLocation::get()), Fungible(amount)).into()), + Box::new((Concrete(UsdtLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { parents: 0, interior: X2( @@ -1355,14 +1405,24 @@ pub mod pallet { }), )); // Check balances - assert_eq!(Assets::balance(UsdcAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); - assert_eq!(Assets::balance(UsdcAssetId::get(), BridgeAccount::get()), 0); - assert_eq!(Assets::balance(UsdcAssetId::get(), TreasuryAccount::get()), fee); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); + // USDT in the mock runtime has been configured as the reserved token, so the corresponding account should hold the deposit balance + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ) + ), + amount - fee + ); + assert_eq!(Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), fee); // Check event assert_events(vec![ RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), deposit_nonce: 0, sender: ALICE, transfer_type: TransferType::FungibleTransfer, @@ -1375,9 +1435,9 @@ pub mod pallet { RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { fee_payer: ALICE, dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), fee_amount: fee, - fee_asset_id: UsdcLocation::get().into(), + fee_asset_id: UsdtLocation::get().into(), }), ]); }) @@ -1720,10 +1780,40 @@ pub mod pallet { }), )); - // Register foreign asset (USDC) with asset id 0 + // Register foreign asset (USDT) with asset id 0 assert_ok!( as FungibleCerate< ::AccountId, - >>::create(UsdcAssetId::get(), ASSET_OWNER, true, 1,)); + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + + // Mint 400 USDT to liquidity holder for test + assert_ok!(Assets::mint( + Origin::signed(ASSET_OWNER), + codec::Compact(0), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + 400_000_000_000_000, + )); + // alice deposit 200 - 1 token fee native token, so the native token holder should have 199 tokens + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 + ); + // USDT liquidity holder should have 400 USDT at this moment + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ) + ), + 400_000_000_000_000 + ); // Generate proposals // amount is in 18 decimal 0.000200000000000000, will be convert to 12 decimal @@ -1740,10 +1830,10 @@ pub mod pallet { }; // amount is in 18 decimal 0.000200000000000000, will be convert to 18 decimal // 0.000200000000000000 - let valid_usdc_transfer_proposal = Proposal { + let valid_usdt_transfer_proposal = Proposal { origin_domain_id: DEST_DOMAIN_ID, deposit_nonce: 2, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), data: SygmaBridge::create_deposit_data( amount, MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) @@ -1789,13 +1879,13 @@ pub mod pallet { let empty_data_proposal = Proposal { origin_domain_id: DEST_DOMAIN_ID, deposit_nonce: 3, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), data: vec![], }; let proposals = vec![ valid_native_transfer_proposal, - valid_usdc_transfer_proposal, + valid_usdt_transfer_proposal, invalid_depositnonce_proposal, invalid_domainid_proposal, invalid_resourceid_proposal, @@ -1834,7 +1924,7 @@ pub mod pallet { bridge::Error::::BadMpcSignature, ); assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE); - assert_eq!(Assets::balance(UsdcAssetId::get(), &BOB), 0); + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); assert!(SygmaBridge::verify_by_mpc_address( final_message, proposals_with_valid_signature.encode() @@ -1847,8 +1937,29 @@ pub mod pallet { // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); - // usdc is defined in 18 decimal so that converted amount is the same as in proposal - assert_eq!(Assets::balance(UsdcAssetId::get(), &BOB), amount); + // usdt is defined in 18 decimal so that converted amount is the same as in proposal + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), amount); + + // liquidity holder accounts balance after proposals execution + // 199 - 0.0002 native token is 198.999800000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 - 200_000_000 + ); + // 400 USDT after transferring out the USDT proposal, should remain 200 USDT + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ) + ), + 200_000_000_000_000 + ); }) } @@ -2044,10 +2155,10 @@ pub mod pallet { let amount_native_asset = 123_456_789_123_456u128; // 123.456_789_123_456 let adjusted_amount_native_asset = 122_456_789_123_456_000_000u128; // amount_native_asset - fee_native_asset then adjust it to 18 decimals - // usdc asset with 18 decimal - let fee_usdc_asset = 1_000_000_000_000_000_000u128; // 1.0 usdc asset - let amount_usdc_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 - let adjusted_amount_usdc_asset = 122_456_789_123_456_789_123u128; // amount_usdc_asset - fee_usdc_asset then adjust it to 18 decimals + // usdt asset with 18 decimal + let fee_usdt_asset = 1_000_000_000_000_000_000u128; // 1.0 usdt asset + let amount_usdt_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 + let adjusted_amount_usdt_asset = 122_456_789_123_456_789_123u128; // amount_usdt_asset - fee_usdt_asset then adjust it to 18 decimals // astr asset with 24 decimal let fee_astr_asset = 1_000_000_000_000_000_000_000_000u128; // 1.0 astr asset @@ -2064,8 +2175,8 @@ pub mod pallet { assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, - Box::new(UsdcLocation::get().into()), - fee_usdc_asset + Box::new(UsdtLocation::get().into()), + fee_usdt_asset )); assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), @@ -2082,7 +2193,7 @@ pub mod pallet { assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, - Box::new(UsdcLocation::get().into()), + Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( @@ -2116,7 +2227,10 @@ pub mod pallet { assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount_native_asset); // native asset should be reserved so that BridgeAccount should hold it assert_eq!( - Balances::free_balance(BridgeAccount::get()), + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), amount_native_asset - fee_native_asset ); // TreasuryAccount is collecting the bridging fee @@ -2144,25 +2258,25 @@ pub mod pallet { }), ]); - // deposit usdc asset which has 18 decimal - // Register foreign asset (usdc) with asset id 0 + // deposit usdt asset which has 18 decimal + // Register foreign asset (usdt) with asset id 0 assert_ok!( as FungibleCerate< ::AccountId, - >>::create(UsdcAssetId::get(), ASSET_OWNER, true, 1,)); + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some usdc to ALICE for test + // Mint some usdt to ALICE for test assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); // make sure Alice owns enough funds here - assert_eq!(Assets::balance(UsdcAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); // deposit assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), - Box::new((Concrete(UsdcLocation::get()), Fungible(amount_usdc_asset)).into()), + Box::new((Concrete(UsdtLocation::get()), Fungible(amount_usdt_asset)).into()), Box::new(MultiLocation { parents: 0, interior: X2( @@ -2173,27 +2287,35 @@ pub mod pallet { )); // Check balances assert_eq!( - Assets::balance(UsdcAssetId::get(), &ALICE), - ENDOWED_BALANCE - amount_usdc_asset + Assets::balance(UsdtAssetId::get(), &ALICE), + ENDOWED_BALANCE - amount_usdt_asset + ); + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ) + ), + 122_456_789_123_456_789_123 ); - // usdc asset should not be reserved so that BridgeAccount should not hold it - assert_eq!(Assets::balance(UsdcAssetId::get(), BridgeAccount::get()), 0); // TreasuryAccount is collecting the bridging fee assert_eq!( - Assets::balance(UsdcAssetId::get(), TreasuryAccount::get()), - fee_usdc_asset + Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), + fee_usdt_asset ); // Check event assert_events(vec![ RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), deposit_nonce: 1, sender: ALICE, transfer_type: TransferType::FungibleTransfer, deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_usdc_asset, + adjusted_amount_usdt_asset, b"ethereum recipient".to_vec(), ), handler_response: vec![], @@ -2201,9 +2323,9 @@ pub mod pallet { RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { fee_payer: ALICE, dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdcResourceId::get(), - fee_amount: fee_usdc_asset, - fee_asset_id: UsdcLocation::get().into(), + resource_id: UsdtResourceId::get(), + fee_amount: fee_usdt_asset, + fee_asset_id: UsdtLocation::get().into(), }), ]); @@ -2242,7 +2364,13 @@ pub mod pallet { // astr asset should be reserved so that BridgeAccount should hold it(Astr is not // defined in ConcrateSygmaAsset) assert_eq!( - Assets::balance(AstrAssetId::get(), BridgeAccount::get()), + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ) + ), amount_astr_asset - fee_astr_asset ); // TreasuryAccount is collecting the bridging fee @@ -2353,7 +2481,13 @@ pub mod pallet { }), )); // BridgeAccount should have half of alice native asset - fee - assert_eq!(Balances::free_balance(BridgeAccount::get()), ENDOWED_BALANCE / 2 - fee); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + ENDOWED_BALANCE / 2 - fee + ); // TreasuryAccount is collecting the bridging fee assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); @@ -2389,37 +2523,58 @@ pub mod pallet { ENDOWED_BALANCE / 2 + 100_000_000_000_000 ); - // proposal for bridging usdc asset to alice(usdc asset is 18 decimal) - // Register foreign asset (usdc) with asset id 0 + // proposal for bridging usdt asset to alice(usdt asset is 18 decimal) + // Register foreign asset (usdt) with asset id 0 assert_ok!( as FungibleCerate< ::AccountId, - >>::create(UsdcAssetId::get(), ASSET_OWNER, true, 1,)); + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + + // Mint some USDT to liquidity holder for test + assert_ok!(Assets::mint( + Origin::signed(ASSET_OWNER), + codec::Compact(0), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ENDOWED_BALANCE, + )); + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ) + ), + ENDOWED_BALANCE + ); - let p_usdc = Proposal { + let p_usdt = Proposal { origin_domain_id: 1, deposit_nonce: 2, - resource_id: UsdcResourceId::get(), + resource_id: UsdtResourceId::get(), data: SygmaBridge::create_deposit_data( bridge_amount, MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) .encode(), ), }; - let proposals_usdc = vec![p_usdc]; - let final_message_usdc = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdc); - let signature_usdc = pair.sign_prehashed(&final_message_usdc); + let proposals_usdt = vec![p_usdt]; + let final_message_usdt = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdt); + let signature_usdt = pair.sign_prehashed(&final_message_usdt); - // alice does not have any usdc at this moment - assert_eq!(Assets::balance(UsdcAssetId::get(), &ALICE), 0); + // alice does not have any usdt at this moment + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), 0); assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), - proposals_usdc, - signature_usdc.encode() + proposals_usdt, + signature_usdt.encode() )); - // alice should have 100 usdc at this moment (100 usdc with 18 decimals) + // alice should have 100 usdt at this moment (100 usdt with 18 decimals) assert_eq!( - Assets::balance(UsdcAssetId::get(), &ALICE), + Assets::balance(UsdtAssetId::get(), &ALICE), 100_000_000_000_000_000_000 ); @@ -2433,11 +2588,20 @@ pub mod pallet { assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(1), - BridgeAccount::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ), ENDOWED_BALANCE )); assert_eq!( - Assets::balance(AstrAssetId::get(), BridgeAccount::get()), + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ) + ), ENDOWED_BALANCE ); @@ -2696,7 +2860,13 @@ pub mod pallet { )); // Check balances assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!(Balances::free_balance(BridgeAccount::get()), amount - fee); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); // proposal execution should work @@ -2774,7 +2944,13 @@ pub mod pallet { // Check balances of Alice after deposit 200 native token assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); // Check reserved native token - assert_eq!(Balances::free_balance(BridgeAccount::get()), 190_000_000_000_000u128); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_000_000_000_000u128 + ); // Check fee collected assert_eq!(Balances::free_balance(TreasuryAccount::get()), 10_000_000_000_000u128); // Check event @@ -2837,7 +3013,13 @@ pub mod pallet { }), )); // Check reserved native token, should increase by 0.02 to 190.020000000000 - assert_eq!(Balances::free_balance(BridgeAccount::get()), 190_020_000_000_000u128); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_020_000_000_000u128 + ); // Check fee collected, should increase by 199.98 to 209.980000000000 assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); @@ -2863,7 +3045,13 @@ pub mod pallet { }), )); // Check reserved native token, should increase by 200 to 390.020000000000 - assert_eq!(Balances::free_balance(BridgeAccount::get()), 390_020_000_000_000u128); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); // Check fee collected, should increase by 0 to 209.980000000000 assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); @@ -2882,7 +3070,13 @@ pub mod pallet { ); // Check reserved native token, should remain as 390.020000000000 - assert_eq!(Balances::free_balance(BridgeAccount::get()), 390_020_000_000_000u128); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); // Check fee collected, should remain as 209.980000000000 assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); @@ -2912,7 +3106,13 @@ pub mod pallet { }), )); // Check reserved native token, should increase by 100 to 490.020000000000 - assert_eq!(Balances::free_balance(BridgeAccount::get()), 490_020_000_000_000u128); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 490_020_000_000_000u128 + ); // Check fee collected, should increase by 100 to 309.980000000000 assert_eq!(Balances::free_balance(TreasuryAccount::get()), 309_980_000_000_000u128); @@ -2934,7 +3134,10 @@ pub mod pallet { )); // Check reserved native token, should increase by 199000 to 199490.020000000000 assert_eq!( - Balances::free_balance(BridgeAccount::get()), + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), 199_490_020_000_000_000u128 ); // Check fee collected, should increase by 1000 to 1309.980000000000 @@ -3026,7 +3229,13 @@ pub mod pallet { )); // Check balances assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!(Balances::free_balance(BridgeAccount::get()), amount - fee); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); // Override Basic fee handler to Percentage fee handler with 5% fee rate @@ -3060,7 +3269,10 @@ pub mod pallet { assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount * 2); // Check reserved native token, should increase by 190 assert_eq!( - Balances::free_balance(BridgeAccount::get()), + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), amount - fee + 190_000_000_000_000u128 ); // Check fee collected, should increase by 10 diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index 9bba75c..19d9e40 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -13,11 +13,14 @@ use frame_support::{ use frame_system::{self as system, EnsureSigned}; use polkadot_parachain::primitives::Sibling; use sp_core::{hash::H256, Get}; +use sp_runtime::traits::AccountIdConversion; use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, AccountId32, BuildStorage, Perbill, }; +use sp_std::collections::btree_map::BTreeMap; use sp_std::{marker::PhantomData, prelude::*, result}; + use sygma_traits::{ ChainID, DecimalConverter, DomainID, ExtractDestinationData, ResourceId, VerifyingContractAddress, @@ -200,25 +203,33 @@ impl sygma_percentage_feehandler::Config for Runtime { type WeightInfo = sygma_percentage_feehandler::weights::SygmaWeightInfo; } +fn bridge_accounts_generator() -> BTreeMap { + let mut account_map: BTreeMap = BTreeMap::new(); + account_map.insert(NativeLocation::get().into(), BridgeAccountNative::get()); + account_map.insert(UsdtLocation::get().into(), BridgeAccountOtherTokens::get()); + account_map.insert(AstrLocation::get().into(), BridgeAccountOtherTokens::get()); + account_map +} + parameter_types! { pub TreasuryAccount: AccountId32 = AccountId32::new([100u8; 32]); pub EIP712ChainID: ChainID = primitive_types::U256([1u64; 4]); pub DestVerifyingContractAddress: VerifyingContractAddress = primitive_types::H160([1u8; 20]); - pub BridgeAccount: AccountId32 = AccountId32::new([101u8; 32]); + pub BridgeAccountNative: AccountId32 = SygmaBridgePalletId::get().into_account_truncating(); + pub BridgeAccountOtherTokens: AccountId32 = SygmaBridgePalletId::get().into_sub_account_truncating(1u32); + pub BridgeAccounts: BTreeMap = bridge_accounts_generator(); pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); pub RelayNetwork: NetworkId = NetworkId::Polkadot; pub AssetsPalletLocation: MultiLocation = PalletInstance(::index() as u8).into(); pub NativeLocation: MultiLocation = MultiLocation::here(); - // amount = 0 act as placeholder - pub NativeAsset: MultiAsset = (Concrete(MultiLocation::here()), 0u128).into(); - pub UsdcAssetId: AssetId = 0; - pub UsdcLocation: MultiLocation = MultiLocation::new( + pub UsdtAssetId: AssetId = 0; + pub UsdtLocation: MultiLocation = MultiLocation::new( 1, X3( - Parachain(2004), + Parachain(2005), slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"usdc"), + slice_to_generalkey(b"usdt"), ), ); pub AstrAssetId: AssetId = 1; @@ -231,10 +242,10 @@ parameter_types! { ), ); pub NativeResourceId: ResourceId = hex_literal::hex!("00e6dfb61a2fb903df487c401663825643bb825d41695e63df8af6162ab145a6"); - pub UsdcResourceId: ResourceId = hex_literal::hex!("00b14e071ddad0b12be5aca6dffc5f2584ea158d9b0ce73e1437115e97a32a3e"); + pub UsdtResourceId: ResourceId = hex_literal::hex!("00b14e071ddad0b12be5aca6dffc5f2584ea158d9b0ce73e1437115e97a32a3e"); pub AstrResourceId: ResourceId = hex_literal::hex!("4e071db61a2fb903df487c401663825643ba158d9b0ce73e1437163825643bba"); - pub ResourcePairs: Vec<(XcmAssetId, ResourceId)> = vec![(NativeLocation::get().into(), NativeResourceId::get()), (UsdcLocation::get().into(), UsdcResourceId::get()), (AstrLocation::get().into(), AstrResourceId::get())]; - pub AssetDecimalPairs: Vec<(XcmAssetId, u8)> = vec![(NativeLocation::get().into(), 12u8), (UsdcLocation::get().into(), 18u8), (AstrLocation::get().into(), 24u8)]; + pub ResourcePairs: Vec<(XcmAssetId, ResourceId)> = vec![(NativeLocation::get().into(), NativeResourceId::get()), (UsdtLocation::get().into(), UsdtResourceId::get()), (AstrLocation::get().into(), AstrResourceId::get())]; + pub AssetDecimalPairs: Vec<(XcmAssetId, u8)> = vec![(NativeLocation::get().into(), 12u8), (UsdtLocation::get().into(), 18u8), (AstrLocation::get().into(), 24u8)]; pub const SygmaBridgePalletId: PalletId = PalletId(*b"sygma/01"); } @@ -272,8 +283,8 @@ impl MatchesFungibles for SimpleForeignAssetConverter { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { match (&a.fun, &a.id) { (Fungible(ref amount), Concrete(ref id)) => { - if id == &UsdcLocation::get() { - Ok((UsdcAssetId::get(), *amount)) + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) } else if id == &AstrLocation::get() { Ok((AstrAssetId::get(), *amount)) } else { @@ -466,7 +477,7 @@ impl ExtractDestinationData for DestinationDataParser { impl sygma_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type TransferReserveAccount = BridgeAccount; + type TransferReserveAccounts = BridgeAccounts; type FeeReserveAccount = TreasuryAccount; type EIP712ChainID = EIP712ChainID; type DestVerifyingContractAddress = DestVerifyingContractAddress; diff --git a/substrate-node/runtime/src/lib.rs b/substrate-node/runtime/src/lib.rs index 433af6a..0cfb7cc 100644 --- a/substrate-node/runtime/src/lib.rs +++ b/substrate-node/runtime/src/lib.rs @@ -20,11 +20,13 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, + AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, + NumberFor, One, Verify, }, transaction_validity::{TransactionSource, TransactionValidity}, AccountId32, ApplyExtrinsicResult, MultiSignature, Perbill, }; +use sp_std::collections::btree_map::BTreeMap; use sp_std::{marker::PhantomData, prelude::*, result, vec::Vec}; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -392,13 +394,25 @@ impl sygma_fee_handler_router::Config for Runtime { // This address is defined in the substrate E2E test of sygma-relayer const DEST_VERIFYING_CONTRACT_ADDRESS: &str = "6CdE2Cd82a4F8B74693Ff5e194c19CA08c2d1c68"; +fn bridge_accounts_generator() -> BTreeMap { + let mut account_map: BTreeMap = BTreeMap::new(); + account_map.insert(NativeLocation::get().into(), BridgeAccountNative::get()); + account_map.insert(UsdtLocation::get().into(), BridgeAccountOtherToken::get()); + account_map.insert(ERC20TSTLocation::get().into(), BridgeAccountOtherToken::get()); + account_map.insert(ERC20TSTD20Location::get().into(), BridgeAccountOtherToken::get()); + account_map +} + parameter_types! { // TreasuryAccount is an substrate account and currently used for substrate -> EVM bridging fee collection // TreasuryAccount address: 5ELLU7ibt5ZrNEYRwohtaRBDBa3TzcWwwPELBPSWWd2mbgv3 pub TreasuryAccount: AccountId32 = AccountId32::new([100u8; 32]); - // BridgeAccount is an account for holding transferred asset collection - // BridgeAccount address: 5EMepC39b7E2zfM9g6CkPp8KCAxGTh7D4w4T2tFjmjpd4tPw - pub BridgeAccount: AccountId32 = AccountId32::new([101u8; 32]); + // BridgeAccountNative: 5EYCAe5jLbHcAAMKvLFSXgCTbPrLgBJusvPwfKcaKzuf5X5e + pub BridgeAccountNative: AccountId32 = SygmaBridgePalletId::get().into_account_truncating(); + // BridgeAccountOtherToken 5EYCAe5jLbHcAAMKvLFiGhk3htXY8jQncbLTDGJQnpnPMAVp + pub BridgeAccountOtherToken: AccountId32 = SygmaBridgePalletId::get().into_sub_account_truncating(1u32); + // BridgeAccounts is a list of accounts for holding transferred asset collection + pub BridgeAccounts: BTreeMap = bridge_accounts_generator(); // EIP712ChainID is the chainID that pallet is assigned with, used in EIP712 typed data domain pub EIP712ChainID: ChainID = U256::from(5); // DestVerifyingContractAddress is a H160 address that is used in proposal signature verification, specifically EIP712 typed data @@ -411,22 +425,20 @@ parameter_types! { PalletInstance(::index() as u8).into(); // NativeLocation is the representation of the current parachain's native asset location in substrate, it can be various on different parachains pub NativeLocation: MultiLocation = MultiLocation::here(); - // amount = 0 act as placeholder - pub NativeAsset: MultiAsset = (Concrete(MultiLocation::here()), 0u128).into(); - // UsdcLocation is the representation of the USDC asset location in substrate - // USDC is a foreign asset, and in our local testing env, it's being registered on Parachain 2004 with the following location - pub UsdcLocation: MultiLocation = MultiLocation::new( + // UsdtLocation is the representation of the USDT asset location in substrate + // USDT is a foreign asset, and in our local testing env, it's being registered on Parachain 2004 with the following location + pub UsdtLocation: MultiLocation = MultiLocation::new( 1, X3( - Parachain(2004), + Parachain(2005), slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"usdc"), + slice_to_generalkey(b"usdt"), ), ); pub ERC20TSTLocation: MultiLocation = MultiLocation::new( 1, X3( - Parachain(2004), + Parachain(2005), slice_to_generalkey(b"sygma"), slice_to_generalkey(b"erc20tst"), ), @@ -434,28 +446,28 @@ parameter_types! { pub ERC20TSTD20Location: MultiLocation = MultiLocation::new( 1, X3( - Parachain(2004), + Parachain(2005), slice_to_generalkey(b"sygma"), slice_to_generalkey(b"erc20tstd20"), ), ); - // UsdcAssetId is the substrate assetID of USDC - pub UsdcAssetId: AssetId = 2000; + // UsdtAssetId is the substrate assetID of USDT + pub UsdtAssetId: AssetId = 2000; pub ERC20TSTAssetId: AssetId = 2001; pub ERC20TSTD20AssetId: AssetId = 2002; // NativeResourceId is the resourceID that mapping with the current parachain native asset pub NativeResourceId: ResourceId = hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000001"); - // UsdcResourceId is the resourceID that mapping with the foreign asset USDC - pub UsdcResourceId: ResourceId = hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000300"); + // UsdtResourceId is the resourceID that mapping with the foreign asset USDT + pub UsdtResourceId: ResourceId = hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000300"); pub ERC20TSTResourceId: ResourceId = hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000000"); pub ERC20TSTD20ResourceId: ResourceId = hex_literal::hex!("0000000000000000000000000000000000000000000000000000000000000900"); // ResourcePairs is where all supported assets and their associated resourceID are binding - pub ResourcePairs: Vec<(XcmAssetId, ResourceId)> = vec![(NativeLocation::get().into(), NativeResourceId::get()), (UsdcLocation::get().into(), UsdcResourceId::get()), (ERC20TSTLocation::get().into(), ERC20TSTResourceId::get()), (ERC20TSTD20Location::get().into(), ERC20TSTD20ResourceId::get())]; + pub ResourcePairs: Vec<(XcmAssetId, ResourceId)> = vec![(NativeLocation::get().into(), NativeResourceId::get()), (UsdtLocation::get().into(), UsdtResourceId::get()), (ERC20TSTLocation::get().into(), ERC20TSTResourceId::get()), (ERC20TSTD20Location::get().into(), ERC20TSTD20ResourceId::get())]; // SygmaBridgePalletId is the palletIDl // this is used as the replacement of handler address in the ProposalExecution event pub const SygmaBridgePalletId: PalletId = PalletId(*b"sygma/01"); - pub AssetDecimalPairs: Vec<(XcmAssetId, u8)> = vec![(NativeLocation::get().into(), 12u8), (UsdcLocation::get().into(), 12u8), (ERC20TSTLocation::get().into(), 18u8), (ERC20TSTD20Location::get().into(), 20u8)]; + pub AssetDecimalPairs: Vec<(XcmAssetId, u8)> = vec![(NativeLocation::get().into(), 12u8), (UsdtLocation::get().into(), 12u8), (ERC20TSTLocation::get().into(), 18u8), (ERC20TSTD20Location::get().into(), 20u8)]; } /// Type for specifying how a `MultiLocation` can be converted into an `AccountId`. This is used @@ -492,8 +504,8 @@ impl MatchesFungibles for SimpleForeignAssetConverter { fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { match (&a.fun, &a.id) { (Fungible(ref amount), Concrete(ref id)) => { - if id == &UsdcLocation::get() { - Ok((UsdcAssetId::get(), *amount)) + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) } else if id == &ERC20TSTLocation::get() { Ok((ERC20TSTAssetId::get(), *amount)) } else if id == &ERC20TSTD20Location::get() { @@ -688,7 +700,7 @@ impl ExtractDestinationData for DestinationDataParser { impl sygma_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type TransferReserveAccount = BridgeAccount; + type TransferReserveAccounts = BridgeAccounts; type FeeReserveAccount = TreasuryAccount; type EIP712ChainID = EIP712ChainID; type DestVerifyingContractAddress = DestVerifyingContractAddress;