NEAR协议批量铸造NFT触发存储费用错误,如何实现铸币成本支付?
Rust合约方法
#[payable] pub fn nft_mint(&mut self, nft_list: Vec<Nft>) -> Vec<Token> { let mut t_result: Vec<Token> = Vec::new(); for nft in nft_list { let s = self.tokens.mint(nft.token_id, nft.receiver_id, Some(nft.token_metadata)); t_result.push(s); } return t_result; }
前端调用代码
let token_list = [{ token_id: nanoid(), receiver_id: window.accountId, token_metadata: { id: i, title: "test", myNumber: 123, price: 10, url: "http://..."} }]; window.contract .nft_mint({ nft_list: token_list }) .then((res) => { console.log("Success", res); }).catch(err => { console.log("Error", err); });
触发的错误
{
"type": "action",
"error": {
"type": "functionCallError",
"error": {
"type": "executionError",
"error": "Smart contract panicked: panicked at 'Must attach 6290000000000000000000 yoctoNEAR to cover storage',
/home/HideThePainHarold/.cargo/registry/src/github.com-1ecass99db9ec823/near-contract-standards-3.2.0/src/non_fungible_token/utils.rs:33:5"
}
}
}
咨询问题
- 如何解决该存储费用错误?
- 如何让调用者支付实际铸币费用(而非仅Gas费用)?
1. 解决存储费用错误
NEAR链上存储需要支付成本,错误提示已明确要求附加6290000000000000000000 yoctoNEAR(即0.00629 NEAR)覆盖存储。只需在前端调用时指定附加金额即可:
修改前端调用代码,添加attachedDeposit参数:
window.contract .nft_mint({ nft_list: token_list }, { attachedDeposit: "6290000000000000000000" // 对应错误提示的存储费用金额 }) .then((res) => { console.log("Success", res); }).catch(err => { console.log("Error", err); });
如果需要支持动态批量铸币,也可以在合约中先计算所需存储费用,再验证调用者附加的存款是否足够:
// 在nft_mint方法内,遍历前先计算总存储成本 let total_storage_cost = nft_list.iter() .map(|nft| self.tokens.storage_cost_to_mint(Some(&nft.token_metadata))) .sum::<u128>(); assert!(env::attached_deposit() >= total_storage_cost, "Insufficient deposit for storage, need {} yoctoNEAR", total_storage_cost);
2. 让调用者支付实际铸币费用
可以通过两种方式实现,核心是让调用者附加包含铸币费的存款,并在合约中处理费用转移:
方式一:前端直接附加总费用
在调用时,将存储费和预设的铸币费相加后作为附加金额传递。比如铸币费设为0.1 NEAR,总金额为0.1 + 0.00629 = 0.10629 NEAR(即106290000000000000000000 yoctoNEAR):
window.contract .nft_mint({ nft_list: token_list }, { attachedDeposit: "106290000000000000000000" // 存储费+铸币费总和 }) .then((res) => { console.log("Success", res); }).catch(err => { console.log("Error", err); });
方式二:合约内强制收取铸币费
在合约中定义铸币单价,验证调用者附加的存款是否覆盖存储费+铸币费,再将铸币费转移到合约所有者账户:
use near_sdk::{env, AccountId, Promise}; #[payable] pub fn nft_mint(&mut self, nft_list: Vec<Nft>) -> Vec<Token> { let mut t_result: Vec<Token> = Vec::new(); // 定义单个NFT的铸币费(0.1 NEAR) let mint_fee_per_nft = 100000000000000000000000; let nft_count = nft_list.len() as u128; // 计算总费用:铸币费总和 + 存储费总和 let total_storage_cost = nft_list.iter() .map(|nft| self.tokens.storage_cost_to_mint(Some(&nft.token_metadata))) .sum::<u128>(); let total_required = total_storage_cost + (nft_count * mint_fee_per_nft); // 验证附加存款是否足够 assert!(env::attached_deposit() >= total_required, "Must attach {} yoctoNEAR to cover mint and storage fees", total_required); // 批量铸币 for nft in nft_list { let s = self.tokens.mint(nft.token_id, nft.receiver_id, Some(nft.token_metadata)); t_result.push(s); } // 将铸币费转移到合约所有者账户 let owner_id: AccountId = "your-owner-account.near".parse().unwrap(); Promise::new(owner_id).transfer(nft_count * mint_fee_per_nft); return t_result; }
内容的提问来源于stack exchange,提问作者Suisse

