Skip to content

Instantly share code, notes, and snippets.

@mrshiposha
Last active March 14, 2023 22:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrshiposha/af5fcd5d99d4c323ae25d3c9328b3ac6 to your computer and use it in GitHub Desktop.
Save mrshiposha/af5fcd5d99d4c323ae25d3c9328b3ac6 to your computer and use it in GitHub Desktop.
XC-NFT transfer + preimages
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Chain A → the Reserve Chain → Chain B

The XCM program
vec![
    WithdrawAsset(vec![
        (ParentThen(RESERVE_CHAIN_ID), RESERVE_CHAIN_FEE_AMOUNT).into(),
        (ParentThen(CHAIN_B_ID), CHAIN_B_FEE_AMOUNT).into(),
        (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
    ].into()),
    InitiateReserveWithdraw {
        assets: All.into(),
        reserve: ParentThen(RESERVE_CHAIN_ID),
        xcm: vec![
            BuyExecution {
                fees: (ParentThen(RESERVE_CHAIN_ID), RESERVE_CHAIN_FEE_AMOUNT).into(),
                weight: XCM_WEIGHT,
            },
            SetErrorHandler {
                RefundSurplus,
                ReportHolding {
                    response_info: QueryResponseInfo {
                        destination: ParentThen(CHAIN_A_ID).into(),
                        query_id: RESTORE_NFTS_QUERY_ID,
                        max_weight: RESTORE_NFTS_WEIGHT,
                    },
                    assets: (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
                },
            },
            SetTopic(METADATA_HASH),
            DepositReserveAsset {
                assets: All.into(),
                dest: ParentThen(CHAIN_B_ID),
                xcm: vec![
                    BuyExecution {
                        fees: (ParentThen(CHAIN_B_ID), CHAIN_B_FEE_AMOUNT).into(),
                        weight: XCM_WEIGHT,
                    },
                    SetErrorHandler {
                        RefundSurplus,
                        ReportHolding {
                            response_info: QueryResponseInfo {
                                destination: ParentThen(RESERVE_CHAIN_ID).into(),
                                query_id: RESTORE_NFTS_QUERY_ID,
                                max_weight: RESTORE_NFTS_WEIGHT,
                            },
                            assets: (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
                        },
                    },
                    SetTopic(METADATA_HASH),
                    DepositAsset {
                        assets: All.into(),
                        beneficiary: BENEFICIARY,
                    },
                ].into(),
            },
        ].into()
    },
].into()

Bind metadata

    sequenceDiagram
        actor S as Someone
        participant C as Chain

        S -) C: bind_nft_metadata(NFT_ID, METADATA_HASH, keys_count, max_key_size, max_value_size)

        activate C
            C ->> C: Get the metadata preimage

            alt The metadata if found
                C ->> C: Interpret the metadata blob and store the info as native NFT metadata
                C ->> C: Unrequest the preimage
                C --) S: [Event] The metadata is bound
                C ->> C: Refund the unused weight
            else No metadata
                C --) S: [Event] The metadata is not found
                C ->> C: Refund the unused weight
            end
        deactivate C
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

the Derivative Chain → The Reserve Chain

The XCM program
vec![
    WithdrawAsset(vec![
        (ParentThen(RESERVE_CHAIN_ID), FEE_AMOUNT).into(),
        (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
    ].into()),
    InitiateReserveWithdraw {
        assets: All.into(),
        reserve: ParentThen(RESERVE_CHAIN_ID),
        xcm: vec![
            BuyExecution {
                fees: (ParentThen(RESERVE_CHAIN_ID), FEE_AMOUNT).into(),
                weight: XCM_WEIGHT,
            },
            SetErrorHandler {
                RefundSurplus,
                ReportHolding {
                    response_info: QueryResponseInfo {
                        destination: ParentThen(DERIVATIVE_CHAIN_ID).into(),
                        query_id: RESTORE_NFTS_QUERY_ID,
                        max_weight: RESTORE_NFTS_WEIGHT,
                    },
                    assets: (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
                },
            },
            SetTopic(METADATA_HASH),
            DepositAsset {
                assets: All.into(),
                beneficiary: BENEFICIARY,                
            },
        ].into(),
    },
].into()
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

The Reserve Chain → the Derivative Chain

The XCM program
vec![
    TransferReserveAsset {
        assets: vec![
            (ParentThen(DERIVATIVE_CHAIN_ID), FEE_AMOUNT).into(),
            (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
        ].into(),
        dest: ParentThen(DERIVATIVE_CHAIN_ID),
        xcm: vec![
            BuyExecution {
                fees: (ParentThen(DERIVATIVE_CHAIN_ID), FEE_AMOUNT).into(),
                weight: XCM_WEIGHT,
            },
            SetErrorHandler(vec![
                RefundSurplus,
                ReportHolding {
                    response_info: QueryResponseInfo {
                        destination: ParentThen(RESERVE_CHAIN_ID).into(),
                        query_id: RESTORE_NFTS_QUERY_ID,
                        max_weight: RESTORE_NFTS_WEIGHT,
                    },
                    assets: (ParentThen(RESERVE_CHAIN_ID), NFT_ID).into(),
                },
            ].into()),
            SetTopic(METADATA_HASH),
            DepositAsset {
                assets: All.into(),
                beneficiary: BENEFICIARY,                
            },
        ].into(),
    },
].into()

XC-NFT Runtime API

decl_runtime_apis! {
    pub trait XcNftApi {
        /// Acquires the NFT metadata in a standard `NftMetadata` format.
        ///
        /// The `asset` identifies the NFT.
        /// It is an abstract `MultiAsset` to have a standard API between chains.
        /// A particular chain can interpret the `asset` in its way.
        ///
        /// NOTE: The `MetadataAcquireError` and the metadata container format are TBD.
        fn acquire_nft_metadata(asset: MultiAsset) -> Result<Vec<u8>, MetadataAcquireError>;

        /// Checks the metadata to see if it can be bound to the NFT identified by the `asset`.
        ///
        /// Note that the `asset` can be missing on the chain.
        /// This method should check the metadata correctness for the `asset` as if it were on the chain.
        /// This is needed to check an NFT's metadata before transferring it.
        ///
        /// The `asset` is an abstract `MultiAsset` to have a standard API between chains.
        /// A particular chain can interpret the `asset` in its way.
        ///
        /// NOTE: the `MetadataCheckError` is TBD.
        fn check_nft_metadata(asset: MultiAsset, metadata: Vec<u8>) -> Result<(), MetadataCheckError>;
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment