Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Transact from eth to sub #114

Open
wants to merge 50 commits into
base: bridge-next-gen
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
d68c3d6
Fix for unit test
yrong Feb 14, 2024
307ecd6
Update for transact
yrong Feb 14, 2024
7c493bd
Penpal config for transact
yrong Feb 13, 2024
e55cfd1
Fix import
yrong Feb 14, 2024
45c3372
Fix taplo
yrong Feb 14, 2024
26df807
Fix for breaking emulated tests
yrong Feb 14, 2024
c4fe031
Remove unused
yrong Feb 14, 2024
51b76fe
Tranfer fees to BH for transact
yrong Feb 14, 2024
3ed7260
Remove the teleport config
yrong Feb 15, 2024
772fa46
Enable create agent/channel by xcm
yrong Feb 15, 2024
540a791
Refund surplus
yrong Feb 16, 2024
051b3b6
Fix format
yrong Feb 16, 2024
e523185
Replace hardcode value
yrong Feb 16, 2024
a8b8435
Leave to user to prefund sovereign account on the destination chain t…
yrong Feb 19, 2024
b10d19e
Update import path
yrong Feb 19, 2024
cbd2e19
Merge branch 'snowbridge' into transact-from-eth-to-sub
yrong Feb 20, 2024
e363918
Unit test for transact
yrong Feb 20, 2024
13217f1
DescendOrigin to inbound-queue first
yrong Feb 22, 2024
257e75d
Fix breaking test
yrong Feb 22, 2024
e03942a
First match RegisterToken or SendToken
yrong Feb 22, 2024
698a9e9
Remove deprecated
yrong Feb 22, 2024
9968a37
Use SetAppendix and refund surplus when transact fail
yrong Feb 22, 2024
40ea01a
Ignore parents which is meaningless for GlobalConsensus locations
yrong Feb 22, 2024
004afd2
Reuse weight type
yrong Feb 23, 2024
85d2c03
Update sender consistent with smoke test
yrong Feb 23, 2024
626ec76
Update Cargo.toml
yrong Feb 26, 2024
0686fcd
Fix breaking test
yrong Feb 26, 2024
7cc0d59
Improve tests
yrong Feb 26, 2024
050585c
Merge branch 'snowbridge' into transact-from-eth-to-sub
yrong Feb 28, 2024
ece8a96
Merge branch 'snowbridge' into transact-from-eth-to-sub
yrong Mar 6, 2024
7b916e5
Add TransactFeeMode
yrong Mar 6, 2024
15759a4
Improve convert logic
yrong Mar 6, 2024
04a339e
Fix UniversalLocation
yrong Mar 7, 2024
c18f771
AllowUnpaidExecutionFromSnowBridgeWithFeeChecked
yrong Mar 7, 2024
e49f077
Merge branch 'snowbridge' into transact-from-eth-to-sub
yrong Mar 19, 2024
362e414
Remove feeMode and fully charge all cost on Ethereum
yrong Mar 19, 2024
6fb78fe
Merge branch 'snowbridge' into transact-from-eth-to-sub
yrong Apr 11, 2024
9d0af91
Fix build error
yrong Apr 11, 2024
68abf04
Make network specific types as storage which can be changed
yrong Apr 11, 2024
76b01b2
Remove the fund steps unnecessary
yrong Apr 11, 2024
87ed097
Move Transact after Origin operations
yrong Apr 11, 2024
0ea24a4
Fix breaking test
yrong Apr 11, 2024
b85e362
Merge branch 'bridge-next-gen' into transact-from-eth-to-sub
yrong Apr 16, 2024
cd7a64a
Fix compile error
yrong Apr 16, 2024
966abdf
Use native token of destination chain to pay fee from a pre-funded so…
yrong Apr 17, 2024
1cab94c
Use native token or DOT based on whether its a system parachain or not
yrong Apr 22, 2024
5a22972
Make fee asset as configuration parameter of the Channel
yrong Apr 26, 2024
9829de7
Zero fee for transact
yrong Apr 28, 2024
2f30d46
Remove unused
yrong Apr 29, 2024
ee6bdc5
Deposit any left over fees back into the pre-funded account
yrong May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

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

30 changes: 18 additions & 12 deletions bridges/snowbridge/pallets/inbound-queue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@
sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters,
StaticLookup,
};
use snowbridge_router_primitives::{
inbound,
inbound::{ConvertMessage, ConvertMessageError},
use snowbridge_router_primitives::inbound::{
Command, ConvertMessage, ConvertMessageError, MessageV1, VersionedMessage,
};
use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError};

Expand Down Expand Up @@ -139,6 +138,9 @@

/// To withdraw and deposit an asset.
type AssetTransactor: TransactAsset;

/// Returns the parachain ID we are running with.
type SelfParaId: Get<ParaId>;
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
}

#[pallet::hooks]
Expand Down Expand Up @@ -267,12 +269,12 @@
let delivery_cost = Self::calculate_delivery_cost(message.encode().len() as u32);
T::Token::transfer(&sovereign_account, &who, delivery_cost, Preservation::Preserve)?;

// Decode message into XCM
let (xcm, fee) =
match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) {
Ok(message) => Self::do_convert(envelope.message_id, message)?,
Err(_) => return Err(Error::<T>::InvalidPayload.into()),
};
// Decode payload into VersionMessage
let message = VersionedMessage::decode_all(&mut envelope.payload.as_ref())
.map_err(|_| Error::<T>::InvalidPayload)?;

// Convert VersionMessage to XCM
let (xcm, fee) = Self::do_convert(envelope.message_id, message.clone())?;

log::info!(
target: LOG_TARGET,
Expand All @@ -281,8 +283,12 @@
fee
);

// Burning fees for teleport
Self::burn_fees(channel.para_id, fee)?;
let _ = match message {
// For transact do nothing here and leave it to dest chain to pay for fees by sender
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
VersionedMessage::V1(MessageV1 { command: Command::Transact { .. }, .. }) => Ok(()),

Check warning on line 288 in bridges/snowbridge/pallets/inbound-queue/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

bridges/snowbridge/pallets/inbound-queue/src/lib.rs#L288

Added line #L288 was not covered by tests
// For others burning fees for teleport
_ => Self::burn_fees(channel.para_id, fee),
}?;

// Attempt to send XCM to a dest parachain
let message_id = Self::send_xcm(xcm, channel.para_id)?;
Expand Down Expand Up @@ -314,7 +320,7 @@
impl<T: Config> Pallet<T> {
pub fn do_convert(
message_id: H256,
message: inbound::VersionedMessage,
message: VersionedMessage,
) -> Result<(Xcm<()>, BalanceOf<T>), Error<T>> {
let (mut xcm, fee) =
T::MessageConverter::convert(message).map_err(|e| Error::<T>::ConvertMessage(e))?;
Expand Down
1 change: 1 addition & 0 deletions bridges/snowbridge/pallets/inbound-queue/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ impl inbound_queue::Config for Test {
type LengthToFee = IdentityFee<u128>;
type MaxMessageSize = ConstU32<1024>;
type AssetTransactor = SuccessfulTransactor;
type SelfParaId = OwnParaId;
}

pub fn last_events(n: usize) -> Vec<RuntimeEvent> {
Expand Down
35 changes: 34 additions & 1 deletion bridges/snowbridge/pallets/inbound-queue/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
// SPDX-FileCopyrightText: 2023 Snowfork <[email protected]>
use super::*;

use frame_support::{assert_noop, assert_ok};
use frame_support::{assert_noop, assert_ok, weights::Weight};
use hex_literal::hex;
use snowbridge_core::{inbound::Proof, ChannelId};
use sp_keyring::AccountKeyring as Keyring;
use sp_runtime::{DispatchError, TokenError};
use sp_std::convert::From;
use xcm::prelude::{OriginKind, Transact};

use crate::{Error, Event as InboundQueueEvent};

Expand Down Expand Up @@ -210,3 +211,35 @@ fn test_set_operating_mode_root_only() {
);
});
}

#[test]
fn test_convert_transact() {
new_tester().execute_with(|| {
let message_id: H256 = [1; 32].into();
let sender: H160 = hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into();
let fee: u128 = 40_000_000_000;
let weight_at_most = Weight::from_parts(40_000_000, 8_000);
let origin_kind = OriginKind::SovereignAccount;
let payload = hex!("00071468656c6c6f").to_vec();
let message = VersionedMessage::V1(MessageV1 {
chain_id: 11155111,
command: Command::Transact {
sender,
fee,
weight_ref_time: weight_at_most.ref_time(),
weight_proof_size: weight_at_most.proof_size(),
origin_kind,
payload: payload.clone(),
},
});
// Convert the message to XCM
let (xcm, dest_fee) = InboundQueue::do_convert(message_id, message).unwrap();
let instructions = xcm.into_inner();
assert_eq!(instructions.len(), 10);
assert_eq!(dest_fee, fee.into());
let transact = instructions.get(5).unwrap().clone();
let expected =
Transact { origin_kind, require_weight_at_most: weight_at_most, call: payload.into() };
assert_eq!(transact, expected);
});
}
2 changes: 0 additions & 2 deletions bridges/snowbridge/pallets/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@ use xcm_executor::traits::ConvertLocation;
#[cfg(feature = "runtime-benchmarks")]
use frame_support::traits::OriginTrait;

pub use pallet::*;

pub type BalanceOf<T> =
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
Expand Down
75 changes: 75 additions & 0 deletions bridges/snowbridge/primitives/router/src/inbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@
/// XCM execution fee on AssetHub
fee: u128,
},
/// call arbitrary transact on dest chain
Transact {
/// The address of the sender
sender: H160,
/// OriginKind
origin_kind: OriginKind,
/// XCM execution fee on dest chain
fee: u128,
/// The ref_time part of weight_at_most
weight_ref_time: u64,
/// The proof_size part of weight_at_most
weight_proof_size: u64,
yrong marked this conversation as resolved.
Show resolved Hide resolved
/// The payload of the transact
payload: Vec<u8>,
},
}

/// Destination for bridged tokens
Expand Down Expand Up @@ -146,6 +161,19 @@
Ok(Self::convert_register_token(chain_id, token, fee)),
V1(MessageV1 { chain_id, command: SendToken { token, destination, amount, fee } }) =>
Ok(Self::convert_send_token(chain_id, token, destination, amount, fee)),
V1(MessageV1 {

Check warning on line 164 in bridges/snowbridge/primitives/router/src/inbound/mod.rs

View check run for this annotation

Codecov / codecov/patch

bridges/snowbridge/primitives/router/src/inbound/mod.rs#L164

Added line #L164 was not covered by tests
chain_id,
command:
Transact { sender, origin_kind, fee, weight_ref_time, weight_proof_size, payload },
}) => Ok(Self::convert_transact(
chain_id,
sender,
origin_kind,
fee,
weight_ref_time,
weight_proof_size,
payload,
)),
}
}
}
Expand Down Expand Up @@ -289,6 +317,53 @@
[GlobalConsensus(network), AccountKey20 { network: None, key: token.into() }],
)
}

fn convert_transact(
chain_id: u64,
sender: H160,
origin_kind: OriginKind,
fee: u128,
weight_ref_time: u64,
weight_proof_size: u64,
payload: Vec<u8>,
) -> (Xcm<()>, Balance) {
let xcm_fee: Asset = (Location::parent(), fee).into();

let xcm: Xcm<()> = vec![
// Only our inbound-queue pallet is allowed to invoke `UniversalOrigin`
DescendOrigin(PalletInstance(InboundQueuePalletInstance::get()).into()),
// Change origin to the bridge.
UniversalOrigin(GlobalConsensus(Ethereum { chain_id })),
// DescendOrigin to the sender.
DescendOrigin(AccountKey20 { network: None, key: sender.into() }.into()),
// Withdraw fees from sender to pay the xcm execution
WithdrawAsset(xcm_fee.clone().into()),
// Pay for execution.
BuyExecution { fees: xcm_fee.clone(), weight_limit: Unlimited },
// Transact on dest chain.
Transact {
origin_kind,
require_weight_at_most: Weight::from_parts(weight_ref_time, weight_proof_size),
call: payload.into(),
},
ExpectTransactStatus(MaybeErrorCode::Success),
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
RefundSurplus,
// Deposit surplus back to sender.
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
DepositAsset {
assets: Wild(AllCounted(1u32)),
beneficiary: Location {
parents: 1,
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
interior: Junctions::from([
GlobalConsensus(Ethereum { chain_id }),
AccountKey20 { network: None, key: sender.into() },
]),
},
},
]
.into();

(xcm, fee.into())
yrong marked this conversation as resolved.
Show resolved Hide resolved
}
}

pub struct GlobalConsensusEthereumConvertsFor<AccountId>(PhantomData<AccountId>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ hex-literal = "0.4.1"
# Substrate
sp-core = { path = "../../../../../../../substrate/primitives/core", default-features = false }
frame-support = { path = "../../../../../../../substrate/frame/support", default-features = false }
frame-system = { path = "../../../../../../../substrate/frame/system", default-features = false }
pallet-assets = { path = "../../../../../../../substrate/frame/assets", default-features = false }
pallet-asset-conversion = { path = "../../../../../../../substrate/frame/asset-conversion", default-features = false }
pallet-balances = { path = "../../../../../../../substrate/frame/balances", default-features = false }
pallet-message-queue = { path = "../../../../../../../substrate/frame/message-queue" }
sp-runtime = { path = "../../../../../../../substrate/primitives/runtime", default-features = false }
sp-io = { path = "../../../../../../../substrate/primitives/io", default-features = false }

# Polkadot
xcm = { package = "staging-xcm", path = "../../../../../../../polkadot/xcm", default-features = false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ use snowbridge_pallet_inbound_queue_fixtures::{
InboundQueueFixture,
};
use snowbridge_pallet_system;
use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor;
use sp_core::H256;
use snowbridge_router_primitives::inbound::{
Command, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage,
};
use sp_core::{H160, H256};
use sp_io::hashing::blake2_256;
use sp_runtime::{ArithmeticError::Underflow, DispatchError::Arithmetic};
use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork;

Expand All @@ -38,6 +41,7 @@ const TREASURY_ACCOUNT: [u8; 32] =
hex!("6d6f646c70792f74727372790000000000000000000000000000000000000000");
const WETH: [u8; 20] = hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d");
const ETHEREUM_DESTINATION_ADDRESS: [u8; 20] = hex!("44a57ee2f2FCcb85FDa2B0B18EBD0D8D2333700e");
const XCM_FEE: u128 = 40_000_000_000;

#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub enum ControlCall {
Expand Down Expand Up @@ -71,17 +75,16 @@ pub fn send_inbound_message(fixture: InboundQueueFixture) -> DispatchResult {
/// Create an agent on Ethereum. An agent is a representation of an entity in the Polkadot
/// ecosystem (like a parachain) on Ethereum.
#[test]
#[ignore]
fn create_agent() {
let origin_para: u32 = 1001;
let origin_para: u32 = 2000;
// Fund the origin parachain sovereign account so that it can pay execution fees.
BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND);

let sudo_origin = <Rococo as Chain>::RuntimeOrigin::root();
let destination = Rococo::child_location_of(BridgeHubRococo::para_id()).into();

let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {});
// Construct XCM to create an agent for para 1001
// Construct XCM to create an agent for para 2000
let remote_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(Parachain(origin_para).into()),
Expand Down Expand Up @@ -128,9 +131,8 @@ fn create_agent() {
/// Create a channel for a consensus system. A channel is a bidirectional messaging channel
/// between BridgeHub and Ethereum.
#[test]
#[ignore]
fn create_channel() {
let origin_para: u32 = 1001;
let origin_para: u32 = 2000;
// Fund AssetHub sovereign account so that it can pay execution fees.
BridgeHubRococo::fund_para_sovereign(origin_para.into(), INITIAL_FUND);

Expand All @@ -139,7 +141,7 @@ fn create_channel() {
Rococo::child_location_of(BridgeHubRococo::para_id()).into();

let create_agent_call = SnowbridgeControl::Control(ControlCall::CreateAgent {});
// Construct XCM to create an agent for para 1001
// Construct XCM to create an agent for para 2000
let create_agent_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(Parachain(origin_para).into()),
Expand All @@ -152,7 +154,7 @@ fn create_channel() {

let create_channel_call =
SnowbridgeControl::Control(ControlCall::CreateChannel { mode: OperatingMode::Normal });
// Construct XCM to create a channel for para 1001
// Construct XCM to create a channel for para 2000
let create_channel_xcm = VersionedXcm::from(Xcm(vec![
UnpaidExecution { weight_limit: Unlimited, check_origin: None },
DescendOrigin(Parachain(origin_para).into()),
Expand Down Expand Up @@ -535,3 +537,52 @@ fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() {
assert_err!(send_inbound_message(make_register_token_message()), Arithmetic(Underflow));
});
}

#[test]
fn transact_from_ethereum_to_penpal() {
vgeddes marked this conversation as resolved.
Show resolved Hide resolved
// Fund sender on penpal so that it can pay execution fees.
let sender: H160 = hex!("ee9170abfbf9421ad6dd07f6bdec9d89f2b581e0").into();
PenpalA::fund_accounts(vec![(
blake2_256(&(b"AccountKey20", sender).encode()).into(),
INITIAL_FUND,
)]);

BridgeHubRococo::execute_with(|| {
type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;

let message_id: H256 = [1; 32].into();
let message = VersionedMessage::V1(MessageV1 {
chain_id: CHAIN_ID,
command: Command::Transact {
sender,
fee: XCM_FEE,
weight_ref_time: 40_000_000,
weight_proof_size: 8_000,
origin_kind: OriginKind::SovereignAccount,
payload: hex!("00071468656c6c6f").to_vec(),
},
});
// Convert the message to XCM
let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap();
// Send the XCM
let _ = EthereumInboundQueue::send_xcm(xcm, PenpalA::para_id().into()).unwrap();

assert_expected_events!(
BridgeHubRococo,
vec![
RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
]
);
});

PenpalA::execute_with(|| {
type RuntimeEvent = <PenpalA as Chain>::RuntimeEvent;
// Check that system event remarked on PenPal
assert_expected_events!(
PenpalA,
vec![
RuntimeEvent::System(frame_system::Event::Remarked { .. }) => {},
]
);
});
}
Loading
Loading