generated at
Soulbound Token
Non-Fungible かつ Non-Transferable なトークン運転免許証卒業証書などの各種の証明書POAP のような参加証明などによくマッチしそうなインターフェイスのトークン



----

WagumiSoulbound Token の実装例

solidity
/** *Submitted for verification at polygonscan.com on 2022-09-08 */ // SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library SbtLib { bytes32 constant SBT_STRUCT_POSITION = keccak256("xyz.wagumi.sbt"); struct SbtStruct { address contractOwner; string name; string symbol; string baseURI; bytes32 validator; mapping(bytes4 => bool) interfaces; mapping(address => uint256) balances; mapping(uint256 => address) owners; mapping(uint256 => SbbStruct[]) sbbs; mapping(bytes32 => uint256) sbbIndex; } struct SbbStruct { uint256 chainId; address contractAddress; uint256 tokenId; } function sbtStorage() internal pure returns (SbtStruct storage sbtstruct) { bytes32 position = SBT_STRUCT_POSITION; assembly { sbtstruct.slot := position } } } // File: diamond/Sbt.sol pragma solidity ^0.8.16.0; contract Sbt { function init( address _contractOwner, string calldata _name, string calldata _symbol, string calldata _baseURI, bytes32 _validator ) external { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); require(sbtstruct.contractOwner == address(0), "INITED ALREADY"); sbtstruct.contractOwner = _contractOwner; sbtstruct.name = _name; sbtstruct.symbol = _symbol; sbtstruct.baseURI = _baseURI; sbtstruct.validator = _validator; sbtstruct.interfaces[(bytes4)(0x01ffc9a7)] = true; //ERC165 sbtstruct.interfaces[(bytes4)(0x5b5e139f)] = true; //ERC721metadata } mapping(bytes4 => address) public implementations; function setImplementation( bytes4[] calldata _sigs, address[] calldata _impAddress ) external { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); require(msg.sender == sbtstruct.contractOwner, "OWNER ONLY"); require(_sigs.length == _impAddress.length, "INVAILED LENGTH"); for (uint256 i = 0; i < _sigs.length; i++) { unchecked { implementations[_sigs[i]] = _impAddress[i]; } } } function contractOwner() external view returns (address) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return sbtstruct.contractOwner; } function supportsInterface(bytes4 _interfaceID) external view returns (bool) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return sbtstruct.interfaces[_interfaceID]; } function name() external view returns (string memory) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return sbtstruct.name; } function symbol() external view returns (string memory) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return sbtstruct.symbol; } function tokenURI(uint256 _tokenId) external view returns (string memory) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return string( abi.encodePacked(sbtstruct.baseURI, toString(_tokenId), ".json") ); } function ownerOf(uint256 _tokenId) external view returns (address) { SbtLib.SbtStruct storage sbtstruct = SbtLib.sbtStorage(); return sbtstruct.owners[_tokenId]; } function toString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { unchecked { digits++; temp /= 10; } } bytes memory buffer = new bytes(digits); while (value != 0) { unchecked { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } } return string(buffer); } fallback() external payable { address _imp = implementations[msg.sig]; require(_imp != address(0), "Function does not exist"); assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), _imp, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } receive() external payable {} }