编译器
0.8.17+commit.8df45f5f
文件 1 的 21:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 21:BDNS.sol
pragma solidity >=0.8.4;
interface BDNS {
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
event Transfer(bytes32 indexed node, address owner);
event NewResolver(bytes32 indexed node, address resolver);
event NewTTL(bytes32 indexed node, uint64 ttl);
event ApprovalForAll(
address indexed owner,
address indexed operator,
bool approved
);
function setRecord(
bytes32 node,
address owner,
address resolver,
uint64 ttl
) external;
function setSubnodeRecord(
bytes32 node,
bytes32 label,
address owner,
address resolver,
uint64 ttl
) external;
function setSubnodeOwner(
bytes32 node,
bytes32 label,
address owner
) external returns (bytes32);
function setResolver(bytes32 node, address resolver) external;
function setOwner(bytes32 node, address owner) external;
function setTTL(bytes32 node, uint64 ttl) external;
function setApprovalForAll(address operator, bool approved) external;
function owner(bytes32 node) external view returns (address);
function resolver(bytes32 node) external view returns (address);
function ttl(bytes32 node) external view returns (uint64);
function recordExists(bytes32 node) external view returns (bool);
function isApprovedForAll(address owner, address operator)
external
view
returns (bool);
}
文件 3 的 21:BytesUtils.sol
pragma solidity ~0.8.17;
library BytesUtils {
function keccak(
bytes memory self,
uint256 offset,
uint256 len
) internal pure returns (bytes32 ret) {
require(offset + len <= self.length);
assembly {
ret := keccak256(add(add(self, 32), offset), len)
}
}
function namehash(bytes memory self, uint256 offset)
internal
pure
returns (bytes32)
{
(bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);
if (labelhash == bytes32(0)) {
require(offset == self.length - 1, "namehash: Junk at end of name");
return bytes32(0);
}
return
keccak256(abi.encodePacked(namehash(self, newOffset), labelhash));
}
function readLabel(bytes memory self, uint256 idx)
internal
pure
returns (bytes32 labelhash, uint256 newIdx)
{
require(idx < self.length, "readLabel: Index out of bounds");
uint256 len = uint256(uint8(self[idx]));
if (len > 0) {
labelhash = keccak(self, idx + 1, len);
} else {
labelhash = bytes32(0);
}
newIdx = idx + len + 1;
}
}
文件 4 的 21:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 5 的 21:Controllable.sol
pragma solidity ~0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
contract Controllable is Ownable {
mapping(address => bool) public controllers;
event ControllerChanged(address indexed controller, bool active);
function setController(address controller, bool active) public onlyOwner {
controllers[controller] = active;
emit ControllerChanged(controller, active);
}
modifier onlyController() {
require(
controllers[msg.sender],
"Controllable: Caller is not a controller"
);
_;
}
}
文件 6 的 21:ERC1155Fuse.sol
pragma solidity ~0.8.17;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/utils/Address.sol";
error OperationProhibited(bytes32 node);
abstract contract ERC1155Fuse is ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
mapping(uint256 => uint256) public _tokens;
mapping(address => mapping(address => bool)) private _operatorApprovals;
function ownerOf(uint256 id) public view virtual returns (address) {
(address owner, , ) = getData(id);
return owner;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC165, IERC165)
returns (bool)
{
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address account, uint256 id)
public
view
virtual
override
returns (uint256)
{
require(
account != address(0),
"ERC1155: balance query for the zero address"
);
(address owner, , ) = getData(id);
if (owner == account) {
return 1;
}
return 0;
}
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(
accounts.length == ids.length,
"ERC1155: accounts and ids length mismatch"
);
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
function setApprovalForAll(address operator, bool approved)
public
virtual
override
{
require(
msg.sender != operator,
"ERC1155: setting approval status for self"
);
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address account, address operator)
public
view
virtual
override
returns (bool)
{
return _operatorApprovals[account][operator];
}
function getData(uint256 tokenId)
public
view
virtual
returns (
address owner,
uint32 fuses,
uint64 expiry
)
{
uint256 t = _tokens[tokenId];
owner = address(uint160(t));
expiry = uint64(t >> 192);
if (block.timestamp > expiry) {
fuses = 0;
} else {
fuses = uint32(t >> 160);
}
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(to != address(0), "ERC1155: transfer to the zero address");
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"ERC1155: caller is not owner nor approved"
);
_transfer(from, to, id, amount, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
ids.length == amounts.length,
"ERC1155: ids and amounts length mismatch"
);
require(to != address(0), "ERC1155: transfer to the zero address");
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"ERC1155: transfer caller is not owner nor approved"
);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
(address oldOwner, uint32 fuses, uint64 expiration) = getData(id);
if (!_canTransfer(fuses)) {
revert OperationProhibited(bytes32(id));
}
require(
amount == 1 && oldOwner == from,
"ERC1155: insufficient balance for transfer"
);
_setData(id, to, fuses, expiration);
}
emit TransferBatch(msg.sender, from, to, ids, amounts);
_doSafeBatchTransferAcceptanceCheck(
msg.sender,
from,
to,
ids,
amounts,
data
);
}
function _setData(
uint256 tokenId,
address owner,
uint32 fuses,
uint64 expiry
) internal virtual {
_tokens[tokenId] =
uint256(uint160(owner)) |
(uint256(fuses) << 160) |
(uint256(expiry) << 192);
}
function _canTransfer(uint32 fuses) internal virtual returns (bool);
function _mint(
bytes32 node,
address owner,
uint32 fuses,
uint64 expiry
) internal virtual {
uint256 tokenId = uint256(node);
(address oldOwner, uint32 oldFuses, uint64 oldExpiry) = getData(
uint256(node)
);
if (oldExpiry > expiry) {
expiry = oldExpiry;
}
require(oldOwner == address(0), "ERC1155: mint of existing token");
require(owner != address(0), "ERC1155: mint to the zero address");
require(
owner != address(this),
"ERC1155: newOwner cannot be the NameWrapper contract"
);
_setData(tokenId, owner, fuses | oldFuses, expiry);
emit TransferSingle(msg.sender, address(0x0), owner, tokenId, 1);
_doSafeTransferAcceptanceCheck(
msg.sender,
address(0),
owner,
tokenId,
1,
""
);
}
function _burn(uint256 tokenId) internal virtual {
(address owner, uint32 fuses, uint64 expiry) = getData(tokenId);
_setData(tokenId, address(0x0), fuses, expiry);
emit TransferSingle(msg.sender, owner, address(0x0), tokenId, 1);
}
function _transfer(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal {
(address oldOwner, uint32 fuses, uint64 expiry) = getData(id);
if (!_canTransfer(fuses)) {
revert OperationProhibited(bytes32(id));
}
require(
amount == 1 && oldOwner == from,
"ERC1155: insufficient balance for transfer"
);
if (oldOwner == to) {
return;
}
_setData(id, to, fuses, expiry);
emit TransferSingle(msg.sender, from, to, id, amount);
_doSafeTransferAcceptanceCheck(msg.sender, from, to, id, amount, data);
}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try
IERC1155Receiver(to).onERC1155Received(
operator,
from,
id,
amount,
data
)
returns (bytes4 response) {
if (
response != IERC1155Receiver(to).onERC1155Received.selector
) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try
IERC1155Receiver(to).onERC1155BatchReceived(
operator,
from,
ids,
amounts,
data
)
returns (bytes4 response) {
if (
response !=
IERC1155Receiver(to).onERC1155BatchReceived.selector
) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
}
文件 7 的 21:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 8 的 21:ERC20Recoverable.sol
pragma solidity >=0.8.17 <0.9.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract ERC20Recoverable is Ownable {
function recoverFunds(
address _token,
address _to,
uint256 _amount
) external onlyOwner {
IERC20(_token).transfer(_to, _amount);
}
}
文件 9 的 21:IBaseRegistrar.sol
import "../registry/BDNS.sol";
import "./IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IBaseRegistrar is IERC721 {
event ControllerAdded(address indexed controller);
event ControllerRemoved(address indexed controller);
event NameMigrated(
uint256 indexed id,
address indexed owner,
uint256 expires
);
event NameRegistered(
uint256 indexed id,
address indexed owner,
uint256 expires
);
event NameRenewed(uint256 indexed id, uint256 expires);
function addController(address controller) external;
function removeController(address controller) external;
function setResolver(address resolver) external;
function nameExpires(uint256 id) external view returns (uint256);
function available(uint256 id) external view returns (bool);
function register(
uint256 id,
address owner,
uint256 duration
) external returns (uint256);
function renew(uint256 id, uint256 duration) external returns (uint256);
function reclaim(uint256 id, address owner) external;
}
文件 10 的 21:IERC1155.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155 is IERC165 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
文件 11 的 21:IERC1155MetadataURI.sol
pragma solidity ^0.8.0;
import "../IERC1155.sol";
interface IERC1155MetadataURI is IERC1155 {
function uri(uint256 id) external view returns (string memory);
}
文件 12 的 21:IERC1155Receiver.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC1155Receiver is IERC165 {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
文件 13 的 21:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 14 的 21:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
文件 15 的 21:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function setApprovalForAll(address operator, bool _approved) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
文件 16 的 21:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 17 的 21:IMetadataService.sol
pragma solidity ~0.8.17;
interface IMetadataService {
function uri(uint256) external view returns (string memory);
}
文件 18 的 21:INameWrapper.sol
pragma solidity ~0.8.17;
import "../registry/BDNS.sol";
import "../ethregistrar/IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "./IMetadataService.sol";
uint32 constant CANNOT_UNWRAP = 1;
uint32 constant CANNOT_BURN_FUSES = 2;
uint32 constant CANNOT_TRANSFER = 4;
uint32 constant CANNOT_SET_RESOLVER = 8;
uint32 constant CANNOT_SET_TTL = 16;
uint32 constant PARENT_CANNOT_CONTROL = 32;
uint32 constant CAN_DO_EVERYTHING = 0;
interface INameWrapper is IERC1155 {
event NameWrapped(
bytes32 indexed node,
bytes name,
address owner,
uint32 fuses,
uint64 expiry
);
event NameUnwrapped(bytes32 indexed node, address owner);
event FusesSet(bytes32 indexed node, uint32 fuses, uint64 expiry);
function bdns() external view returns (BDNS);
function registrar() external view returns (IBaseRegistrar);
function metadataService() external view returns (IMetadataService);
function names(bytes32) external view returns (bytes memory);
function wrap(
string calldata label,
address wrappedOwner,
uint32 fuses,
uint64 _expiry,
address resolver
) external returns (uint64 expiry);
function registerAndWrap(
string calldata label,
address wrappedOwner,
uint256 duration,
address resolver,
uint32 fuses,
uint64 expiry
) external returns (uint256 registrarExpiry);
function renew(
uint256 labelHash,
uint256 duration,
uint32 fuses,
uint64 expiry
) external returns (uint256 expires);
function unwrap(
bytes32 label,
address newRegistrant,
address newController
) external;
function setFuses(bytes32 node, uint32 fuses)
external
returns (uint32 newFuses);
function setRecord(
bytes32 node,
address owner,
address resolver,
uint64 ttl
) external;
function isTokenOwnerOrApproved(bytes32 node, address addr)
external
returns (bool);
function setResolver(bytes32 node, address resolver) external;
function setTTL(bytes32 node, uint64 ttl) external;
function ownerOf(uint256 id) external returns (address owner);
function getData(uint256 id)
external
returns (
address,
uint32,
uint64
);
function allFusesBurned(bytes32 node, uint32 fuseMask)
external
view
returns (bool);
function isWrapped(bytes32 node) external view returns (bool);
}
文件 19 的 21:INameWrapperUpgrade.sol
pragma solidity ~0.8.17;
interface INameWrapperUpgrade {
function wrap(
string calldata label,
address wrappedOwner,
uint32 fuses,
uint64 expiry,
address resolver
) external;
}
文件 20 的 21:NameWrapper.sol
pragma solidity ~0.8.17;
import {ERC1155Fuse, IERC165, OperationProhibited} from "./ERC1155Fuse.sol";
import {Controllable} from "./Controllable.sol";
import {INameWrapper, CANNOT_UNWRAP, CANNOT_BURN_FUSES, CANNOT_TRANSFER, CANNOT_SET_RESOLVER, CANNOT_SET_TTL, PARENT_CANNOT_CONTROL} from "./INameWrapper.sol";
import {INameWrapperUpgrade} from "./INameWrapperUpgrade.sol";
import {IMetadataService} from "./IMetadataService.sol";
import {BDNS} from "../registry/BDNS.sol";
import {IBaseRegistrar} from "../ethregistrar/IBaseRegistrar.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {BytesUtils} from "./BytesUtils.sol";
import {ERC20Recoverable} from "../utils/ERC20Recoverable.sol";
error Unauthorised(bytes32 node, address addr);
error IncorrectTokenType();
error LabelMismatch(bytes32 labelHash, bytes32 expectedLabelhash);
error LabelTooShort();
error LabelTooLong(string label);
error IncorrectTargetOwner(address owner);
error CannotUpgrade();
contract NameWrapper is
Ownable,
ERC1155Fuse,
INameWrapper,
Controllable,
IERC721Receiver,
ERC20Recoverable
{
using BytesUtils for bytes;
BDNS public immutable override bdns;
IBaseRegistrar public immutable override registrar;
IMetadataService public override metadataService;
mapping(bytes32 => bytes) public override names;
string public constant name = "NameWrapper";
bytes32 private constant ROOT_NODE = 0;
INameWrapperUpgrade public upgradeContract;
uint64 private constant MAX_EXPIRY = type(uint64).max;
constructor(
BDNS _bdns,
IBaseRegistrar _registrar,
IMetadataService _metadataService
) {
bdns = _bdns;
registrar = _registrar;
metadataService = _metadataService;
_setData(
uint256(ROOT_NODE),
address(0),
uint32(PARENT_CANNOT_CONTROL | CANNOT_UNWRAP),
MAX_EXPIRY
);
names[ROOT_NODE] = "\x00";
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC1155Fuse, IERC165)
returns (bool)
{
return
interfaceId == type(INameWrapper).interfaceId ||
interfaceId == type(IERC721Receiver).interfaceId ||
super.supportsInterface(interfaceId);
}
function ownerOf(uint256 id)
public
view
override(ERC1155Fuse, INameWrapper)
returns (address owner)
{
return super.ownerOf(id);
}
function getData(uint256 id)
public
view
override(ERC1155Fuse, INameWrapper)
returns (
address,
uint32,
uint64
)
{
return super.getData(id);
}
function setMetadataService(IMetadataService _metadataService)
public
onlyOwner
{
metadataService = _metadataService;
}
function uri(uint256 tokenId) public view override returns (string memory) {
return metadataService.uri(tokenId);
}
function setUpgradeContract(INameWrapperUpgrade _upgradeAddress)
public
onlyOwner
{
if (address(upgradeContract) != address(0)) {
registrar.setApprovalForAll(address(upgradeContract), false);
bdns.setApprovalForAll(address(upgradeContract), false);
}
upgradeContract = _upgradeAddress;
if (address(upgradeContract) != address(0)) {
registrar.setApprovalForAll(address(upgradeContract), true);
bdns.setApprovalForAll(address(upgradeContract), true);
}
}
modifier onlyTokenOwner(bytes32 node) {
if (!isTokenOwnerOrApproved(node, msg.sender)) {
revert Unauthorised(node, msg.sender);
}
_;
}
function isTokenOwnerOrApproved(bytes32 node, address addr)
public
view
override
returns (bool)
{
address owner = ownerOf(uint256(node));
return owner == addr || isApprovedForAll(owner, addr);
}
function wrap(
string calldata label,
address wrappedOwner,
uint32 fuses,
uint64 expiry,
address resolver
) public override returns (uint64) {
uint256 tokenId = uint256(keccak256(bytes(label)));
address registrant = registrar.ownerOf(tokenId);
if (
registrant != msg.sender &&
!registrar.isApprovedForAll(registrant, msg.sender)
) {
revert Unauthorised(
_makeNode(ROOT_NODE, bytes32(tokenId)),
msg.sender
);
}
registrar.transferFrom(registrant, address(this), tokenId);
registrar.reclaim(tokenId, address(this));
return _wrapROOT(label, wrappedOwner, fuses, expiry, resolver);
}
function registerAndWrap(
string calldata label,
address wrappedOwner,
uint256 duration,
address resolver,
uint32 fuses,
uint64 expiry
) external override onlyController returns (uint256 registrarExpiry) {
uint256 tokenId = uint256(keccak256(bytes(label)));
registrarExpiry = registrar.register(tokenId, address(this), duration);
_wrapROOT(label, wrappedOwner, fuses, expiry, resolver);
}
function renew(
uint256 tokenId,
uint256 duration,
uint32 fuses,
uint64 expiry
) external override onlyController returns (uint256 expires) {
bytes32 node = _makeNode(ROOT_NODE, bytes32(tokenId));
expires = registrar.renew(tokenId, duration);
if (isWrapped(node)) {
(address owner, uint32 oldFuses, uint64 oldExpiry) = getData(
uint256(node)
);
expiry = _normaliseExpiry(expiry, oldExpiry, uint64(expires));
_setData(
node,
owner,
oldFuses | fuses | PARENT_CANNOT_CONTROL,
expiry
);
}
}
function unwrap(
bytes32 labelhash,
address registrant,
address controller
) public override onlyTokenOwner(_makeNode(ROOT_NODE, labelhash)) {
if (controller == address(0x0)) {
revert IncorrectTargetOwner(controller);
}
if (registrant == address(this)) {
revert IncorrectTargetOwner(registrant);
}
_unwrap(_makeNode(ROOT_NODE, labelhash), controller);
registrar.safeTransferFrom(
address(this),
registrant,
uint256(labelhash)
);
}
function setFuses(bytes32 node, uint32 fuses)
public
onlyTokenOwner(node)
operationAllowed(node, CANNOT_BURN_FUSES)
returns (uint32)
{
_checkForParentCannotControl(node, fuses);
(address owner, uint32 oldFuses, uint64 expiry) = getData(
uint256(node)
);
fuses |= oldFuses;
_setFuses(node, owner, fuses, expiry);
return fuses;
}
function upgrade(
string calldata label,
address wrappedOwner,
address resolver
) public {
bytes32 labelhash = keccak256(bytes(label));
bytes32 node = _makeNode(ROOT_NODE, labelhash);
(uint32 fuses, uint64 expiry) = _prepareUpgrade(node);
upgradeContract.wrap(
label,
wrappedOwner,
fuses,
expiry,
resolver
);
}
function setRecord(
bytes32 node,
address owner,
address resolver,
uint64 ttl
)
public
override
onlyTokenOwner(node)
operationAllowed(
node,
CANNOT_TRANSFER | CANNOT_SET_RESOLVER | CANNOT_SET_TTL
)
{
bdns.setRecord(node, address(this), resolver, ttl);
(address oldOwner, , ) = getData(uint256(node));
_transfer(oldOwner, owner, uint256(node), 1, "");
}
function setResolver(bytes32 node, address resolver)
public
override
onlyTokenOwner(node)
operationAllowed(node, CANNOT_SET_RESOLVER)
{
bdns.setResolver(node, resolver);
}
function setTTL(bytes32 node, uint64 ttl)
public
override
onlyTokenOwner(node)
operationAllowed(node, CANNOT_SET_TTL)
{
bdns.setTTL(node, ttl);
}
modifier operationAllowed(bytes32 node, uint32 fuseMask) {
(, uint32 fuses, ) = getData(uint256(node));
if (fuses & fuseMask != 0) {
revert OperationProhibited(node);
}
_;
}
function allFusesBurned(bytes32 node, uint32 fuseMask)
public
view
override
returns (bool)
{
(, uint32 fuses, ) = getData(uint256(node));
return fuses & fuseMask == fuseMask;
}
function isWrapped(bytes32 node) public view override returns (bool) {
return
ownerOf(uint256(node)) != address(0) &&
bdns.owner(node) == address(this);
}
function onERC721Received(
address to,
address,
uint256 tokenId,
bytes calldata data
) public override returns (bytes4) {
if (msg.sender != address(registrar)) {
revert IncorrectTokenType();
}
(
string memory label,
address owner,
uint32 fuses,
uint64 expiry,
address resolver
) = abi.decode(data, (string, address, uint32, uint64, address));
bytes32 labelhash = bytes32(tokenId);
bytes32 labelhashFromData = keccak256(bytes(label));
if (labelhashFromData != labelhash) {
revert LabelMismatch(labelhashFromData, labelhash);
}
registrar.reclaim(uint256(labelhash), address(this));
_wrapROOT(label, owner, fuses, expiry, resolver);
return IERC721Receiver(to).onERC721Received.selector;
}
function _canTransfer(uint32 fuses) internal pure override returns (bool) {
return fuses & CANNOT_TRANSFER == 0;
}
function _makeNode(bytes32 node, bytes32 labelhash)
private
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(node, labelhash));
}
function _addLabel(string memory label, bytes memory name)
internal
pure
returns (bytes memory ret)
{
if (bytes(label).length < 1) {
revert LabelTooShort();
}
if (bytes(label).length > 255) {
revert LabelTooLong(label);
}
return abi.encodePacked(uint8(bytes(label).length), label, name);
}
function _mint(
bytes32 node,
address owner,
uint32 fuses,
uint64 expiry
) internal override {
_canFusesBeBurned(node, fuses);
address oldOwner = ownerOf(uint256(node));
if (oldOwner != address(0)) {
_burn(uint256(node));
emit NameUnwrapped(node, address(0));
}
super._mint(node, owner, fuses, expiry);
}
function _wrap(
bytes32 node,
bytes memory name,
address wrappedOwner,
uint32 fuses,
uint64 expiry
) internal {
names[node] = name;
_mint(node, wrappedOwner, fuses, expiry);
emit NameWrapped(node, name, wrappedOwner, fuses, expiry);
}
function _addLabelAndWrap(
bytes32 parentNode,
bytes32 node,
string memory label,
address owner,
uint32 fuses,
uint64 expiry
) internal {
bytes memory name = _addLabel(label, names[parentNode]);
_wrap(node, name, owner, fuses, expiry);
}
function _prepareUpgrade(bytes32 node)
private
returns (uint32 fuses, uint64 expiry)
{
if (address(upgradeContract) == address(0)) {
revert CannotUpgrade();
}
if (!isTokenOwnerOrApproved(node, msg.sender)) {
revert Unauthorised(node, msg.sender);
}
(, fuses, expiry) = getData(uint256(node));
_burn(uint256(node));
}
function _getDataAndNormaliseExpiry(
bytes32 node,
bytes32 labelhash,
uint64 expiry
)
internal
view
returns (
address owner,
uint32 fuses,
uint64
)
{
uint64 oldExpiry;
(owner, fuses, oldExpiry) = getData(uint256(node));
uint64 maxExpiry = uint64(registrar.nameExpires(uint256(labelhash)));
expiry = _normaliseExpiry(expiry, oldExpiry, maxExpiry);
return (owner, fuses, expiry);
}
function _normaliseExpiry(
uint64 expiry,
uint64 oldExpiry,
uint64 maxExpiry
) internal pure returns (uint64) {
if (expiry > maxExpiry) {
expiry = maxExpiry;
}
if (expiry < oldExpiry) {
expiry = oldExpiry;
}
return expiry;
}
function _wrapROOT(
string memory label,
address wrappedOwner,
uint32 fuses,
uint64 expiry,
address resolver
) private returns (uint64) {
bytes32 labelhash = keccak256(bytes(label));
bytes32 node = _makeNode(ROOT_NODE, labelhash);
uint32 oldFuses;
(, oldFuses, expiry) = _getDataAndNormaliseExpiry(
node,
labelhash,
expiry
);
_addLabelAndWrap(
ROOT_NODE,
node,
label,
wrappedOwner,
fuses | PARENT_CANNOT_CONTROL,
expiry
);
if (resolver != address(0)) {
bdns.setResolver(node, resolver);
}
return expiry;
}
function _unwrap(bytes32 node, address owner) private {
if (allFusesBurned(node, CANNOT_UNWRAP)) {
revert OperationProhibited(node);
}
_burn(uint256(node));
bdns.setOwner(node, owner);
emit NameUnwrapped(node, owner);
}
function _setFuses(
bytes32 node,
address owner,
uint32 fuses,
uint64 expiry
) internal {
_setData(node, owner, fuses, expiry);
emit FusesSet(node, fuses, expiry);
}
function _setData(
bytes32 node,
address owner,
uint32 fuses,
uint64 expiry
) internal {
_canFusesBeBurned(node, fuses);
super._setData(uint256(node), owner, fuses, expiry);
}
function _canFusesBeBurned(bytes32 node, uint32 fuses) internal pure {
if (
fuses & ~PARENT_CANNOT_CONTROL != 0 &&
fuses & (PARENT_CANNOT_CONTROL | CANNOT_UNWRAP) !=
(PARENT_CANNOT_CONTROL | CANNOT_UNWRAP)
) {
revert OperationProhibited(node);
}
}
function _checkForParentCannotControl(bytes32 node, uint32 fuses)
internal
view
{
if (fuses & PARENT_CANNOT_CONTROL != 0) {
revert Unauthorised(node, msg.sender);
}
}
}
文件 21 的 21:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
{
"compilationTarget": {
"contracts/wrapper/NameWrapper.sol": "NameWrapper"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 4000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract BDNS","name":"_bdns","type":"address"},{"internalType":"contract IBaseRegistrar","name":"_registrar","type":"address"},{"internalType":"contract IMetadataService","name":"_metadataService","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotUpgrade","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"IncorrectTargetOwner","type":"error"},{"inputs":[],"name":"IncorrectTokenType","type":"error"},{"inputs":[{"internalType":"bytes32","name":"labelHash","type":"bytes32"},{"internalType":"bytes32","name":"expectedLabelhash","type":"bytes32"}],"name":"LabelMismatch","type":"error"},{"inputs":[{"internalType":"string","name":"label","type":"string"}],"name":"LabelTooLong","type":"error"},{"inputs":[],"name":"LabelTooShort","type":"error"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"OperationProhibited","type":"error"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"addr","type":"address"}],"name":"Unauthorised","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"controller","type":"address"},{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"ControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"fuses","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"expiry","type":"uint64"}],"name":"FusesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"NameUnwrapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"fuses","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"expiry","type":"uint64"}],"name":"NameWrapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_tokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint32","name":"fuseMask","type":"uint32"}],"name":"allFusesBurned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bdns","outputs":[{"internalType":"contract BDNS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"controllers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getData","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"addr","type":"address"}],"name":"isTokenOwnerOrApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"isWrapped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataService","outputs":[{"internalType":"contract IMetadataService","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"names","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"address","name":"wrappedOwner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint32","name":"fuses","type":"uint32"},{"internalType":"uint64","name":"expiry","type":"uint64"}],"name":"registerAndWrap","outputs":[{"internalType":"uint256","name":"registrarExpiry","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registrar","outputs":[{"internalType":"contract IBaseRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint32","name":"fuses","type":"uint32"},{"internalType":"uint64","name":"expiry","type":"uint64"}],"name":"renew","outputs":[{"internalType":"uint256","name":"expires","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"controller","type":"address"},{"internalType":"bool","name":"active","type":"bool"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint32","name":"fuses","type":"uint32"}],"name":"setFuses","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IMetadataService","name":"_metadataService","type":"address"}],"name":"setMetadataService","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract INameWrapperUpgrade","name":"_upgradeAddress","type":"address"}],"name":"setUpgradeContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"labelhash","type":"bytes32"},{"internalType":"address","name":"registrant","type":"address"},{"internalType":"address","name":"controller","type":"address"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"address","name":"wrappedOwner","type":"address"},{"internalType":"address","name":"resolver","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upgradeContract","outputs":[{"internalType":"contract INameWrapperUpgrade","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"address","name":"wrappedOwner","type":"address"},{"internalType":"uint32","name":"fuses","type":"uint32"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"address","name":"resolver","type":"address"}],"name":"wrap","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"nonpayable","type":"function"}]