NFT smart contract integration

Follow these requirements before you integrate with our marketplace

NFT requirements

There are two requirements:

  1. Implement nft_transfer_payout and nft_payout

  2. Implement logging for nft_transfer, nft_transfer_call, nft_transfer_payout. Please follow the event standard

Implement nft_transfer_payout

Paras marketplace will call nft_transfer_payout when user purchase the NFT. https://github.com/ParasHQ/paras-marketplace-contract/blob/master/paras-marketplace-contract/src/lib.rs#L213

    fn internal_process_purchase(
        &mut self,
        nft_contract_id: AccountId,
        token_id: TokenId,
        buyer_id: AccountId,
    ) -> Promise {

        let market_data = self.internal_delete_market_data(&nft_contract_id, &token_id); 

        ext_contract::nft_transfer_payout(
            buyer_id.clone(),
            token_id,
            Some(market_data.approval_id),
            Some(U128::from(market_data.price)),
            Some(10u32), // max length payout
            &nft_contract_id,
            1,
            GAS_FOR_NFT_TRANSFER,
        )
        .then(ext_self::resolve_purchase(
            buyer_id,
            market_data,
            &env::current_account_id(),
            NO_DEPOSIT,
            GAS_FOR_ROYALTIES,
        ))
    }

Implementation Standard

https://nomicon.io/Standards/NonFungibleToken/Payout.html

#[derive(Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Payout {
  pub payout: HashMap<AccountId, U128>,
}

pub trait Payouts{
  /// Given a `token_id` and NEAR-denominated balance, return the `Payout`.
  /// struct for the given token. Panic if the length of the payout exceeds
  /// `max_len_payout.`
  fn nft_payout(&self, token_id: String, balance: U128, max_len_payout: u32) -> Payout;
  /// Given a `token_id` and NEAR-denominated balance, transfer the token
  /// and return the `Payout` struct for the given token. Panic if the
  /// length of the payout exceeds `max_len_payout.`
  #[payable]
  fn nft_transfer_payout(
    &mut self,
    receiver_id: AccountId,
    token_id: String,
    approval_id: u64,
    balance: U128,
    max_len_payout: u32,
  ) -> Payout{
    assert_one_yocto();
    let payout = self.nft_payout(token_id, balance);
    self.nft_transfer(receiver_id, token_id, approval_id);
    payout
  }
}

NOTE: If you are not using royalty, then implement nft_transfer_payout as a wrapper for nft_transfer and return HashMap of {"<owner_id>": balance}, e.g.

    #[payable]
    pub fn nft_transfer_payout(
        &mut self,
        receiver_id: ValidAccountId,
        token_id: String,
        approval_id: u64,
        balance: U128,
        max_len_payout: u32,
    ) -> HashMap<AccountId, U128> {
        assert_one_yocto();

        let owner_id = self.tokens.owner_by_id.get(&token_id).expect("Token id does not exist");
        self.tokens.nft_transfer(receiver_id.clone(), token_id.clone(), Some(approval_id), None);

        env::log(
            json!({
                "type": "nft_transfer",
                "params": {
                    "token_id": token_id,
                    "sender_id": owner_id,
                    "receiver_id": receiver_id,
                }
            })
            .to_string()
            .as_bytes(),
        );

        let mut result: HashMap<AccountId, U128> = HashMap::new();
        result.insert(owner_id, balance);
        result
    }

Other nft_transfer_payout implementation

NFT series: https://github.com/near-apps/nft-series/blob/main/contract/src/lib.rs#L207

NFT simple: https://github.com/near-apps/nft-market/blob/main/contracts/nft-simple/src/nft_core.rs#L165

Paras NFT: https://github.com/ParasHQ/paras-nft-contract/blob/main/paras-nft-contract/src/lib.rs#L839

Implement logging (prefered)

Please implement the NFT event standard (https://github.com/near/NEPs/blob/master/specs/Standards/NonFungibleToken/Event.md) on your NFT contract.

Example: https://github.com/near/near-sdk-rs/pull/627

Implement logging (old)

Example : Paras NFT contract (https://github.com/ParasHQ/paras-nft-contract/blob/main/paras-nft-contract/src/lib.rs#L697)


        env::log(
            json!({
                "type": "nft_transfer",
                "params": {
                    "token_id": token_id,
                    "sender_id": sender_id,
                    "receiver_id": receiver_id_str
                }
            })
            .to_string()
            .as_bytes(),
        );

Listing your NFTs on Paras marketplace

By event standard

Any function calls with NFT event standard will automatically trigger a listing on our indexer.

By cold start

Our team will list all of your NFTs into Paras without having to place a sale in the first place.

By nft_approve

Every time there is an nft_approve into paras-marketplace contract then it will be automatically listed on Paras.

Before calling nft_approve, please deposit storage fee for your sale.

storage deposit function call:

near call paras-marketplace-v1.testnet storage_deposit '{"accountId":"orang.testnet"}' --accountId orang.testnet --depositYocto 8590000000000000000000

nft_approve function call:

near call nft_contract_id nft_approve '{"token_id":"<token_id>","account_id":"paras-marketplace-v1.testnet","msg":"{\"market_type\":\"sale\",\"price\":\"1000000000000000000000000\",\"ft_token_id\":\"near\"}"}'

Last updated