Skip to content

Commit

Permalink
XRPL -> TRN NFT bridging (#897)
Browse files Browse the repository at this point in the history
* Add decode_xls20_token function

* Refactors and basic structure

* Add submit_transaction flow, refactor xrpl and fix build errors

* fmt

* Fix xrpl-bridge tests

* Fix xls20 tests

* Fix xls20 benchmarks

* Update Ext trait

* Add benchmarks for xrpl and xls20 for deposit

* Add collection mappings extrinsic + tests for xls20 and nft pallets

* Add test for XRPL pallet

* Update tests to use NFTBuilder

* Add continue to failed route in process_xrp_tx

* Remove transfer flow from deposit

---------

Co-authored-by: JasonTulp <[email protected]>
Co-authored-by: JasonT <[email protected]>
  • Loading branch information
3 people authored Nov 3, 2024
1 parent 6d07f17 commit 79b7f55
Show file tree
Hide file tree
Showing 41 changed files with 1,244 additions and 509 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

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

6 changes: 3 additions & 3 deletions evm-precompiles/nft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ use frame_support::{
ensure,
};
use pallet_evm::{GasWeightMapping, Precompile};
use pallet_nft::{CrossChainCompatibility, WeightInfo};
use pallet_nft::WeightInfo;
use precompile_utils::{constants::ERC721_PRECOMPILE_ADDRESS_PREFIX, prelude::*};
use seed_primitives::{
CollectionUuid, MetadataScheme, OriginChain, RoyaltiesSchedule, TokenCount,
MAX_COLLECTION_ENTITLEMENTS, MAX_ENTITLEMENTS,
CollectionUuid, CrossChainCompatibility, MetadataScheme, OriginChain, RoyaltiesSchedule,
TokenCount, MAX_COLLECTION_ENTITLEMENTS, MAX_ENTITLEMENTS,
};
use sp_core::{H160, U256};
use sp_runtime::{
Expand Down
71 changes: 61 additions & 10 deletions pallet/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ use frame_support::{
};
use frame_system::Config;
use scale_info::TypeInfo;
use seed_primitives::xrpl::Xls20TokenId;
use seed_primitives::{
ethy::{EventClaimId, EventProofId},
AccountId, AssetId, Balance, CollectionUuid, MetadataScheme, OriginChain, RoyaltiesSchedule,
SerialNumber, TokenCount, TokenId, TokenLockReason,
AccountId, AssetId, Balance, CollectionUuid, CrossChainCompatibility, MetadataScheme,
OriginChain, RoyaltiesSchedule, SerialNumber, TokenCount, TokenId, TokenLockReason,
WeightedDispatchResult,
};
use sp_core::{bounded::BoundedVec, H160, U256};
use sp_std::{fmt::Debug, vec::Vec};
Expand Down Expand Up @@ -204,9 +206,6 @@ pub trait EthereumEventRouter {
fn route(source: &H160, destination: &H160, data: &[u8]) -> EventRouterResult;
}

/// Result of processing an event by an `EthereumEventSubscriber`
pub type OnEventResult = Result<Weight, (Weight, DispatchError)>;

/// Handle verified Ethereum events (implemented by handler pallet)
pub trait EthereumEventSubscriber {
/// The destination address of this subscriber (doubles as the source address for sent messages)
Expand All @@ -221,7 +220,7 @@ pub trait EthereumEventSubscriber {

/// process an incoming event from Ethereum
/// Verifies source address then calls on_event
fn process_event(source: &H160, data: &[u8]) -> OnEventResult {
fn process_event(source: &H160, data: &[u8]) -> WeightedDispatchResult {
let verify_weight = Self::verify_source(source)?;
let on_event_weight = Self::on_event(source, data)?;
Ok(verify_weight.saturating_add(on_event_weight))
Expand All @@ -230,7 +229,7 @@ pub trait EthereumEventSubscriber {
/// Verifies the source address
/// Allows pallets to restrict the source based on individual requirements
/// Default implementation compares source with SourceAddress
fn verify_source(source: &H160) -> OnEventResult {
fn verify_source(source: &H160) -> WeightedDispatchResult {
if source != &Self::SourceAddress::get() {
Err((
DbWeight::get().reads(1u64),
Expand All @@ -244,7 +243,7 @@ pub trait EthereumEventSubscriber {
/// Notify subscriber about a event received from Ethereum
/// - `source` the sender address on Ethereum
/// - `data` the Ethereum ABI encoded event data
fn on_event(source: &H160, data: &[u8]) -> OnEventResult;
fn on_event(source: &H160, data: &[u8]) -> WeightedDispatchResult;
}

/// Interface for an Ethereum event bridge
Expand Down Expand Up @@ -377,6 +376,57 @@ impl Xls20MintRequest for () {
}
}

/// Interface for the XLS20 pallet
pub trait Xls20Ext {
type AccountId;

fn deposit_xls20_token(
receiver: &Self::AccountId,
xls20_token_id: Xls20TokenId,
) -> WeightedDispatchResult;

fn get_xls20_token_id(token_id: TokenId) -> Option<Xls20TokenId>;
}

impl Xls20Ext for () {
type AccountId = AccountId;

fn deposit_xls20_token(
_receiver: &Self::AccountId,
_xls20_token_id: Xls20TokenId,
) -> WeightedDispatchResult {
Ok(Weight::zero())
}

fn get_xls20_token_id(_token_id: TokenId) -> Option<Xls20TokenId> {
None
}
}

/// NFT Minter trait allows minting of Bridged NFTs that originate on other chains
pub trait NFTMinter {
type AccountId;

/// Mint bridged tokens from other chain
fn mint_bridged_nft(
owner: &Self::AccountId,
collection_id: CollectionUuid,
serial_numbers: Vec<SerialNumber>,
) -> WeightedDispatchResult;
}

impl NFTMinter for () {
type AccountId = AccountId;

fn mint_bridged_nft(
_owner: &Self::AccountId,
_collection_id: CollectionUuid,
_serial_numbers: Vec<SerialNumber>,
) -> WeightedDispatchResult {
Ok(Weight::zero())
}
}

pub trait NFIRequest {
type AccountId;

Expand Down Expand Up @@ -479,10 +529,10 @@ pub trait NFTExt {

/// Transfer a token from origin to new_owner
fn do_transfer(
origin: Self::AccountId,
origin: &Self::AccountId,
collection_id: CollectionUuid,
serial_numbers: Vec<SerialNumber>,
new_owner: Self::AccountId,
new_owner: &Self::AccountId,
) -> DispatchResult;

/// Create a new collection
Expand All @@ -495,6 +545,7 @@ pub trait NFTExt {
metadata_scheme: MetadataScheme,
royalties_schedule: Option<RoyaltiesSchedule<Self::AccountId>>,
origin_chain: OriginChain,
cross_chain_compatibility: CrossChainCompatibility,
) -> Result<CollectionUuid, DispatchError>;

/// Returns Some(token_owner) for a token if the owner exists
Expand Down
3 changes: 2 additions & 1 deletion pallet/crowdsale/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::Pallet as CrowdSale;
use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite};
use frame_support::traits::fungibles::Inspect;
use frame_system::RawOrigin;
use seed_primitives::{nft::OriginChain, MetadataScheme};
use seed_primitives::{nft::OriginChain, CrossChainCompatibility, MetadataScheme};

pub fn build_collection<T: Config>(collection_owner: T::AccountId) -> CollectionUuid {
T::NFTExt::do_create_collection(
Expand All @@ -31,6 +31,7 @@ pub fn build_collection<T: Config>(collection_owner: T::AccountId) -> Collection
MetadataScheme::try_from(b"https://google.com/".as_slice()).unwrap(),
None,
OriginChain::Root,
CrossChainCompatibility::default(),
)
.unwrap()
}
Expand Down
41 changes: 13 additions & 28 deletions pallet/crowdsale/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,9 @@ use crate::{
Pallet,
};
use frame_support::traits::fungibles::{metadata::Inspect as InspectMetadata, Inspect};
use pallet_nft::{traits::NFTCollectionInfo, CrossChainCompatibility};
use pallet_nft::{test_utils::NftBuilder, traits::NFTCollectionInfo};
use seed_pallet_common::test_prelude::{BlockNumber, *};
use seed_primitives::TokenCount;

// Create an NFT collection
// Returns the created `collection_id`
fn create_nft_collection(owner: AccountId, max_issuance: TokenCount) -> CollectionUuid {
let collection_id = Nft::next_collection_uuid().unwrap();
let collection_name = bounded_string("test-collection");
let metadata_scheme = MetadataScheme::try_from(b"https://google.com/".as_slice()).unwrap();
assert_ok!(Nft::create_collection(
Some(owner).into(),
collection_name,
0,
Some(max_issuance),
None,
metadata_scheme,
None,
CrossChainCompatibility::default(),
));
collection_id
}
use seed_primitives::CrossChainCompatibility;

// Helper function to initialize a crowdsale with default values
fn initialize_crowdsale(
Expand All @@ -58,7 +39,9 @@ fn initialize_crowdsale_with_soft_cap(
max_issuance: Balance,
soft_cap_price: Balance,
) -> (SaleId, SaleInformation<AccountId, BlockNumber>) {
let reward_collection_id = create_nft_collection(alice(), max_issuance.saturated_into());
let reward_collection_id = NftBuilder::<Test>::new(alice())
.max_issuance(max_issuance.saturated_into())
.build();
let payment_asset_id = ROOT_ASSET_ID;
let duration = 100;

Expand Down Expand Up @@ -377,7 +360,8 @@ mod initialize {
fn initialize_works() {
TestExt::<Test>::default().build().execute_with(|| {
let max_issuance = 10_000;
let reward_collection_id = create_nft_collection(alice(), max_issuance);
let reward_collection_id =
NftBuilder::<Test>::new(alice()).max_issuance(max_issuance).build();
let payment_asset_id = 1;
let soft_cap_price = 10;
let duration = 100;
Expand Down Expand Up @@ -451,7 +435,8 @@ mod initialize {
fn initialize_with_voucher_metadata_works() {
TestExt::<Test>::default().build().execute_with(|| {
let max_issuance = 10_000;
let reward_collection_id = create_nft_collection(alice(), max_issuance);
let reward_collection_id =
NftBuilder::<Test>::new(alice()).max_issuance(max_issuance).build();
let payment_asset_id = 1;
let soft_cap_price = 10;
let duration = 100;
Expand Down Expand Up @@ -495,7 +480,7 @@ mod initialize {
#[test]
fn no_ids_fails() {
TestExt::<Test>::default().build().execute_with(|| {
let collection_id = create_nft_collection(alice(), 10);
let collection_id = NftBuilder::<Test>::new(alice()).max_issuance(10).build();
let payment_asset = 1;
let soft_cap_price = 10;
let duration = 100;
Expand All @@ -522,7 +507,7 @@ mod initialize {
#[test]
fn invalid_asset_fails() {
TestExt::<Test>::default().build().execute_with(|| {
let collection_id = create_nft_collection(alice(), 10);
let collection_id = NftBuilder::<Test>::new(alice()).max_issuance(10).build();
let payment_asset = 100; // Payment asset doesn't exist
let soft_cap_price = 10;
let duration = 100;
Expand All @@ -546,7 +531,7 @@ mod initialize {
#[test]
fn invalid_soft_cap_fails() {
TestExt::<Test>::default().build().execute_with(|| {
let collection_id = create_nft_collection(alice(), 10);
let collection_id = NftBuilder::<Test>::new(alice()).max_issuance(10).build();
let payment_asset = 1;
let soft_cap_price = 0;
let duration = 100;
Expand All @@ -570,7 +555,7 @@ mod initialize {
#[test]
fn invalid_sale_duration_fails() {
TestExt::<Test>::default().build().execute_with(|| {
let collection_id = create_nft_collection(alice(), 10);
let collection_id = NftBuilder::<Test>::new(alice()).max_issuance(10).build();
let payment_asset = 1;
let soft_cap_price = 10;
let duration = MaxSaleDuration::get() + 1;
Expand Down
8 changes: 4 additions & 4 deletions pallet/echo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use frame_support::{
PalletId,
};
use frame_system::pallet_prelude::*;
use seed_pallet_common::{EthereumBridge, EthereumEventSubscriber, OnEventResult};
use seed_primitives::{ethy::EventProofId, AccountId};
use seed_pallet_common::{EthereumBridge, EthereumEventSubscriber};
use seed_primitives::{ethy::EventProofId, AccountId, WeightedDispatchResult};
use sp_core::H160;
use sp_std::prelude::*;

Expand Down Expand Up @@ -143,13 +143,13 @@ impl<T: Config> EthereumEventSubscriber for Pallet<T> {
type Address = T::PalletId;
type SourceAddress = ();

fn verify_source(_source: &H160) -> OnEventResult {
fn verify_source(_source: &H160) -> WeightedDispatchResult {
// For testing purposes we don't require a verified source for the Echo pallet
// Can overwrite this method and simply return ok
Ok(Weight::zero())
}

fn on_event(source: &H160, data: &[u8]) -> OnEventResult {
fn on_event(source: &H160, data: &[u8]) -> WeightedDispatchResult {
let abi_decoded = match ethabi::decode(
&[ParamType::Uint(64), ParamType::Uint(64), ParamType::Address],
data,
Expand Down
8 changes: 4 additions & 4 deletions pallet/erc20-peg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use frame_support::{
PalletId,
};
use frame_system::pallet_prelude::*;
use seed_pallet_common::{CreateExt, EthereumBridge, EthereumEventSubscriber, OnEventResult};
use seed_primitives::{AccountId, AssetId, Balance, EthAddress};
use seed_pallet_common::{CreateExt, EthereumBridge, EthereumEventSubscriber};
use seed_primitives::{AccountId, AssetId, Balance, EthAddress, WeightedDispatchResult};
use sp_core::{bounded::WeakBoundedVec, H160, U256};
use sp_runtime::{
traits::{AccountIdConversion, One, Saturating},
Expand Down Expand Up @@ -841,7 +841,7 @@ impl<T: Config> EthereumEventSubscriber for Pallet<T> {

/// Verifies the source address with either the erc20Peg contract address
/// Or the RootPeg contract address
fn verify_source(source: &H160) -> OnEventResult {
fn verify_source(source: &H160) -> WeightedDispatchResult {
let erc20_peg_contract_address: H160 = Self::SourceAddress::get();
let root_peg_contract_address: H160 = RootPegContractAddress::<T>::get();
if source == &erc20_peg_contract_address || source == &root_peg_contract_address {
Expand All @@ -854,7 +854,7 @@ impl<T: Config> EthereumEventSubscriber for Pallet<T> {
}
}

fn on_event(source: &H160, data: &[u8]) -> OnEventResult {
fn on_event(source: &H160, data: &[u8]) -> WeightedDispatchResult {
let abi_decoded = match ethabi::decode(
&[ParamType::Address, ParamType::Uint(128), ParamType::Address],
data,
Expand Down
3 changes: 0 additions & 3 deletions pallet/ethy/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ use sp_core::bounded::WeakBoundedVec;
use sp_runtime::{
generic::DigestItem,
traits::{AccountIdConversion, Convert, SaturatedConversion, Saturating},
transaction_validity::{
InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction,
},
Percent, RuntimeAppPublic,
};
use sp_std::prelude::*;
Expand Down
3 changes: 2 additions & 1 deletion pallet/marketplace/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use frame_support::{
BoundedVec,
};
use frame_system::RawOrigin;
use pallet_nft::{CrossChainCompatibility, Pallet as Nft};
use pallet_nft::Pallet as Nft;
use pallet_sft::Pallet as Sft;
use seed_primitives::nft::CrossChainCompatibility;
use seed_primitives::MetadataScheme;
use sp_runtime::Permill;
use sp_std::{vec, vec::Vec};
Expand Down
Loading

0 comments on commit 79b7f55

Please sign in to comment.