TRC-721 合约交互
使用 TronWeb 读取和写入已部署的 TRC-721 合约——查询名称、符号、余额、转账 NFT 以及管理授权。
前置阅读
TRC-721 合约部署后,可用 TronWeb 对其读写。本文通过一组可在 Shasta 测试网直接跑通的 JavaScript 示例,演示常见操作。
共用配置
本页所有示例使用相同的 TronWeb 配置。定义一次,复用即可:
const { TronWeb } = require('tronweb');
const tronWeb = new TronWeb({
fullHost: 'https://api.shasta.trongrid.io',
// headers: { 'TRON-PRO-API-KEY': 'YOUR_API_KEY' }, // 仅主网(api.trongrid.io)需要;Shasta 和 Nile 测试网不需要 API key
privateKey: process.env.PRIVATE_KEY
});
// 替换为你已部署的 TRC-721 合约地址。
const trc721ContractAddress = 'TRio4Fwn...TLwWMNs'; // TRON 地址示例,Base58,共 34 位
切勿提交真实私钥将私钥存储在环境变量(
process.env.PRIVATE_KEY)或密钥管理器中,参见安全最佳实践。
feeLimit 单位下方
.send()调用中使用的feeLimit参数单位为sun(1 TRX = 1,000,000 sun)。示例中使用100_000_000,即 100 TRX。
1. 查询 Token 名称
调用 name() 获取名称。这是一个 view 函数——不消耗能量。
async function trc721Name() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
// call() 用于运行 view/pure 方法,无需广播交易。
const name = await contract.name().call();
console.log('name:', name);
} catch (error) {
console.error('TRC-721 query error', error);
}
}
trc721Name();输出示例:
name: TRC721TEST
2. 查询 Token 符号
调用 symbol() 获取简称。
async function trc721Symbol() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const symbol = await contract.symbol().call();
console.log('symbol:', symbol);
} catch (error) {
console.error('TRC-721 query error', error);
}
}
trc721Symbol();输出示例:
symbol: TEST
3. 查询地址持有的 NFT 数量
调用 balanceOf(address) 获取某账户在该系列中持有的 NFT 总数。
async function trc721BalanceOf() {
const owner = 'TA1g2WQi...jT3ug9uK'; // TRON 地址示例,Base58,共 34 位
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const result = await contract.balanceOf(owner).call();
console.log('balance:', tronWeb.toDecimal(result));
} catch (error) {
console.error('TRC-721 query error', error);
}
}
trc721BalanceOf();输出示例:
balance: 1
4. 转账 NFT
调用 transferFrom(from, to, tokenId) 转账特定 NFT。
async function trc721TransferFrom() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
// send() 执行改变状态的方法并广播交易。
const txHash = await contract
.transferFrom(
'TA1g2WQi...jT3ug9uK', // from
'TM8vRheb...rHjBgC', // to
666 // tokenId
)
.send({ feeLimit: 100_000_000 });
console.log('transferFrom tx hash:', txHash);
} catch (error) {
console.error('TRC-721 transaction error', error);
}
}
trc721TransferFrom();输出示例:
transferFrom tx hash: 9f4d10713cb0406adb7c729013b941d35597afeeba56faf2a1bc7647fc0a92bd
在 Shasta TronScan 上验证该交易。
transferFrom与safeTransferFrom
transferFrom不检查接收方是否是合约,也不检查该合约是否能接受 NFT。如果将 NFT 发送到未实现TRC721TokenReceiver的合约,该 Token 将永久丢失。对于未知接收方,请使用safeTransferFrom。
安全转账替代方案
对于未知接收方,请使用 safeTransferFrom——它会在目标合约上调用接收者钩子,若合约未实现 TRC721TokenReceiver 则 revert:
async function trc721SafeTransferFrom() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const txHash = await contract
.safeTransferFrom(
'TA1g2WQi...jT3ug9uK', // from
'TM8vRheb...rHjBgC', // to(可能是合约)
666 // tokenId
)
.send({ feeLimit: 100_000_000 });
console.log('safeTransferFrom tx hash:', txHash);
} catch (error) {
console.error('TRC-721 transaction error', error);
}
}5. 授权对特定 NFT 的操作权
调用 approve(spender, tokenId) 授权另一个地址代表持有人转账特定 NFT。每个 Token 同一时间只能授权一个地址;再次调用 approve 会替换之前的授权。
async function trc721Approve() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const txHash = await contract
.approve(
'TA1g2WQi...jT3ug9uK', // spender
666 // tokenId
)
.send({ feeLimit: 100_000_000 });
console.log('approve tx hash:', txHash);
} catch (error) {
console.error('TRC-721 transaction error', error);
}
}
trc721Approve();输出示例:
approve tx hash: d7cb1451ed962667f3e24323655dadd8c650ee80d171ea5e44ea97b97eaa3118
为交易市场授权所有 NFT
对于交易市场集成,使用 setApprovalForAll(operator, true) 授权操作员转账当前持有和将来持有的所有 NFT:
async function trc721SetApprovalForAll() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const txHash = await contract
.setApprovalForAll(
'TA1g2WQi...jT3ug9uK', // operator(例如交易市场合约)
true // 授权全部
)
.send({ feeLimit: 100_000_000 });
console.log('setApprovalForAll tx hash:', txHash);
} catch (error) {
console.error('TRC-721 transaction error', error);
}
}6. 查询授权状态
使用 getApproved(tokenId) 查询当前的单 Token 授权,或使用 isApprovedForAll(owner, operator) 查询操作员级别的授权。
async function trc721GetApproved() {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const approved = await contract.getApproved(666).call();
console.log('approved address for tokenId 666:', approved);
} catch (error) {
console.error('TRC-721 query error', error);
}
}
async function trc721IsApprovedForAll() {
const owner = 'TM8vRheb...rHjBgC';
const operator = 'TA1g2WQi...jT3ug9uK';
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const approved = await contract.isApprovedForAll(owner, operator).call();
console.log('isApprovedForAll:', approved);
} catch (error) {
console.error('TRC-721 query error', error);
}
}7. 列出地址持有的所有 NFT
若合约实现了 TRC721Enumerable 扩展,可分三步枚举某地址的全部 NFT:查余额、遍历每个索引、获取每个 tokenId 的 tokenURI。
步骤 7.1 — 获取余额
async function ownerBalance() {
const owner = 'TM8vRheb...rHjBgC';
const contract = await tronWeb.contract().at(trc721ContractAddress);
const result = await contract.balanceOf(owner).call();
console.log('count:', tronWeb.toDecimal(result));
}
ownerBalance();假设结果为 2——该所有者持有两个 NFT。
步骤 7.2 — 遍历每个索引
对从 0 到 balance - 1 的每个索引调用 tokenOfOwnerByIndex(owner, index):
async function tokenOfOwnerByIndex(index) {
const owner = 'TM8vRheb...rHjBgC';
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const tokenId = await contract.tokenOfOwnerByIndex(owner, index).call();
console.log('token_id:', tronWeb.toDecimal(tokenId));
} catch (error) {
console.error('TRC-721 query error', error);
}
}
tokenOfOwnerByIndex(0);
tokenOfOwnerByIndex(1);输出示例:
token_id: 666
token_id: 555
步骤 7.3 — 解析每个 Token 的元数据 URI
调用 tokenURI(tokenId) 获取指向链下元数据 JSON 的指针:
async function trc721TokenURI(tokenId) {
try {
const contract = await tronWeb.contract().at(trc721ContractAddress);
const uri = await contract.tokenURI(tokenId).call();
console.log(`${tokenId} tokenURI:`, uri);
} catch (error) {
console.error('TRC-721 query error', error);
}
}
trc721TokenURI(666);
trc721TokenURI(555);不同的 tokenId 对应不同的 tokenURI 值;系列中每个 NFT 都有自己的元数据文件。离线获取每个 URI(通过 HTTPS 或 BTFS 网关)即可获得描述该 NFT 的 JSON,包括名称、描述、图片 URL 以及其他属性。
相关资源
- TRC-721 —— 标准概览
- TRC-721 协议接口 —— 函数参考
- 发行 TRC-721 Token —— 部署新 TRC-721 合约
- TronWeb SDK —— SDK 参考
Updated 26 days ago