文件 1 的 5:ENS.sol
pragma solidity >=0.4.24;
interface ENS {
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);
}
文件 2 的 5:IERC165.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 3 的 5:IERC721.sol
pragma solidity >=0.6.2 <0.8.0;
import "../../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) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
文件 4 的 5:RadicleToken.sol
pragma solidity ^0.7.5;
pragma experimental ABIEncoderV2;
contract RadicleToken {
string public constant NAME = "Radicle";
string public constant SYMBOL = "RAD";
uint8 public constant DECIMALS = 18;
uint256 public totalSupply = 100000000e18;
mapping(address => mapping(address => uint96)) internal allowances;
mapping(address => uint96) internal balances;
mapping(address => address) public delegates;
struct Checkpoint {
uint32 fromBlock;
uint96 votes;
}
mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;
mapping(address => uint32) public numCheckpoints;
bytes32 public constant DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
bytes32 public constant DELEGATION_TYPEHASH =
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
bytes32 public constant PERMIT_TYPEHASH =
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
);
mapping(address => uint256) public nonces;
event DelegateChanged(
address indexed delegator,
address indexed fromDelegate,
address indexed toDelegate
);
event DelegateVotesChanged(
address indexed delegate,
uint256 previousBalance,
uint256 newBalance
);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
constructor(address account) {
balances[account] = uint96(totalSupply);
emit Transfer(address(0), account, totalSupply);
}
function name() public pure returns (string memory) {
return NAME;
}
function symbol() public pure returns (string memory) {
return SYMBOL;
}
function decimals() public pure returns (uint8) {
return DECIMALS;
}
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return
keccak256(
abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))
);
}
function allowance(address account, address spender) external view returns (uint256) {
return allowances[account][spender];
}
function approve(address spender, uint256 rawAmount) external returns (bool) {
_approve(msg.sender, spender, rawAmount);
return true;
}
function _approve(
address owner,
address spender,
uint256 rawAmount
) internal {
uint96 amount;
if (rawAmount == uint256(-1)) {
amount = uint96(-1);
} else {
amount = safe96(rawAmount, "RadicleToken::approve: amount exceeds 96 bits");
}
allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function balanceOf(address account) external view returns (uint256) {
return balances[account];
}
function transfer(address dst, uint256 rawAmount) external returns (bool) {
uint96 amount = safe96(rawAmount, "RadicleToken::transfer: amount exceeds 96 bits");
_transferTokens(msg.sender, dst, amount);
return true;
}
function transferFrom(
address src,
address dst,
uint256 rawAmount
) external returns (bool) {
address spender = msg.sender;
uint96 spenderAllowance = allowances[src][spender];
uint96 amount = safe96(rawAmount, "RadicleToken::approve: amount exceeds 96 bits");
if (spender != src && spenderAllowance != uint96(-1)) {
uint96 newAllowance =
sub96(
spenderAllowance,
amount,
"RadicleToken::transferFrom: transfer amount exceeds spender allowance"
);
allowances[src][spender] = newAllowance;
emit Approval(src, spender, newAllowance);
}
_transferTokens(src, dst, amount);
return true;
}
function burnFrom(address account, uint256 rawAmount) public {
require(account != address(0), "RadicleToken::burnFrom: cannot burn from the zero address");
uint96 amount = safe96(rawAmount, "RadicleToken::burnFrom: amount exceeds 96 bits");
address spender = msg.sender;
uint96 spenderAllowance = allowances[account][spender];
if (spender != account && spenderAllowance != uint96(-1)) {
uint96 newAllowance =
sub96(
spenderAllowance,
amount,
"RadicleToken::burnFrom: burn amount exceeds allowance"
);
allowances[account][spender] = newAllowance;
emit Approval(account, spender, newAllowance);
}
balances[account] = sub96(
balances[account],
amount,
"RadicleToken::burnFrom: burn amount exceeds balance"
);
emit Transfer(account, address(0), amount);
_moveDelegates(delegates[account], address(0), amount);
totalSupply -= rawAmount;
}
function delegate(address delegatee) public {
return _delegate(msg.sender, delegatee);
}
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) public {
bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), "RadicleToken::delegateBySig: invalid signature");
require(nonce == nonces[signatory]++, "RadicleToken::delegateBySig: invalid nonce");
require(block.timestamp <= expiry, "RadicleToken::delegateBySig: signature expired");
_delegate(signatory, delegatee);
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public {
bytes32 structHash =
keccak256(
abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)
);
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), structHash));
require(owner == ecrecover(digest, v, r, s), "RadicleToken::permit: invalid signature");
require(owner != address(0), "RadicleToken::permit: invalid signature");
require(block.timestamp <= deadline, "RadicleToken::permit: signature expired");
_approve(owner, spender, value);
}
function getCurrentVotes(address account) external view returns (uint96) {
uint32 nCheckpoints = numCheckpoints[account];
return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
}
function getPriorVotes(address account, uint256 blockNumber) public view returns (uint96) {
require(blockNumber < block.number, "RadicleToken::getPriorVotes: not yet determined");
uint32 nCheckpoints = numCheckpoints[account];
if (nCheckpoints == 0) {
return 0;
}
if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
return checkpoints[account][nCheckpoints - 1].votes;
}
if (checkpoints[account][0].fromBlock > blockNumber) {
return 0;
}
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
uint32 center = upper - (upper - lower) / 2;
Checkpoint memory cp = checkpoints[account][center];
if (cp.fromBlock == blockNumber) {
return cp.votes;
} else if (cp.fromBlock < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
return checkpoints[account][lower].votes;
}
function _delegate(address delegator, address delegatee) internal {
address currentDelegate = delegates[delegator];
uint96 delegatorBalance = balances[delegator];
delegates[delegator] = delegatee;
emit DelegateChanged(delegator, currentDelegate, delegatee);
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}
function _transferTokens(
address src,
address dst,
uint96 amount
) internal {
require(
src != address(0),
"RadicleToken::_transferTokens: cannot transfer from the zero address"
);
require(
dst != address(0),
"RadicleToken::_transferTokens: cannot transfer to the zero address"
);
balances[src] = sub96(
balances[src],
amount,
"RadicleToken::_transferTokens: transfer amount exceeds balance"
);
balances[dst] = add96(
balances[dst],
amount,
"RadicleToken::_transferTokens: transfer amount overflows"
);
emit Transfer(src, dst, amount);
_moveDelegates(delegates[src], delegates[dst], amount);
}
function _moveDelegates(
address srcRep,
address dstRep,
uint96 amount
) internal {
if (srcRep != dstRep && amount > 0) {
if (srcRep != address(0)) {
uint32 srcRepNum = numCheckpoints[srcRep];
uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
uint96 srcRepNew =
sub96(srcRepOld, amount, "RadicleToken::_moveVotes: vote amount underflows");
_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
}
if (dstRep != address(0)) {
uint32 dstRepNum = numCheckpoints[dstRep];
uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
uint96 dstRepNew =
add96(dstRepOld, amount, "RadicleToken::_moveVotes: vote amount overflows");
_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
}
}
}
function _writeCheckpoint(
address delegatee,
uint32 nCheckpoints,
uint96 oldVotes,
uint96 newVotes
) internal {
uint32 blockNumber =
safe32(block.number, "RadicleToken::_writeCheckpoint: block number exceeds 32 bits");
if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
} else {
checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
numCheckpoints[delegatee] = nCheckpoints + 1;
}
emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
}
function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {
require(n < 2**96, errorMessage);
return uint96(n);
}
function add96(
uint96 a,
uint96 b,
string memory errorMessage
) internal pure returns (uint96) {
uint96 c = a + b;
require(c >= a, errorMessage);
return c;
}
function sub96(
uint96 a,
uint96 b,
string memory errorMessage
) internal pure returns (uint96) {
require(b <= a, errorMessage);
return a - b;
}
function getChainId() internal pure returns (uint256) {
uint256 chainId;
assembly {
chainId := chainid()
}
return chainId;
}
}
文件 5 的 5:Registrar.sol
pragma solidity ^0.7.5;
import "@ensdomains/ens/contracts/ENS.sol";
import "./Governance/RadicleToken.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
contract Commitments {
address public owner;
modifier auth {
require(msg.sender == owner, "Commitments: unauthorized");
_;
}
event SetOwner(address usr);
mapping(bytes32 => uint256) public commited;
constructor() {
owner = msg.sender;
}
function setOwner(address usr) external auth {
owner = usr;
emit SetOwner(usr);
}
function commit(bytes32 commitment) external auth {
commited[commitment] = block.number;
}
}
contract Registrar {
ENS public immutable ens;
RadicleToken public immutable rad;
string public constant NAME = "Registrar";
Commitments public immutable commitments = new Commitments();
bytes32 public constant ETH_NODE = keccak256(abi.encodePacked(bytes32(0), keccak256("eth")));
bytes32 public immutable radNode;
uint256 public immutable tokenId;
uint256 public minCommitmentAge;
uint256 public registrationFeeRad = 10e18;
bytes32 public constant DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
bytes32 public constant COMMIT_TYPEHASH =
keccak256("Commit(bytes32 commitment,uint256 nonce,uint256 expiry,uint256 submissionFee)");
mapping(address => uint256) public nonces;
event NameRegistered(string indexed name, bytes32 indexed label, address indexed owner);
event CommitmentMade(bytes32 commitment, uint256 blockNumber);
event AdminChanged(address newAdmin);
event RegistrationRadFeeChanged(uint256 amt);
event DomainOwnershipChanged(address newOwner);
event ResolverChanged(address resolver);
event TTLChanged(uint64 amt);
event MinCommitmentAgeChanged(uint256 amt);
address public admin;
modifier adminOnly {
require(msg.sender == admin, "Registrar: only the admin can perform this action");
_;
}
constructor(
ENS _ens,
RadicleToken _rad,
address _admin,
uint256 _minCommitmentAge,
bytes32 _radNode,
uint256 _tokenId
) {
ens = _ens;
rad = _rad;
admin = _admin;
minCommitmentAge = _minCommitmentAge;
radNode = _radNode;
tokenId = _tokenId;
}
function commit(bytes32 commitment) public {
_commit(msg.sender, commitment);
}
function commitWithPermit(
bytes32 commitment,
address owner,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
rad.permit(owner, address(this), value, deadline, v, r, s);
_commit(msg.sender, commitment);
}
function commitBySig(
bytes32 commitment,
uint256 nonce,
uint256 expiry,
uint256 submissionFee,
uint8 v,
bytes32 r,
bytes32 s
) public {
bytes32 domainSeparator =
keccak256(
abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))
);
bytes32 structHash =
keccak256(abi.encode(COMMIT_TYPEHASH, commitment, nonce, expiry, submissionFee));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), "Registrar::commitBySig: invalid signature");
require(nonce == nonces[signatory]++, "Registrar::commitBySig: invalid nonce");
require(block.timestamp <= expiry, "Registrar::commitBySig: signature expired");
rad.transferFrom(signatory, msg.sender, submissionFee);
_commit(signatory, commitment);
}
function commitBySigWithPermit(
bytes32 commitment,
uint256 nonce,
uint256 expiry,
uint256 submissionFee,
uint8 v,
bytes32 r,
bytes32 s,
address owner,
uint256 value,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) public {
rad.permit(owner, address(this), value, deadline, permitV, permitR, permitS);
commitBySig(commitment, nonce, expiry, submissionFee, v, r, s);
}
function _commit(address payer, bytes32 commitment) internal {
require(commitments.commited(commitment) == 0, "Registrar::commit: already commited");
rad.burnFrom(payer, registrationFeeRad);
commitments.commit(commitment);
emit CommitmentMade(commitment, block.number);
}
function register(
string calldata name,
address owner,
uint256 salt
) external {
bytes32 label = keccak256(bytes(name));
bytes32 commitment = keccak256(abi.encodePacked(name, owner, salt));
uint256 commited = commitments.commited(commitment);
require(valid(name), "Registrar::register: invalid name");
require(available(name), "Registrar::register: name has already been registered");
require(commited != 0, "Registrar::register: must commit before registration");
require(
commited + minCommitmentAge < block.number,
"Registrar::register: commitment too new"
);
ens.setSubnodeRecord(radNode, label, owner, ens.resolver(radNode), ens.ttl(radNode));
emit NameRegistered(name, label, owner);
}
function valid(string memory name) public pure returns (bool) {
uint256 len = bytes(name).length;
return len >= 2 && len <= 128;
}
function available(string memory name) public view returns (bool) {
bytes32 label = keccak256(bytes(name));
bytes32 node = namehash(radNode, label);
return ens.owner(node) == address(0);
}
function namehash(bytes32 parent, bytes32 label) public pure returns (bytes32) {
return keccak256(abi.encodePacked(parent, label));
}
function setDomainOwner(address newOwner) public adminOnly {
IERC721 ethRegistrar = IERC721(ens.owner(ETH_NODE));
ens.setOwner(radNode, newOwner);
ethRegistrar.transferFrom(address(this), newOwner, tokenId);
commitments.setOwner(newOwner);
emit DomainOwnershipChanged(newOwner);
}
function setDomainResolver(address resolver) public adminOnly {
ens.setResolver(radNode, resolver);
emit ResolverChanged(resolver);
}
function setDomainTTL(uint64 ttl) public adminOnly {
ens.setTTL(radNode, ttl);
emit TTLChanged(ttl);
}
function setMinCommitmentAge(uint256 amt) public adminOnly {
minCommitmentAge = amt;
emit MinCommitmentAgeChanged(amt);
}
function setRadRegistrationFee(uint256 amt) public adminOnly {
registrationFeeRad = amt;
emit RegistrationRadFeeChanged(amt);
}
function setAdmin(address newAdmin) public adminOnly {
admin = newAdmin;
emit AdminChanged(newAdmin);
}
function getChainId() internal pure returns (uint256) {
uint256 chainId;
assembly {
chainId := chainid()
}
return chainId;
}
}
{
"compilationTarget": {
"contracts/Registrar.sol": "Registrar"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"},{"internalType":"contract RadicleToken","name":"_rad","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"uint256","name":"_minCommitmentAge","type":"uint256"},{"internalType":"bytes32","name":"_radNode","type":"bytes32"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"commitment","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"CommitmentMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"DomainOwnershipChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"MinCommitmentAgeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"name","type":"string"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"NameRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amt","type":"uint256"}],"name":"RegistrationRadFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"ResolverChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"amt","type":"uint64"}],"name":"TTLChanged","type":"event"},{"inputs":[],"name":"COMMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_NODE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"available","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"submissionFee","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"commitBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"submissionFee","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"permitV","type":"uint8"},{"internalType":"bytes32","name":"permitR","type":"bytes32"},{"internalType":"bytes32","name":"permitS","type":"bytes32"}],"name":"commitBySigWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"commitWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"commitments","outputs":[{"internalType":"contract Commitments","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ens","outputs":[{"internalType":"contract ENS","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minCommitmentAge","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"parent","type":"bytes32"},{"internalType":"bytes32","name":"label","type":"bytes32"}],"name":"namehash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rad","outputs":[{"internalType":"contract RadicleToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"radNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registrationFeeRad","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setDomainOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"resolver","type":"address"}],"name":"setDomainResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"ttl","type":"uint64"}],"name":"setDomainTTL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"setMinCommitmentAge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"setRadRegistrationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"valid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]