You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Web3.js转移ERC1155代币?调用Monkeys合约getMyToken函数触发“ERC1155: caller is not owner nor approved”错误的问题排查

问题排查与解决方案

咱们一步一步拆解你遇到的问题,先搞清楚错误根源,再给你具体的修复步骤:

核心错误原因分析

你遇到的ERC1155: caller is not owner nor approved错误,主要来自三个关键点:

1. 前端调用方式错误:用了只读的.call()而非交易.send()

你的前端代码里用.call()调用getMyToken(注意你代码里写的mintMyMonkey是笔误,合约里实际方法名是getMyToken),但这个函数是修改链上状态的操作(转移代币)。.call()只能用于只读视图函数,不会发起真实交易,不仅无法完成代币转移,还会因为执行上下文错误触发权限校验失败。

2. 授权对象搞反了

你给接收账户做了setApprovalForAll授权,但这个授权是让接收账户能操作owner的代币吗?不对——你的isApproved函数检查的是owner()是否授权了接收账户,但调用getMyToken的是前端连接的用户账户,这个账户并没有被owner授权可以转移owner的代币。

ERC1155的safeTransferFrom规则是:调用者必须是from(这里是owner)本人,或者是被from授权的operator(通过setApprovalForAll(owner, 调用者账户))。你现在授权的是接收账户,而非执行转移操作的调用者,自然会触发权限错误。

3. 合约方法的权限逻辑缺失

你的getMyToken函数没有任何权限修饰,任何人都能调用,但如果调用者不是owner也没被授权,就会触发ERC1155内置的权限校验。


具体修复方案

方案一:修正前端调用逻辑

先把前端代码的两个错误改掉:

const selectedAccountIsApproved = await monkeysContract.methods.isApproved(selectedAccount).call();
console.log('IS APPROVED RESULT: ', selectedAccountIsApproved);
// 注意:这里的isApproved检查的是接收账户是否被owner授权,实际我们需要的是调用者是否被owner授权
// 如果你想让当前连接账户能调用getMyToken,应该检查isApprovedForAll(owner, 当前账户)
const callerIsApproved = await monkeysContract.methods.isApprovedForAll(ownerAddress, currentConnectedAccount).call();
if(callerIsApproved) {
  // 1. 修正方法名:mintMyMonkey → getMyToken
  // 2. 用send()代替call(),发起真实交易
  const result = await monkeysContract.methods.getMyToken(selectedAccount, 0).send({ 
    from: currentConnectedAccount 
  });
  console.log('Transfer Result: ', result);
} else {
  console.log('Caller account not approved by owner for transfers');
}

方案二:调整合约权限逻辑(更安全)

如果你希望getMyToken只能由owner调用,或者跳过调用者权限校验,可以修改合约:

选项A:给getMyToken添加onlyOwner修饰符

这样只有合约部署者能调用这个函数转移代币:

function getMyToken(address to, uint256 id) public onlyOwner {
    transfer(owner(), to, id, 1, 'test');
}

选项B:改用内部函数_safeTransferFrom跳过调用者权限检查

内部函数_safeTransferFrom不会校验调用者的权限,只检查from的代币余额,适合合约内部发起的转移:

function getMyToken(address to, uint256 id) public {
    _safeTransferFrom(owner(), to, id, 1, 'test');
}

方案三:正确授权调用者账户

由合约owner执行以下代码,给前端连接的用户账户授权:

// 用owner账户发起这个交易
await monkeysContract.methods.setApprovalForAll(currentConnectedAccount, true).send({ 
  from: ownerAddress 
});

授权完成后,调用者账户就有权限执行getMyToken函数了。


额外提醒

  • 你在Etherscan上能成功转移,是因为你用owner账户直接操作的,满足safeTransferFrom的调用者是owner的条件;
  • 后续测试时,一定要区分调用者账户和接收账户的权限差异,不要搞混授权对象。

内容的提问来源于stack exchange,提问作者XCEPTION

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 02:42:31