文件 1 的 1:BulkRenewal.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);
}
pragma solidity >=0.4.24;
interface PriceOracle {
function price(string calldata name, uint expires, uint duration) external view returns(uint);
}
pragma solidity >=0.5.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
pragma solidity >=0.5.0;
contract 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) public view returns (uint256 balance);
function ownerOf(uint256 tokenId) public view returns (address owner);
function approve(address to, uint256 tokenId) public;
function getApproved(uint256 tokenId) public view returns (address operator);
function setApprovalForAll(address operator, bool _approved) public;
function isApprovedForAll(address owner, address operator) public view returns (bool);
function transferFrom(address from, address to, uint256 tokenId) public;
function safeTransferFrom(address from, address to, uint256 tokenId) public;
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}
pragma solidity >=0.5.0;
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner());
_;
}
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
pragma solidity >=0.4.24;
contract BaseRegistrar is IERC721, Ownable {
uint constant public GRACE_PERIOD = 90 days;
event ControllerAdded(address indexed controller);
event ControllerRemoved(address indexed controller);
event NameMigrated(uint256 indexed id, address indexed owner, uint expires);
event NameRegistered(uint256 indexed id, address indexed owner, uint expires);
event NameRenewed(uint256 indexed id, uint expires);
ENS public ens;
bytes32 public baseNode;
mapping(address=>bool) public controllers;
function addController(address controller) external;
function removeController(address controller) external;
function setResolver(address resolver) external;
function nameExpires(uint256 id) external view returns(uint);
function available(uint256 id) public view returns(bool);
function register(uint256 id, address owner, uint duration) external returns(uint);
function renew(uint256 id, uint duration) external returns(uint);
function reclaim(uint256 id, address owner) external;
}
pragma solidity >=0.4.24;
library StringUtils {
function strlen(string memory s) internal pure returns (uint) {
uint len;
uint i = 0;
uint bytelength = bytes(s).length;
for(len = 0; i < bytelength; len++) {
byte b = bytes(s)[i];
if(b < 0x80) {
i += 1;
} else if (b < 0xE0) {
i += 2;
} else if (b < 0xF0) {
i += 3;
} else if (b < 0xF8) {
i += 4;
} else if (b < 0xFC) {
i += 5;
} else {
i += 6;
}
}
return len;
}
}
pragma solidity >=0.4.25;
interface Resolver{
event AddrChanged(bytes32 indexed node, address a);
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
event NameChanged(bytes32 indexed node, string name);
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
event ContenthashChanged(bytes32 indexed node, bytes hash);
event ContentChanged(bytes32 indexed node, bytes32 hash);
function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory);
function addr(bytes32 node) external view returns (address);
function addr(bytes32 node, uint coinType) external view returns(bytes memory);
function contenthash(bytes32 node) external view returns (bytes memory);
function dnsrr(bytes32 node) external view returns (bytes memory);
function name(bytes32 node) external view returns (string memory);
function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y);
function text(bytes32 node, string calldata key) external view returns (string memory);
function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address);
function setABI(bytes32 node, uint256 contentType, bytes calldata data) external;
function setAddr(bytes32 node, address addr) external;
function setAddr(bytes32 node, uint coinType, bytes calldata a) external;
function setContenthash(bytes32 node, bytes calldata hash) external;
function setDnsrr(bytes32 node, bytes calldata data) external;
function setName(bytes32 node, string calldata _name) external;
function setPubkey(bytes32 node, bytes32 x, bytes32 y) external;
function setText(bytes32 node, string calldata key, string calldata value) external;
function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external;
function supportsInterface(bytes4 interfaceID) external pure returns (bool);
function content(bytes32 node) external view returns (bytes32);
function multihash(bytes32 node) external view returns (bytes memory);
function setContent(bytes32 node, bytes32 hash) external;
function setMultihash(bytes32 node, bytes calldata hash) external;
}
pragma solidity >=0.5.0;
contract ETHRegistrarController is Ownable {
using StringUtils for *;
uint constant public MIN_REGISTRATION_DURATION = 28 days;
bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
bytes4 constant private COMMITMENT_CONTROLLER_ID = bytes4(
keccak256("rentPrice(string,uint256)") ^
keccak256("available(string)") ^
keccak256("makeCommitment(string,address,bytes32)") ^
keccak256("commit(bytes32)") ^
keccak256("register(string,address,uint256,bytes32)") ^
keccak256("renew(string,uint256)")
);
bytes4 constant private COMMITMENT_WITH_CONFIG_CONTROLLER_ID = bytes4(
keccak256("registerWithConfig(string,address,uint256,bytes32,address,address)") ^
keccak256("makeCommitmentWithConfig(string,address,bytes32,address,address)")
);
BaseRegistrar base;
PriceOracle prices;
uint public minCommitmentAge;
uint public maxCommitmentAge;
mapping(bytes32=>uint) public commitments;
event NameRegistered(string name, bytes32 indexed label, address indexed owner, uint cost, uint expires);
event NameRenewed(string name, bytes32 indexed label, uint cost, uint expires);
event NewPriceOracle(address indexed oracle);
constructor(BaseRegistrar _base, PriceOracle _prices, uint _minCommitmentAge, uint _maxCommitmentAge) public {
require(_maxCommitmentAge > _minCommitmentAge);
base = _base;
prices = _prices;
minCommitmentAge = _minCommitmentAge;
maxCommitmentAge = _maxCommitmentAge;
}
function rentPrice(string memory name, uint duration) view public returns(uint) {
bytes32 hash = keccak256(bytes(name));
return prices.price(name, base.nameExpires(uint256(hash)), duration);
}
function valid(string memory name) public pure returns(bool) {
return name.strlen() >= 3;
}
function available(string memory name) public view returns(bool) {
bytes32 label = keccak256(bytes(name));
return valid(name) && base.available(uint256(label));
}
function makeCommitment(string memory name, address owner, bytes32 secret) pure public returns(bytes32) {
return makeCommitmentWithConfig(name, owner, secret, address(0), address(0));
}
function makeCommitmentWithConfig(string memory name, address owner, bytes32 secret, address resolver, address addr) pure public returns(bytes32) {
bytes32 label = keccak256(bytes(name));
if (resolver == address(0) && addr == address(0)) {
return keccak256(abi.encodePacked(label, owner, secret));
}
require(resolver != address(0));
return keccak256(abi.encodePacked(label, owner, resolver, addr, secret));
}
function commit(bytes32 commitment) public {
require(commitments[commitment] + maxCommitmentAge < now);
commitments[commitment] = now;
}
function register(string calldata name, address owner, uint duration, bytes32 secret) external payable {
registerWithConfig(name, owner, duration, secret, address(0), address(0));
}
function registerWithConfig(string memory name, address owner, uint duration, bytes32 secret, address resolver, address addr) public payable {
bytes32 commitment = makeCommitmentWithConfig(name, owner, secret, resolver, addr);
uint cost = _consumeCommitment(name, duration, commitment);
bytes32 label = keccak256(bytes(name));
uint256 tokenId = uint256(label);
uint expires;
if(resolver != address(0)) {
expires = base.register(tokenId, address(this), duration);
bytes32 nodehash = keccak256(abi.encodePacked(base.baseNode(), label));
base.ens().setResolver(nodehash, resolver);
if (addr != address(0)) {
Resolver(resolver).setAddr(nodehash, addr);
}
base.reclaim(tokenId, owner);
base.transferFrom(address(this), owner, tokenId);
} else {
require(addr == address(0));
expires = base.register(tokenId, owner, duration);
}
emit NameRegistered(name, label, owner, cost, expires);
if(msg.value > cost) {
msg.sender.transfer(msg.value - cost);
}
}
function renew(string calldata name, uint duration) external payable {
uint cost = rentPrice(name, duration);
require(msg.value >= cost);
bytes32 label = keccak256(bytes(name));
uint expires = base.renew(uint256(label), duration);
if(msg.value > cost) {
msg.sender.transfer(msg.value - cost);
}
emit NameRenewed(name, label, cost, expires);
}
function setPriceOracle(PriceOracle _prices) public onlyOwner {
prices = _prices;
emit NewPriceOracle(address(prices));
}
function setCommitmentAges(uint _minCommitmentAge, uint _maxCommitmentAge) public onlyOwner {
minCommitmentAge = _minCommitmentAge;
maxCommitmentAge = _maxCommitmentAge;
}
function withdraw() public onlyOwner {
msg.sender.transfer(address(this).balance);
}
function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
return interfaceID == INTERFACE_META_ID ||
interfaceID == COMMITMENT_CONTROLLER_ID ||
interfaceID == COMMITMENT_WITH_CONFIG_CONTROLLER_ID;
}
function _consumeCommitment(string memory name, uint duration, bytes32 commitment) internal returns (uint256) {
require(commitments[commitment] + minCommitmentAge <= now);
require(commitments[commitment] + maxCommitmentAge > now);
require(available(name));
delete(commitments[commitment]);
uint cost = rentPrice(name, duration);
require(duration >= MIN_REGISTRATION_DURATION);
require(msg.value >= cost);
return cost;
}
}
pragma solidity >=0.5.0;
pragma experimental ABIEncoderV2;
contract BulkRenewal {
bytes32 constant private ETH_NAMEHASH = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
bytes4 constant private REGISTRAR_CONTROLLER_ID = 0x018fac06;
bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
bytes4 constant public BULK_RENEWAL_ID = bytes4(
keccak256("rentPrice(string[],uint)") ^
keccak256("renewAll(string[],uint")
);
ENS public ens;
constructor(ENS _ens) public {
ens = _ens;
}
function getController() internal view returns(ETHRegistrarController) {
Resolver r = Resolver(ens.resolver(ETH_NAMEHASH));
return ETHRegistrarController(r.interfaceImplementer(ETH_NAMEHASH, REGISTRAR_CONTROLLER_ID));
}
function rentPrice(string[] calldata names, uint duration) external view returns(uint total) {
ETHRegistrarController controller = getController();
for(uint i = 0; i < names.length; i++) {
total += controller.rentPrice(names[i], duration);
}
}
function renewAll(string[] calldata names, uint duration) external payable {
ETHRegistrarController controller = getController();
for(uint i = 0; i < names.length; i++) {
uint cost = controller.rentPrice(names[i], duration);
controller.renew.value(cost)(names[i], duration);
}
msg.sender.transfer(address(this).balance);
}
function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
return interfaceID == INTERFACE_META_ID || interfaceID == BULK_RENEWAL_ID;
}
}