0

I want to transfer NFTs between a relay chain and a parachain. Does anyone have any knowledge or ideas about how to accomplish this

1 Answer 1

1

There was a PR regarding supporting non-fungibles here.

And there are also some nice examples in the XCM Simulator:

/// Scenario:
/// The relay-chain teleports an NFT to a parachain.
///
/// Asserts that the parachain accounts are updated as expected.
#[test]
fn teleport_nft() {
    MockNet::reset();

    Relay::execute_with(|| {
        // Mint the NFT (1, 69) and give it to our "parachain#1 alias".
        assert_ok!(relay_chain::Uniques::mint(
            relay_chain::RuntimeOrigin::signed(ALICE),
            1,
            69,
            child_account_account_id(1, ALICE),
        ));
        // The parachain#1 alias of Alice is what must hold it on the Relay-chain for it to be
        // withdrawable by Alice on the parachain.
        assert_eq!(
            relay_chain::Uniques::owner(1, 69),
            Some(child_account_account_id(1, ALICE))
        );
    });
    ParaA::execute_with(|| {
        assert_ok!(parachain::ForeignUniques::force_create(
            parachain::RuntimeOrigin::root(),
            (Parent, GeneralIndex(1)).into(),
            ALICE,
            false,
        ));
        assert_eq!(
            parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
            None,
        );
        assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);

        // IRL Alice would probably just execute this locally on the Relay-chain, but we can't
        // easily do that here since we only send between chains.
        let message = Xcm(vec![
            WithdrawAsset((GeneralIndex(1), 69u32).into()),
            InitiateTeleport {
                assets: AllCounted(1).into(),
                dest: Parachain(1).into(),
                xcm: Xcm(vec![DepositAsset {
                    assets: AllCounted(1).into(),
                    beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
                }]),
            },
        ]);
        // Send teleport
        let alice = AccountId32 { id: ALICE.into(), network: None };
        assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
    });
    ParaA::execute_with(|| {
        assert_eq!(
            parachain::ForeignUniques::owner((Parent, GeneralIndex(1)).into(), 69u32.into()),
            Some(ALICE),
        );
        assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
    });
    Relay::execute_with(|| {
        assert_eq!(relay_chain::Uniques::owner(1, 69), None);
    });
}

/// Scenario:
/// The relay-chain transfers an NFT into a parachain's sovereign account, who then mints a
/// trustless-backed-derivated locally.
///
/// Asserts that the parachain accounts are updated as expected.
#[test]
fn reserve_asset_transfer_nft() {
    sp_tracing::init_for_tests();
    MockNet::reset();

    Relay::execute_with(|| {
        assert_ok!(relay_chain::Uniques::force_create(
            relay_chain::RuntimeOrigin::root(),
            2,
            ALICE,
            false
        ));
        assert_ok!(relay_chain::Uniques::mint(
            relay_chain::RuntimeOrigin::signed(ALICE),
            2,
            69,
            child_account_account_id(1, ALICE)
        ));
        assert_eq!(
            relay_chain::Uniques::owner(2, 69),
            Some(child_account_account_id(1, ALICE))
        );
    });
    ParaA::execute_with(|| {
        assert_ok!(parachain::ForeignUniques::force_create(
            parachain::RuntimeOrigin::root(),
            (Parent, GeneralIndex(2)).into(),
            ALICE,
            false,
        ));
        assert_eq!(
            parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
            None,
        );
        assert_eq!(parachain::Balances::reserved_balance(&ALICE), 0);

        let message = Xcm(vec![
            WithdrawAsset((GeneralIndex(2), 69u32).into()),
            DepositReserveAsset {
                assets: AllCounted(1).into(),
                dest: Parachain(1).into(),
                xcm: Xcm(vec![DepositAsset {
                    assets: AllCounted(1).into(),
                    beneficiary: (AccountId32 { id: ALICE.into(), network: None },).into(),
                }]),
            },
        ]);
        // Send transfer
        let alice = AccountId32 { id: ALICE.into(), network: None };
        assert_ok!(ParachainPalletXcm::send_xcm(alice, Parent, message));
    });
    ParaA::execute_with(|| {
        log::debug!(target: "xcm-exceutor", "Hello");
        assert_eq!(
            parachain::ForeignUniques::owner((Parent, GeneralIndex(2)).into(), 69u32.into()),
            Some(ALICE),
        );
        assert_eq!(parachain::Balances::reserved_balance(&ALICE), 1000);
    });

    Relay::execute_with(|| {
        assert_eq!(relay_chain::Uniques::owner(2, 69), Some(child_account_id(1)));
    });
}

There was also some discussion in the Polkadot Forum:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.