在同一合约中处理多个 ERC721 代币

Handling multiple ERC721 Tokens in the same Contract

同一个合约是否可以处理多个ERC721代币?如果是,怎么做?

假设您正在制作一款游戏,您需要跟踪两种类型的 ERC721 标记:独特的 Weapons 和独特的 Vehicles.

您可以为它们创建结构,如下所示:

struct Weapon { 
    uint256 IDNumber;
    string type; // Sword, Bow&Arrow, Gun, Rifle, etc.  
    string specialFeature; 
}


struct Vehicle { 
    uint256 IDNumber;
    string type;  // Car, Airplane, Boat, Spaceship, etc.  
    uint256 damageFactor; 
}

要跟踪它们的所有权,您可以将管理它们的数组加倍 - 例如,而不是使用标准:

// Enumerable mapping from token ids to their owners
EnumerableMap.UintToAddressMap private _tokenOwners;

你会做:

// Enumerable mapping from token ids to their owners
EnumerableMap.UintToAddressMap private _weaponTokenOwners;
EnumerableMap.UintToAddressMap private _vehicleTtokenOwners;

(这可能不是最优雅的方式,但它是一个开始。)

但真正的问题是:您将如何处理属于 ERC721 标准的强制性函数,例如 balanceOf()ownerOf()

具体来说,您是否可以说向这些方法的签名添加一个额外的参数以帮助指示您正在查询的特定令牌?

例如,而不是这个:

function balanceOf(address owner) public view override returns (uint256) {

}

您将向函数的签名添加一个 tokenName 参数,如下所示:

function balanceOf(address owner, string tokenName) public view override returns (uint256) {
    if(tokenName == “weapon”) {
       return ownerAndHisWeaponTokensDictionary[owner].length;
    }
    else if(tokenName == “vehicle”) {
       return ownerAndHisVehicleTokensDictionary[owner].length;
    }
}

你会为 ownerOf() 做类似的事情吗?

这是允许的吗? 这甚至是解决这个问题的正确方法 - 或者是否有不同的方法来推理所有这些并以不同的方式处理它?

我的方法是在 3 个单独的地址上定义 3 个单独的合约:

  • 作为武器 ERC-721 代币合约的地址 0x123123
  • 作为 Vehicles ERC-721 代币合约的地址 0x456456
  • 地址0x789789为实际游戏合约

在游戏合约中,您可以调用 NFTs 合约来获取或验证值:

function attack(uint attackerWeaponId) {
    require(weaponsContract.isOwnerOf(msg.sender, attackerWeaponId));
    // ...
}

isOwnerOf() 函数有两个参数,address owneruint256 weaponId。此外,用户可能拥有更多武器,所以这就是我显示验证的原因。

而武器合约 balanceOf(address) 将反映用户拥有的武器 NFT 的总量。

mapping (address => Weapon[]) userOwnedWeapons;

function balanceOf(address owner) external view returns (uint256) {
    return userOwnedWeapons[msg.sender].length;
}