Skip to content

Commit

Permalink
Allow to receive and send Ethereum assets (#1305)
Browse files Browse the repository at this point in the history
* feat: 🎸 add buy-back

* Bifrost v0.10.001

* feat: 🎸 benchmark

* SLPx mint support commission id (#1261)

* Add vtoken exchange rate rpc (#1260)

* fix: 🐛 add event (#1263)

* add update_currency_metadata function (#1259)

* add update_currency_metadata function

* fix: 🐛 correct update_currency_metadata weight

* add the use of Vec (#1264)

* Add vtoken exchange rate rpc

* add the use of Vec

* Upgrade to Polkadot-SDK v1.7.0 (#1262)

* Bifrost v0.10.0

* fix: 🐛 clippy

* Fix chain spec (#1243)

* Upgrade to polkadot-v1.7.0

---------

Co-authored-by: SunTiebing <[email protected]>
Co-authored-by: Edwin Wang <[email protected]>

* feat: 🎸 add metadata-hash-extension (#1265)

* Fix compile (#1266)

* Fix/fix vtoken voting unlock (#1267)

* update the exchange rate of vtokenminting of vtokenvoting test

* Resolve the frozen anomaly when unlocking

* Revert "feat: 🎸 add metadata-hash-extension (#1265)" (#1268)

This reverts commit 489fc9c.

* rename the version number to 0.11.0

* Slp supports XCMv4 and reconstruct integration tests (#1272)

* Fix compile

* Reconstruct integration tests and slp supports XCMv4

* Fix slp construct_xcm_message

* Feat/slpx mint add commission (#1273)

* SLPx mint support commission id

* remove the channel_id parameter from the mint method

* add mint_with_channel_id method

* perform data migration for OrderQueue storage

* slpx: set the default value of channel_id to 0

* resolve conflicts

* change the location of the old data structure during storage migration

* Feat/add vtoken exchange rate rpc (#1274)

* Add vtoken exchange rate rpc

* add the use of Vec

* supplement the RPC logic && fix bugs

* adjust the RPC exchange rate precision to three decimal places

* fix clippy

* fix bug: storage migration anomaly (#1276)

* SLPx mint support commission id

* remove the channel_id parameter from the mint method

* add mint_with_channel_id method

* perform data migration for OrderQueue storage

* slpx: set the default value of channel_id to 0

* resolve conflicts

* change the location of the old data structure during storage migration

* fix bug: storage migration anomaly

* Slp removes refund (#1275)

* Slp removes refund

* Fix clippy

* Allow to receive and send Ethereum assets

* Add constants

---------

Co-authored-by: yooml <[email protected]>
Co-authored-by: SunTiebing <[email protected]>
Co-authored-by: SunTiebing <[email protected]>
Co-authored-by: Edwin Wang <[email protected]>
  • Loading branch information
5 people authored Jul 12, 2024
1 parent 01e0a8e commit 8e45b7f
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 22 additions & 16 deletions pallets/xcm-interface/src/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use frame_support::sp_runtime::MultiSignature;
use parity_scale_codec::{Decode, Encode};
use sp_runtime::RuntimeDebug;
use sp_std::{boxed::Box, vec::Vec};
use xcm::{VersionedAssets, VersionedLocation};
use xcm::{v4::WeightLimit, VersionedAssets, VersionedLocation};

use crate::ChainId;

Expand All @@ -39,14 +39,22 @@ pub enum StakingCall {
}

#[derive(Encode, Decode, RuntimeDebug, Clone)]
pub enum PolkadotXcm {
pub enum PolkadotXcmCall {
#[codec(index = 2)]
ReserveTransferAssets(
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
u32,
),
#[codec(index = 8)]
LimitedReserveTransferAssets(
Box<VersionedLocation>,
Box<VersionedLocation>,
Box<VersionedAssets>,
u32,
WeightLimit,
),
}

#[derive(Encode, Decode, RuntimeDebug, Clone)]
Expand All @@ -55,19 +63,6 @@ pub enum SystemCall {
RemarkWithEvent(Vec<u8>),
}

pub mod rococo {

pub use crate::calls::*;

#[derive(Encode, Decode, RuntimeDebug)]
pub enum RelaychainCall<BalanceOf, AccountIdOf, BlockNumberOf> {
#[codec(index = 28)]
Crowdloan(ContributeCall<BalanceOf, AccountIdOf>),
#[codec(index = 91)]
Proxy(ProxyCall<AccountIdOf, BlockNumberOf>),
}
}

pub mod kusama {

pub use crate::calls::*;
Expand All @@ -79,10 +74,15 @@ pub mod kusama {
#[codec(index = 30)]
Proxy(ProxyCall<AccountIdOf, BlockNumberOf>),
}

#[derive(Encode, Decode, RuntimeDebug)]
pub enum AssetHubCall {
#[codec(index = 31)]
PolkadotXcm(PolkadotXcmCall),
}
}

pub mod polkadot {

pub use crate::calls::*;

#[derive(Encode, Decode, RuntimeDebug)]
Expand All @@ -92,6 +92,12 @@ pub mod polkadot {
#[codec(index = 29)]
Proxy(ProxyCall<AccountIdOf, BlockNumberOf>),
}

#[derive(Encode, Decode, RuntimeDebug)]
pub enum AssetHubCall {
#[codec(index = 31)]
PolkadotXcm(PolkadotXcmCall),
}
}

#[derive(Encode, Decode, RuntimeDebug)]
Expand Down
79 changes: 75 additions & 4 deletions pallets/xcm-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

#![cfg_attr(not(feature = "std"), no_std)]
#![allow(unused_imports)]

pub mod calls;
pub mod traits;
Expand All @@ -25,20 +26,19 @@ use bifrost_primitives::{traits::XcmDestWeightAndFeeHandler, CurrencyIdMapping,
pub use calls::*;
use orml_traits::MultiCurrency;
pub use pallet::*;
use sp_runtime::traits::UniqueSaturatedInto;
pub use traits::{ChainId, MessageId, Nonce, SalpHelper};

macro_rules! use_relay {
({ $( $code:tt )* }) => {
if T::RelayNetwork::get() == NetworkId::Polkadot {
use polkadot::RelaychainCall;
use polkadot::AssetHubCall;

$( $code )*
} else if T::RelayNetwork::get() == NetworkId::Kusama {
use kusama::RelaychainCall;

$( $code )*
} else if T::RelayNetwork::get() == NetworkId::Rococo {
use rococo::RelaychainCall;
use kusama::AssetHubCall;

$( $code )*
} else {
Expand Down Expand Up @@ -135,6 +135,7 @@ pub mod pallet {
pub enum Event<T: Config> {
XcmDestWeightAndFeeUpdated(XcmOperationType, CurrencyIdOf<T>, Weight, BalanceOf<T>),
TransferredStatemineMultiAsset(AccountIdOf<T>, BalanceOf<T>),
TransferredEthereumAssets(AccountIdOf<T>, sp_core::H160, BalanceOf<T>),
}

/// The current storage version, we set to 2 our new version(after migrate stroage
Expand Down Expand Up @@ -278,6 +279,76 @@ pub mod pallet {

Ok(())
}

#[pallet::call_index(2)]
#[pallet::weight({2_000_000_000})]
pub fn transfer_ethereum_assets(
origin: OriginFor<T>,
currency_id: CurrencyIdOf<T>,
amount: BalanceOf<T>,
to: sp_core::H160,
) -> DispatchResult {
let who = ensure_signed(origin.clone())?;
let asset_location =
T::CurrencyIdConvert::get_location(currency_id).ok_or(Error::<T>::FailToConvert)?;

let asset: Asset = Asset {
id: AssetId(asset_location),
fun: Fungible(UniqueSaturatedInto::<u128>::unique_saturated_into(amount)),
};

let (require_weight_at_most, xcm_fee) =
Self::xcm_dest_weight_and_fee(currency_id, XcmOperationType::EthereumTransfer)
.ok_or(Error::<T>::OperationWeightAndFeeNotExist)?;

let fee: Asset = Asset {
id: AssetId(Location::parent()),
fun: Fungible(UniqueSaturatedInto::<u128>::unique_saturated_into(xcm_fee)),
};

T::MultiCurrency::withdraw(currency_id, &who, amount)?;

let remote_call: DoubleEncoded<()> = use_relay!({
AssetHubCall::PolkadotXcm(PolkadotXcmCall::LimitedReserveTransferAssets(
Box::new(Location::new(2, [GlobalConsensus(Ethereum { chain_id: 1 })]).into()),
Box::new(
Location::new(
0,
[AccountKey20 { network: None, key: to.to_fixed_bytes() }],
)
.into(),
),
Box::new(asset.into()),
0,
Unlimited,
))
.encode()
.into()
});

let remote_xcm = Xcm(vec![
WithdrawAsset(fee.clone().into()),
BuyExecution { fees: fee.clone(), weight_limit: Unlimited },
Transact {
origin_kind: OriginKind::SovereignAccount,
require_weight_at_most,
call: remote_call,
},
DepositAsset {
assets: All.into(),
beneficiary: Location::new(1, [Parachain(T::ParachainId::get().into())]),
},
]);
let (ticket, _) = <T as pallet_xcm::Config>::XcmRouter::validate(
&mut Some(Location::new(1, [Parachain(parachains::Statemine::ID)])),
&mut Some(remote_xcm),
)
.map_err(|_| Error::<T>::UnweighableMessage)?;
<T as pallet_xcm::Config>::XcmRouter::deliver(ticket)
.map_err(|_| Error::<T>::XcmExecutionFailed)?;
Self::deposit_event(Event::<T>::TransferredEthereumAssets(who, to, amount));
Ok(())
}
}

impl<T: Config> XcmHelper<AccountIdOf<T>, BalanceOf<T>> for Pallet<T> {
Expand Down
1 change: 1 addition & 0 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ pub enum XcmOperationType {
RemoveVote,
Any,
SupplementaryFee,
EthereumTransfer,
}

pub struct ExtraFeeInfo {
Expand Down
38 changes: 37 additions & 1 deletion runtime/bifrost-kusama/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,14 +629,50 @@ impl Contains<RuntimeCall> for SafeCallFilter {
}
}

/// Asset filter that allows all assets from a certain location matching asset id.
pub struct AssetPrefixFrom<Prefix, Origin>(PhantomData<(Prefix, Origin)>);
impl<Prefix, Origin> ContainsPair<Asset, Location> for AssetPrefixFrom<Prefix, Origin>
where
Prefix: Get<Location>,
Origin: Get<Location>,
{
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = Origin::get();
&loc == origin &&
matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) }
if asset_loc.starts_with(&Prefix::get()))
}
}

/// Asset filter that allows native/relay asset if coming from a certain location.
pub struct NativeAssetFrom<T>(PhantomData<T>);
impl<T: Get<Location>> ContainsPair<Asset, Location> for NativeAssetFrom<T> {
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = T::get();
&loc == origin &&
matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) }
if *asset_loc == Location::from(Parent))
}
}

parameter_types! {
/// Location of Asset Hub
pub AssetHubLocation: Location = (Parent, Parachain(1000)).into();
pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(Ethereum { chain_id: 1 })]);
}

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type AssetClaims = PolkadotXcm;
type AssetTransactor = BifrostAssetTransactor;
type AssetTrap = BifrostDropAssets<ToTreasury>;
type Barrier = Barrier;
type RuntimeCall = RuntimeCall;
type IsReserve = MultiNativeAsset<RelativeReserveProvider>;
type IsReserve = (
NativeAssetFrom<AssetHubLocation>,
AssetPrefixFrom<EthereumLocation, AssetHubLocation>,
MultiNativeAsset<RelativeReserveProvider>,
);
type IsTeleporter = ();
type UniversalLocation = UniversalLocation;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
Expand Down
38 changes: 37 additions & 1 deletion runtime/bifrost-polkadot/src/xcm_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,14 +483,50 @@ impl Contains<RuntimeCall> for SafeCallFilter {
}
}

/// Asset filter that allows all assets from a certain location matching asset id.
pub struct AssetPrefixFrom<Prefix, Origin>(PhantomData<(Prefix, Origin)>);
impl<Prefix, Origin> ContainsPair<Asset, Location> for AssetPrefixFrom<Prefix, Origin>
where
Prefix: Get<Location>,
Origin: Get<Location>,
{
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = Origin::get();
&loc == origin &&
matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) }
if asset_loc.starts_with(&Prefix::get()))
}
}

/// Asset filter that allows native/relay asset if coming from a certain location.
pub struct NativeAssetFrom<T>(PhantomData<T>);
impl<T: Get<Location>> ContainsPair<Asset, Location> for NativeAssetFrom<T> {
fn contains(asset: &Asset, origin: &Location) -> bool {
let loc = T::get();
&loc == origin &&
matches!(asset, Asset { id: AssetId(asset_loc), fun: Fungible(_a) }
if *asset_loc == Location::from(Parent))
}
}

parameter_types! {
/// Location of Asset Hub
pub AssetHubLocation: Location = (Parent, Parachain(1000)).into();
pub EthereumLocation: Location = Location::new(2, [GlobalConsensus(Ethereum { chain_id: 1 })]);
}

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type AssetClaims = PolkadotXcm;
type AssetTransactor = BifrostAssetTransactor;
type AssetTrap = BifrostDropAssets<ToTreasury>;
type Barrier = Barrier;
type RuntimeCall = RuntimeCall;
type IsReserve = MultiNativeAsset<RelativeReserveProvider>;
type IsReserve = (
NativeAssetFrom<AssetHubLocation>,
AssetPrefixFrom<EthereumLocation, AssetHubLocation>,
MultiNativeAsset<RelativeReserveProvider>,
);
type IsTeleporter = ();
type UniversalLocation = UniversalLocation;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
Expand Down

0 comments on commit 8e45b7f

Please sign in to comment.