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

Commit

Permalink
SNO-104 Add destination parachain id as parameter. (paritytech#533)
Browse files Browse the repository at this point in the history
* added paraId to EthApp

* added event

* fixed e2e tests

* fixed benchmark code

* fixed formatting

* plumbing through pallet xcm to eth app

* added xcm executor to eth-app

* added origin and execute command

* fixed formatting

* fixed tests

* started building xcm message

* use weight estimate

* fixed formatting

* fixed error message

* refactoring out xcm from eth-app

* fixed tests and formatted code

* added xcm attributes

* re-used pallet-xcm instead of forwarding XcmExecutor manually

* converted amount to u128

* built source and destination locations

* buying of execution and deposit asset

* encoded AccountId

* added in weight calculation

* Renamed XcmAssetTransactor to XcmReserveTransfer

* do transfers from erc20 app

* fixed formatting

* whitespace change

* more whitespace

* removed old benchmarking file

* reset file to empty content

* removed crate alias

* updated erc20 app lock call and added in encoding of scale optional types

* fixed erc20 test

* fixed whitespace

* do xcm transfer after mint

* used two different encode calls for each case

* changed encodeCall to encodeCallWithParaId
  • Loading branch information
alistair-singh authored Dec 22, 2021
1 parent 6e18906 commit 49c94b0
Show file tree
Hide file tree
Showing 21 changed files with 290 additions and 43 deletions.
42 changes: 35 additions & 7 deletions ethereum/contracts/ERC20App.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum ChannelId {

contract ERC20App is AccessControl {
using ScaleCodec for uint256;
using ScaleCodec for uint32;
using SafeERC20 for IERC20;

mapping(address => uint256) public balances;
Expand All @@ -27,7 +28,8 @@ contract ERC20App is AccessControl {
address token,
address sender,
bytes32 recipient,
uint256 amount
uint256 amount,
uint32 paraId
);

event Unlocked(
Expand Down Expand Up @@ -62,7 +64,8 @@ contract ERC20App is AccessControl {
address _token,
bytes32 _recipient,
uint256 _amount,
ChannelId _channelId
ChannelId _channelId,
uint32 _paraId
) public {
require(
_channelId == ChannelId.Basic ||
Expand All @@ -72,9 +75,14 @@ contract ERC20App is AccessControl {

balances[_token] = balances[_token] + _amount;

emit Locked(_token, msg.sender, _recipient, _amount);
emit Locked(_token, msg.sender, _recipient, _amount, _paraId);

bytes memory call = encodeCall(_token, msg.sender, _recipient, _amount);
bytes memory call;
if(_paraId == 0) {
call = encodeCall(_token, msg.sender, _recipient, _amount);
} else {
call = encodeCallWithParaId(_token, msg.sender, _recipient, _amount, _paraId);
}

OutboundChannel channel = OutboundChannel(
channels[_channelId].outbound
Expand Down Expand Up @@ -111,14 +119,34 @@ contract ERC20App is AccessControl {
bytes32 _recipient,
uint256 _amount
) private pure returns (bytes memory) {
return
abi.encodePacked(
return abi.encodePacked(
MINT_CALL,
_token,
_sender,
bytes1(0x00), // Encode recipient as MultiAddress::Id
_recipient,
_amount.encode256(),
bytes1(0x00)
);
}

// SCALE-encode payload with parachain Id
function encodeCallWithParaId(
address _token,
address _sender,
bytes32 _recipient,
uint256 _amount,
uint32 _paraId
) private pure returns (bytes memory) {
return abi.encodePacked(
MINT_CALL,
_token,
_sender,
bytes1(0x00), // Encode recipient as MultiAddress::Id
_recipient,
_amount.encode256()
_amount.encode256(),
bytes1(0x01),
_paraId.encode32()
);
}
}
66 changes: 56 additions & 10 deletions ethereum/contracts/ETHApp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,25 @@ import "./RewardSource.sol";
import "./ScaleCodec.sol";
import "./OutboundChannel.sol";

enum ChannelId {Basic, Incentivized}
enum ChannelId {
Basic,
Incentivized
}

contract ETHApp is RewardSource, AccessControl {
using ScaleCodec for uint256;
using ScaleCodec for uint32;

uint256 public balance;

mapping(ChannelId => Channel) public channels;

event Locked(address sender, bytes32 recipient, uint256 amount);
event Locked(
address sender,
bytes32 recipient,
uint256 amount,
uint32 paraId
);

event Unlocked(bytes32 sender, address recipient, uint256 amount);

Expand Down Expand Up @@ -52,7 +61,11 @@ contract ETHApp is RewardSource, AccessControl {
_setupRole(INBOUND_CHANNEL_ROLE, _incentivized.inbound);
}

function lock(bytes32 _recipient, ChannelId _channelId) public payable {
function lock(
bytes32 _recipient,
ChannelId _channelId,
uint32 _paraId
) public payable {
require(msg.value > 0, "Value of transaction must be positive");
require(
_channelId == ChannelId.Basic ||
Expand All @@ -62,12 +75,27 @@ contract ETHApp is RewardSource, AccessControl {

balance = balance + msg.value;

emit Locked(msg.sender, _recipient, msg.value);
emit Locked(msg.sender, _recipient, msg.value, _paraId);

bytes memory call = encodeCall(msg.sender, _recipient, msg.value);
bytes memory call;
if(_paraId == 0) {
call = encodeCall(
msg.sender,
_recipient,
msg.value
);
} else {
call = encodeCallWithParaId(
msg.sender,
_recipient,
msg.value,
_paraId
);
}

OutboundChannel channel =
OutboundChannel(channels[_channelId].outbound);
OutboundChannel channel = OutboundChannel(
channels[_channelId].outbound
);
channel.submit(msg.sender, call);
}

Expand All @@ -94,13 +122,31 @@ contract ETHApp is RewardSource, AccessControl {
bytes32 _recipient,
uint256 _amount
) private pure returns (bytes memory) {
return
abi.encodePacked(
return abi.encodePacked(
MINT_CALL,
_sender,
bytes1(0x00), // Encode recipient as MultiAddress::Id
_recipient,
_amount.encode256(),
bytes1(0x00)
);
}

// SCALE-encode payload with parachain Id
function encodeCallWithParaId(
address _sender,
bytes32 _recipient,
uint256 _amount,
uint32 _paraId
) private pure returns (bytes memory) {
return abi.encodePacked(
MINT_CALL,
_sender,
bytes1(0x00), // Encode recipient as MultiAddress::Id
_recipient,
_amount.encode256()
_amount.encode256(),
bytes1(0x01),
_paraId.encode32()
);
}

Expand Down
3 changes: 2 additions & 1 deletion ethereum/test/test_erc20_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const lockupFunds = (contract, token, sender, recipient, amount, channel) => {
addressBytes(recipient),
amount.toString(),
channel,
0, // paraId
{
from: sender,
value: 0
Expand Down Expand Up @@ -125,7 +126,7 @@ describe("ERC20App", function () {
amount.toString(),
{
from: inboundChannel,
}
},
).should.be.fulfilled;
printTxPromiseGas(txPromise)
const { receipt } = await txPromise;
Expand Down
1 change: 1 addition & 0 deletions ethereum/test/test_eth_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const lockupFunds = (contract, sender, recipient, amount, channel) => {
return contract.lock(
addressBytes(recipient),
channel,
0, // paraId
{
from: sender,
value: amount.toString(),
Expand Down
2 changes: 2 additions & 0 deletions parachain/Cargo.lock

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

4 changes: 4 additions & 0 deletions parachain/pallets/assets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ where
T: Config,
I: Get<AssetId>,
{
fn asset_id() -> AssetId {
I::get()
}

fn total_issuance() -> U256 {
Module::<T>::total_issuance(I::get())
}
Expand Down
2 changes: 1 addition & 1 deletion parachain/pallets/erc20-app/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ benchmarks! {
let sender = H160::zero();
let amount: U256 = 500.into();

let call = Call::<T>::mint { token: token, sender: sender, recipient: recipient_lookup, amount : amount};
let call = Call::<T>::mint { token: token, sender: sender, recipient: recipient_lookup, amount : amount, para_id: None};

}: { call.dispatch_bypass_filter(origin)? }
verify {
Expand Down
15 changes: 12 additions & 3 deletions parachain/pallets/erc20-app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use sp_core::{H160, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::prelude::*;

use snowbridge_core::{AssetId, ChannelId, MultiAsset, OutboundRouter};
use snowbridge_core::{assets::XcmReserveTransfer, AssetId, ChannelId, MultiAsset, OutboundRouter};

use payload::OutboundPayload;
pub use weights::WeightInfo;
Expand Down Expand Up @@ -67,6 +67,8 @@ pub mod pallet {
type CallOrigin: EnsureOrigin<Self::Origin, Success = H160>;

type WeightInfo: WeightInfo;

type XcmReserveTransfer: XcmReserveTransfer<Self::AccountId, Self::Origin>;
}

#[pallet::hooks]
Expand Down Expand Up @@ -146,14 +148,21 @@ pub mod pallet {
sender: H160,
recipient: <T::Lookup as StaticLookup>::Source,
amount: U256,
para_id: Option<u32>,
) -> DispatchResult {
let who = T::CallOrigin::ensure_origin(origin)?;
let who = T::CallOrigin::ensure_origin(origin.clone())?;
if who != <Address<T>>::get() {
return Err(DispatchError::BadOrigin.into())
}

let recipient = T::Lookup::lookup(recipient)?;
T::Assets::deposit(AssetId::Token(token), &recipient, amount)?;
let asset_id = AssetId::Token(token);
T::Assets::deposit(asset_id, &recipient, amount)?;

if let Some(id) = para_id {
T::XcmReserveTransfer::reserve_transfer(origin, asset_id, id, &recipient, amount)?;
}

Self::deposit_event(Event::Minted(token, sender, recipient, amount));

Ok(())
Expand Down
16 changes: 15 additions & 1 deletion parachain/pallets/erc20-app/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use sp_runtime::{
};

use snowbridge_assets::SingleAssetAdaptor;
use snowbridge_core::{AssetId, ChannelId};
use snowbridge_core::{assets::XcmReserveTransfer, AssetId, ChannelId};

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;
Expand Down Expand Up @@ -131,12 +131,26 @@ impl snowbridge_incentivized_channel::outbound::Config for Test {
type WeightInfo = ();
}

pub struct XcmAssetTransfererMock<T>(PhantomData<T>);
impl XcmReserveTransfer<AccountId, Origin> for XcmAssetTransfererMock<Test> {
fn reserve_transfer(
_origin: Origin,
_asset_id: AssetId,
_para_id: u32,
_dest: &AccountId,
_amount: ethabi::U256,
) -> DispatchResult {
todo!()
}
}

impl crate::Config for Test {
type Event = Event;
type Assets = Assets;
type OutboundRouter = OutboundRouter<Test>;
type CallOrigin = snowbridge_dispatch::EnsureEthereumAccount;
type WeightInfo = ();
type XcmReserveTransfer = XcmAssetTransfererMock<Self>;
}

#[cfg(feature = "runtime-benchmarks")]
Expand Down
3 changes: 2 additions & 1 deletion parachain/pallets/erc20-app/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ fn mints_after_handling_ethereum_event() {
token,
sender,
recipient.clone(),
amount.into()
amount.into(),
None
));
assert_eq!(Assets::balance(AssetId::Token(token), &recipient), amount.into());

Expand Down
3 changes: 1 addition & 2 deletions parachain/pallets/eth-app/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ benchmarks! {
let sender = H160::zero();
let amount: U256 = 500.into();

let call = Call::<T>::mint { sender: sender, recipient: recipient_lookup, amount : amount};

let call = Call::<T>::mint { sender: sender, recipient: recipient_lookup, amount: amount, para_id: None };
}: { call.dispatch_bypass_filter(origin)? }
verify {
assert_eq!(T::Asset::balance(&recipient), amount);
Expand Down
21 changes: 17 additions & 4 deletions parachain/pallets/eth-app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ use sp_core::{H160, U256};
use sp_runtime::traits::StaticLookup;
use sp_std::prelude::*;

use snowbridge_core::{ChannelId, OutboundRouter, SingleAsset};
use snowbridge_core::{assets::XcmReserveTransfer, ChannelId, OutboundRouter, SingleAsset};

pub use pallet::*;
use payload::OutboundPayload;
pub use weights::WeightInfo;

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {

Expand All @@ -67,6 +66,8 @@ pub mod pallet {
type CallOrigin: EnsureOrigin<Self::Origin, Success = H160>;

type WeightInfo: WeightInfo;

type XcmReserveTransfer: XcmReserveTransfer<Self::AccountId, Self::Origin>;
}

#[pallet::hooks]
Expand Down Expand Up @@ -141,14 +142,26 @@ pub mod pallet {
sender: H160,
recipient: <T::Lookup as StaticLookup>::Source,
amount: U256,
para_id: Option<u32>,
) -> DispatchResult {
let who = T::CallOrigin::ensure_origin(origin)?;
let who = T::CallOrigin::ensure_origin(origin.clone())?;
if who != <Address<T>>::get() {
return Err(DispatchError::BadOrigin.into())
}

let recipient = T::Lookup::lookup(recipient)?;
T::Asset::deposit(&recipient, amount)?;

if let Some(id) = para_id {
T::XcmReserveTransfer::reserve_transfer(
origin,
T::Asset::asset_id(),
id,
&recipient,
amount,
)?;
}

Self::deposit_event(Event::Minted(sender, recipient.clone(), amount));

Ok(())
Expand Down
Loading

0 comments on commit 49c94b0

Please sign in to comment.