Transaction Hash:
Block:
24482509 at Feb-18-2026 08:24:59 AM +UTC
Transaction Fee:
0.000186655825708192 ETH
$0.37
Gas Used:
91,844 Gas / 2.032313768 Gwei
Emitted Events:
| 276 |
BaseRegistrarImplementation.NameRenewed( id=34419449573917233387833017832830560321047379427340927702376763611889045818583, expires=1771593186 )
|
| 277 |
ETHRegistrarController.NameRenewed( name=1201, label=4C18B7D4A0E4F2C46154995D106079228D62C5881D3D1D55517DEAC2D5774CD7, cost=647089899955918, expires=1771593186 )
|
Account State Difference:
| Address | Before | After | State Difference | ||
|---|---|---|---|---|---|
| 0x283Af0B2...A627EB7F5 | (ENS: Old ETH Registrar Controller) | 772.001228347233462739 Eth | 772.001875437133418657 Eth | 0.000647089899955918 | |
|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 19.596340602887216408 Eth | 19.596524290887216408 Eth | 0.000183688 | |
| 0x57f1887a...Af147eA85 | |||||
| 0xb7fbe2b5...2BDC7886D |
0.08128047933614927 Eth
Nonce: 2685
|
0.08044673361048516 Eth
Nonce: 2686
| 0.00083374572566411 |
Execution Trace
ETH 0.000711798889951509
ETHRegistrarController.renew( name=1201, duration=258767 )
-
BaseRegistrarImplementation.nameExpires( id=34419449573917233387833017832830560321047379427340927702376763611889045818583 ) => ( 1771334419 )
ExponentialPremiumPriceOracle.price( name=1201, expires=1771334419, duration=258767 ) => ( 647089899955918 )EACAggregatorProxy.STATICCALL( )-
0x7d4e742018fb52e48b08be73d041c18b21de6fb5.STATICCALL( )
-
BaseRegistrarImplementation.renew( id=34419449573917233387833017832830560321047379427340927702376763611889045818583, duration=258767 ) => ( 1771593186 )
-
ENSRegistryWithFallback.owner( node=93CDEB708B7545DC668EB9280176169D1C33CFD8ED6F04690A0BCC88A93FC4AE ) => ( 0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85 )
-
- ETH 0.000064708989995591
0xb7fbe2b55b4affe8a45af46663fa9602bdc7886d.CALL( )
File 1 of 5: ETHRegistrarController
File 2 of 5: BaseRegistrarImplementation
File 3 of 5: ExponentialPremiumPriceOracle
File 4 of 5: EACAggregatorProxy
File 5 of 5: ENSRegistryWithFallback
// File: @ensdomains/ethregistrar/contracts/PriceOracle.sol
pragma solidity >=0.4.24;
interface PriceOracle {
/**
* @dev Returns the price to register or renew a name.
* @param name The name being registered or renewed.
* @param expires When the name presently expires (0 if this is a new registration).
* @param duration How long the name is being registered or extended for, in seconds.
* @return The price of this renewal or registration, in wei.
*/
function price(string calldata name, uint expires, uint duration) external view returns(uint);
}
// File: @ensdomains/ens/contracts/ENS.sol
pragma solidity >=0.4.24;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when an operator is added or removed.
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);
}
// File: openzeppelin-solidity/contracts/introspection/IERC165.sol
pragma solidity ^0.5.0;
/**
* @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface IERC165 {
/**
* @notice Query if a contract implements an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
pragma solidity ^0.5.0;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
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;
}
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.5.0;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @return the address of the owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner());
_;
}
/**
* @return true if `msg.sender` is the owner of the contract.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// File: @ensdomains/ethregistrar/contracts/BaseRegistrar.sol
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);
// The ENS registry
ENS public ens;
// The namehash of the TLD this registrar owns (eg, .eth)
bytes32 public baseNode;
// A map of addresses that are authorised to register and renew names.
mapping(address=>bool) public controllers;
// Authorises a controller, who can register and renew domains.
function addController(address controller) external;
// Revoke controller permission for an address.
function removeController(address controller) external;
// Set the resolver for the TLD this registrar manages.
function setResolver(address resolver) external;
// Returns the expiration timestamp of the specified label hash.
function nameExpires(uint256 id) external view returns(uint);
// Returns true iff the specified name is available for registration.
function available(uint256 id) public view returns(bool);
/**
* @dev Register a name.
*/
function register(uint256 id, address owner, uint duration) external returns(uint);
function renew(uint256 id, uint duration) external returns(uint);
/**
* @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
*/
function reclaim(uint256 id, address owner) external;
}
// File: @ensdomains/ethregistrar/contracts/StringUtils.sol
pragma solidity >=0.4.24;
library StringUtils {
/**
* @dev Returns the length of a given string
*
* @param s The string to measure the length of
* @return The length of the input string
*/
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;
}
}
// File: @ensdomains/resolver/contracts/Resolver.sol
pragma solidity >=0.4.25;
/**
* A generic resolver interface which includes all the functions including the ones deprecated
*/
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);
/* Deprecated events */
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);
/* Deprecated functions */
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;
}
// File: @ensdomains/ethregistrar/contracts/ETHRegistrarController.sol
pragma solidity ^0.5.0;
/**
* @dev A registrar controller for registering and renewing names at fixed cost.
*/
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)) {
// Set this contract as the (temporary) owner, giving it
// permission to set up the resolver.
expires = base.register(tokenId, address(this), duration);
// The nodehash of this label
bytes32 nodehash = keccak256(abi.encodePacked(base.baseNode(), label));
// Set the resolver
base.ens().setResolver(nodehash, resolver);
// Configure the resolver
if (addr != address(0)) {
Resolver(resolver).setAddr(nodehash, addr);
}
// Now transfer full ownership to the expeceted owner
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);
// Refund any extra payment
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 a valid commitment
require(commitments[commitment] + minCommitmentAge <= now);
// If the commitment is too old, or the name is registered, stop
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;
}
}File 2 of 5: BaseRegistrarImplementation
// File: @ensdomains/ens/contracts/ENS.sol
pragma solidity >=0.4.24;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when an operator is added or removed.
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);
}
// File: openzeppelin-solidity/contracts/introspection/IERC165.sol
pragma solidity ^0.5.0;
/**
* @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface IERC165 {
/**
* @notice Query if a contract implements an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @dev Interface identification is specified in ERC-165. This function
* uses less than 30,000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol
pragma solidity ^0.5.0;
/**
* @title ERC721 Non-Fungible Token Standard basic interface
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
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;
}
// File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol
pragma solidity ^0.5.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
contract IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `safeTransfer`. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @param operator The address which called `safeTransferFrom` function
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4);
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.5.0;
/**
* @title SafeMath
* @dev Unsigned math operations with safety checks that revert on error
*/
library SafeMath {
/**
* @dev Multiplies two unsigned integers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two unsigned integers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
// File: openzeppelin-solidity/contracts/utils/Address.sol
pragma solidity ^0.5.0;
/**
* Utility library of inline functions on addresses
*/
library Address {
/**
* Returns whether the target address is a contract
* @dev This function will return false if invoked during the constructor of a contract,
* as the code is not actually created until after the constructor finishes.
* @param account address of the account to check
* @return whether the target address is a contract
*/
function isContract(address account) internal view returns (bool) {
uint256 size;
// XXX Currently there is no better way to check if there is a contract in an address
// than to check the size of the code at that address.
// See https://ethereum.stackexchange.com/a/14016/36603
// for more details about how this works.
// TODO Check this again before the Serenity release, because all addresses will be
// contracts then.
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
}
// File: openzeppelin-solidity/contracts/introspection/ERC165.sol
pragma solidity ^0.5.0;
/**
* @title ERC165
* @author Matt Condon (@shrugs)
* @dev Implements ERC165 using a lookup table.
*/
contract ERC165 is IERC165 {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/**
* 0x01ffc9a7 ===
* bytes4(keccak256('supportsInterface(bytes4)'))
*/
/**
* @dev a mapping of interface id to whether or not it's supported
*/
mapping(bytes4 => bool) private _supportedInterfaces;
/**
* @dev A contract implementing SupportsInterfaceWithLookup
* implement ERC165 itself
*/
constructor () internal {
_registerInterface(_INTERFACE_ID_ERC165);
}
/**
* @dev implement supportsInterface(bytes4) using a lookup table
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool) {
return _supportedInterfaces[interfaceId];
}
/**
* @dev internal method for registering an interface
*/
function _registerInterface(bytes4 interfaceId) internal {
require(interfaceId != 0xffffffff);
_supportedInterfaces[interfaceId] = true;
}
}
// File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol
pragma solidity ^0.5.0;
/**
* @title ERC721 Non-Fungible Token Standard basic implementation
* @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
*/
contract ERC721 is ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
// which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
// Mapping from token ID to owner
mapping (uint256 => address) private _tokenOwner;
// Mapping from token ID to approved address
mapping (uint256 => address) private _tokenApprovals;
// Mapping from owner to number of owned token
mapping (address => uint256) private _ownedTokensCount;
// Mapping from owner to operator approvals
mapping (address => mapping (address => bool)) private _operatorApprovals;
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
/*
* 0x80ac58cd ===
* bytes4(keccak256('balanceOf(address)')) ^
* bytes4(keccak256('ownerOf(uint256)')) ^
* bytes4(keccak256('approve(address,uint256)')) ^
* bytes4(keccak256('getApproved(uint256)')) ^
* bytes4(keccak256('setApprovalForAll(address,bool)')) ^
* bytes4(keccak256('isApprovedForAll(address,address)')) ^
* bytes4(keccak256('transferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
*/
constructor () public {
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(_INTERFACE_ID_ERC721);
}
/**
* @dev Gets the balance of the specified address
* @param owner address to query the balance of
* @return uint256 representing the amount owned by the passed address
*/
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0));
return _ownedTokensCount[owner];
}
/**
* @dev Gets the owner of the specified token ID
* @param tokenId uint256 ID of the token to query the owner of
* @return owner address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0));
return owner;
}
/**
* @dev Approves another address to transfer the given token ID
* The zero address indicates there is no approved address.
* There can only be one approved address per token at a given time.
* Can only be called by the token owner or an approved operator.
* @param to address to be approved for the given token ID
* @param tokenId uint256 ID of the token to be approved
*/
function approve(address to, uint256 tokenId) public {
address owner = ownerOf(tokenId);
require(to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
/**
* @dev Gets the approved address for a token ID, or zero if no address set
* Reverts if the token ID does not exist.
* @param tokenId uint256 ID of the token to query the approval of
* @return address currently approved for the given token ID
*/
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId));
return _tokenApprovals[tokenId];
}
/**
* @dev Sets or unsets the approval of a given operator
* An operator is allowed to transfer all tokens of the sender on their behalf
* @param to operator address to set the approval
* @param approved representing the status of the approval to be set
*/
function setApprovalForAll(address to, bool approved) public {
require(to != msg.sender);
_operatorApprovals[msg.sender][to] = approved;
emit ApprovalForAll(msg.sender, to, approved);
}
/**
* @dev Tells whether an operator is approved by a given owner
* @param owner owner address which you want to query the approval of
* @param operator operator address which you want to query the approval of
* @return bool whether the given operator is approved by the given owner
*/
function isApprovedForAll(address owner, address operator) public view returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Transfers the ownership of a given token ID to another address
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function transferFrom(address from, address to, uint256 tokenId) public {
require(_isApprovedOrOwner(msg.sender, tokenId));
_transferFrom(from, to, tokenId);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
*
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the msg sender to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data));
}
/**
* @dev Returns whether the specified token exists
* @param tokenId uint256 ID of the token to query the existence of
* @return whether the token exists
*/
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
return owner != address(0);
}
/**
* @dev Returns whether the given spender can transfer a given token ID
* @param spender address of the spender to query
* @param tokenId uint256 ID of the token to be transferred
* @return bool whether the msg.sender is approved for the given token ID,
* is an operator of the owner, or is the owner of the token
*/
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
/**
* @dev Internal function to mint a new token
* Reverts if the given token ID already exists
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
*/
function _mint(address to, uint256 tokenId) internal {
require(to != address(0));
require(!_exists(tokenId));
_tokenOwner[tokenId] = to;
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
emit Transfer(address(0), to, tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* Deprecated, use _burn(uint256) instead.
* @param owner owner of the token to burn
* @param tokenId uint256 ID of the token being burned
*/
function _burn(address owner, uint256 tokenId) internal {
require(ownerOf(tokenId) == owner);
_clearApproval(tokenId);
_ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1);
_tokenOwner[tokenId] = address(0);
emit Transfer(owner, address(0), tokenId);
}
/**
* @dev Internal function to burn a specific token
* Reverts if the token does not exist
* @param tokenId uint256 ID of the token being burned
*/
function _burn(uint256 tokenId) internal {
_burn(ownerOf(tokenId), tokenId);
}
/**
* @dev Internal function to transfer ownership of a given token ID to another address.
* As opposed to transferFrom, this imposes no restrictions on msg.sender.
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function _transferFrom(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from);
require(to != address(0));
_clearApproval(tokenId);
_ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
_ownedTokensCount[to] = _ownedTokensCount[to].add(1);
_tokenOwner[tokenId] = to;
emit Transfer(from, to, tokenId);
}
/**
* @dev Internal function to invoke `onERC721Received` on a target address
* The call is not executed if the target address is not a contract
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes optional data to send along with the call
* @return whether the call correctly returned the expected magic value
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
internal returns (bool)
{
if (!to.isContract()) {
return true;
}
bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
return (retval == _ERC721_RECEIVED);
}
/**
* @dev Private function to clear current approval of a given token ID
* @param tokenId uint256 ID of the token to be transferred
*/
function _clearApproval(uint256 tokenId) private {
if (_tokenApprovals[tokenId] != address(0)) {
_tokenApprovals[tokenId] = address(0);
}
}
}
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.5.0;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor () internal {
_owner = msg.sender;
emit OwnershipTransferred(address(0), _owner);
}
/**
* @return the address of the owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner());
_;
}
/**
* @return true if `msg.sender` is the owner of the contract.
*/
function isOwner() public view returns (bool) {
return msg.sender == _owner;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0));
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// File: @ensdomains/ethregistrar/contracts/BaseRegistrar.sol
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);
// The ENS registry
ENS public ens;
// The namehash of the TLD this registrar owns (eg, .eth)
bytes32 public baseNode;
// A map of addresses that are authorised to register and renew names.
mapping(address=>bool) public controllers;
// Authorises a controller, who can register and renew domains.
function addController(address controller) external;
// Revoke controller permission for an address.
function removeController(address controller) external;
// Set the resolver for the TLD this registrar manages.
function setResolver(address resolver) external;
// Returns the expiration timestamp of the specified label hash.
function nameExpires(uint256 id) external view returns(uint);
// Returns true iff the specified name is available for registration.
function available(uint256 id) public view returns(bool);
/**
* @dev Register a name.
*/
function register(uint256 id, address owner, uint duration) external returns(uint);
function renew(uint256 id, uint duration) external returns(uint);
/**
* @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
*/
function reclaim(uint256 id, address owner) external;
}
// File: @ensdomains/ethregistrar/contracts/BaseRegistrarImplementation.sol
pragma solidity ^0.5.0;
contract BaseRegistrarImplementation is BaseRegistrar, ERC721 {
// A map of expiry times
mapping(uint256=>uint) expiries;
bytes4 constant private INTERFACE_META_ID = bytes4(keccak256("supportsInterface(bytes4)"));
bytes4 constant private ERC721_ID = bytes4(
keccak256("balanceOf(address)") ^
keccak256("ownerOf(uint256)") ^
keccak256("approve(address,uint256)") ^
keccak256("getApproved(uint256)") ^
keccak256("setApprovalForAll(address,bool)") ^
keccak256("isApprovedForAll(address,address)") ^
keccak256("transferFrom(address,address,uint256)") ^
keccak256("safeTransferFrom(address,address,uint256)") ^
keccak256("safeTransferFrom(address,address,uint256,bytes)")
);
bytes4 constant private RECLAIM_ID = bytes4(keccak256("reclaim(uint256,address)"));
constructor(ENS _ens, bytes32 _baseNode) public {
ens = _ens;
baseNode = _baseNode;
}
modifier live {
require(ens.owner(baseNode) == address(this));
_;
}
modifier onlyController {
require(controllers[msg.sender]);
_;
}
/**
* @dev Gets the owner of the specified token ID. Names become unowned
* when their registration expires.
* @param tokenId uint256 ID of the token to query the owner of
* @return address currently marked as the owner of the given token ID
*/
function ownerOf(uint256 tokenId) public view returns (address) {
require(expiries[tokenId] > now);
return super.ownerOf(tokenId);
}
// Authorises a controller, who can register and renew domains.
function addController(address controller) external onlyOwner {
controllers[controller] = true;
emit ControllerAdded(controller);
}
// Revoke controller permission for an address.
function removeController(address controller) external onlyOwner {
controllers[controller] = false;
emit ControllerRemoved(controller);
}
// Set the resolver for the TLD this registrar manages.
function setResolver(address resolver) external onlyOwner {
ens.setResolver(baseNode, resolver);
}
// Returns the expiration timestamp of the specified id.
function nameExpires(uint256 id) external view returns(uint) {
return expiries[id];
}
// Returns true iff the specified name is available for registration.
function available(uint256 id) public view returns(bool) {
// Not available if it's registered here or in its grace period.
return expiries[id] + GRACE_PERIOD < now;
}
/**
* @dev Register a name.
* @param id The token ID (keccak256 of the label).
* @param owner The address that should own the registration.
* @param duration Duration in seconds for the registration.
*/
function register(uint256 id, address owner, uint duration) external returns(uint) {
return _register(id, owner, duration, true);
}
/**
* @dev Register a name, without modifying the registry.
* @param id The token ID (keccak256 of the label).
* @param owner The address that should own the registration.
* @param duration Duration in seconds for the registration.
*/
function registerOnly(uint256 id, address owner, uint duration) external returns(uint) {
return _register(id, owner, duration, false);
}
function _register(uint256 id, address owner, uint duration, bool updateRegistry) internal live onlyController returns(uint) {
require(available(id));
require(now + duration + GRACE_PERIOD > now + GRACE_PERIOD); // Prevent future overflow
expiries[id] = now + duration;
if(_exists(id)) {
// Name was previously owned, and expired
_burn(id);
}
_mint(owner, id);
if(updateRegistry) {
ens.setSubnodeOwner(baseNode, bytes32(id), owner);
}
emit NameRegistered(id, owner, now + duration);
return now + duration;
}
function renew(uint256 id, uint duration) external live onlyController returns(uint) {
require(expiries[id] + GRACE_PERIOD >= now); // Name must be registered here or in grace period
require(expiries[id] + duration + GRACE_PERIOD > duration + GRACE_PERIOD); // Prevent future overflow
expiries[id] += duration;
emit NameRenewed(id, expiries[id]);
return expiries[id];
}
/**
* @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
*/
function reclaim(uint256 id, address owner) external live {
require(_isApprovedOrOwner(msg.sender, id));
ens.setSubnodeOwner(baseNode, bytes32(id), owner);
}
function supportsInterface(bytes4 interfaceID) external view returns (bool) {
return interfaceID == INTERFACE_META_ID ||
interfaceID == ERC721_ID ||
interfaceID == RECLAIM_ID;
}
}File 3 of 5: ExponentialPremiumPriceOracle
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
pragma solidity >=0.8.4;
import "./SafeMath.sol";
import "./StablePriceOracle.sol";
contract ExponentialPremiumPriceOracle is StablePriceOracle {
uint256 constant GRACE_PERIOD = 90 days;
uint256 immutable startPremium;
uint256 immutable endValue;
constructor(
AggregatorInterface _usdOracle,
uint256[] memory _rentPrices,
uint256 _startPremium,
uint256 totalDays
) StablePriceOracle(_usdOracle, _rentPrices) {
startPremium = _startPremium;
endValue = _startPremium >> totalDays;
}
uint256 constant PRECISION = 1e18;
uint256 constant bit1 = 999989423469314432; // 0.5 ^ 1/65536 * (10 ** 18)
uint256 constant bit2 = 999978847050491904; // 0.5 ^ 2/65536 * (10 ** 18)
uint256 constant bit3 = 999957694548431104;
uint256 constant bit4 = 999915390886613504;
uint256 constant bit5 = 999830788931929088;
uint256 constant bit6 = 999661606496243712;
uint256 constant bit7 = 999323327502650752;
uint256 constant bit8 = 998647112890970240;
uint256 constant bit9 = 997296056085470080;
uint256 constant bit10 = 994599423483633152;
uint256 constant bit11 = 989228013193975424;
uint256 constant bit12 = 978572062087700096;
uint256 constant bit13 = 957603280698573696;
uint256 constant bit14 = 917004043204671232;
uint256 constant bit15 = 840896415253714560;
uint256 constant bit16 = 707106781186547584;
/**
* @dev Returns the pricing premium in internal base units.
*/
function _premium(
string memory,
uint256 expires,
uint256
) internal view override returns (uint256) {
expires = expires + GRACE_PERIOD;
if (expires > block.timestamp) {
return 0;
}
uint256 elapsed = block.timestamp - expires;
uint256 premium = decayedPremium(startPremium, elapsed);
if (premium >= endValue) {
return premium - endValue;
}
return 0;
}
/**
* @dev Returns the premium price at current time elapsed
* @param startPremium starting price
* @param elapsed time past since expiry
*/
function decayedPremium(uint256 startPremium, uint256 elapsed)
public
pure
returns (uint256)
{
uint256 daysPast = (elapsed * PRECISION) / 1 days;
uint256 intDays = daysPast / PRECISION;
uint256 premium = startPremium >> intDays;
uint256 partDay = (daysPast - intDays * PRECISION);
uint256 fraction = (partDay * (2**16)) / PRECISION;
uint256 totalPremium = addFractionalPremium(fraction, premium);
return totalPremium;
}
function addFractionalPremium(uint256 fraction, uint256 premium)
internal
pure
returns (uint256)
{
if (fraction & (1 << 0) != 0) {
premium = (premium * bit1) / PRECISION;
}
if (fraction & (1 << 1) != 0) {
premium = (premium * bit2) / PRECISION;
}
if (fraction & (1 << 2) != 0) {
premium = (premium * bit3) / PRECISION;
}
if (fraction & (1 << 3) != 0) {
premium = (premium * bit4) / PRECISION;
}
if (fraction & (1 << 4) != 0) {
premium = (premium * bit5) / PRECISION;
}
if (fraction & (1 << 5) != 0) {
premium = (premium * bit6) / PRECISION;
}
if (fraction & (1 << 6) != 0) {
premium = (premium * bit7) / PRECISION;
}
if (fraction & (1 << 7) != 0) {
premium = (premium * bit8) / PRECISION;
}
if (fraction & (1 << 8) != 0) {
premium = (premium * bit9) / PRECISION;
}
if (fraction & (1 << 9) != 0) {
premium = (premium * bit10) / PRECISION;
}
if (fraction & (1 << 10) != 0) {
premium = (premium * bit11) / PRECISION;
}
if (fraction & (1 << 11) != 0) {
premium = (premium * bit12) / PRECISION;
}
if (fraction & (1 << 12) != 0) {
premium = (premium * bit13) / PRECISION;
}
if (fraction & (1 << 13) != 0) {
premium = (premium * bit14) / PRECISION;
}
if (fraction & (1 << 14) != 0) {
premium = (premium * bit15) / PRECISION;
}
if (fraction & (1 << 15) != 0) {
premium = (premium * bit16) / PRECISION;
}
return premium;
}
function supportsInterface(bytes4 interfaceID)
public
view
virtual
override
returns (bool)
{
return super.supportsInterface(interfaceID);
}
}
pragma solidity >=0.8.4;
interface PriceOracle {
/**
* @dev Returns the price to register or renew a name.
* @param name The name being registered or renewed.
* @param expires When the name presently expires (0 if this is a new registration).
* @param duration How long the name is being registered or extended for, in seconds.
* @return The price of this renewal or registration, in wei.
*/
function price(string calldata name, uint expires, uint duration) external view returns(uint);
}
pragma solidity >=0.8.4;
/**
* @title SafeMath
* @dev Unsigned math operations with safety checks that revert on error
*/
library SafeMath {
/**
* @dev Multiplies two unsigned integers, reverts on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b);
return c;
}
/**
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a);
uint256 c = a - b;
return c;
}
/**
* @dev Adds two unsigned integers, reverts on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a);
return c;
}
/**
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
pragma solidity >=0.8.4;
import "./PriceOracle.sol";
import "./SafeMath.sol";
import "./StringUtils.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
}
// StablePriceOracle sets a price in USD, based on an oracle.
contract StablePriceOracle is Ownable, PriceOracle {
using SafeMath for *;
using StringUtils for *;
// Rent in base price units by length. Element 0 is for 1-length names, and so on.
uint256[] public rentPrices;
// Oracle address
AggregatorInterface public immutable usdOracle;
event OracleChanged(address oracle);
event RentPriceChanged(uint256[] prices);
bytes4 private constant INTERFACE_META_ID =
bytes4(keccak256("supportsInterface(bytes4)"));
bytes4 private constant ORACLE_ID =
bytes4(
keccak256("price(string,uint256,uint256)") ^
keccak256("premium(string,uint256,uint256)")
);
constructor(AggregatorInterface _usdOracle, uint256[] memory _rentPrices)
public
{
usdOracle = _usdOracle;
setPrices(_rentPrices);
}
function price(
string calldata name,
uint256 expires,
uint256 duration
) external view override returns (uint256) {
uint256 len = name.strlen();
if (len > rentPrices.length) {
len = rentPrices.length;
}
require(len > 0);
uint256 basePrice = rentPrices[len - 1].mul(duration);
basePrice = basePrice.add(_premium(name, expires, duration));
return attoUSDToWei(basePrice);
}
/**
* @dev Sets rent prices.
* @param _rentPrices The price array. Each element corresponds to a specific
* name length; names longer than the length of the array
* default to the price of the last element. Values are
* in base price units, equal to one attodollar (1e-18
* dollar) each.
*/
function setPrices(uint256[] memory _rentPrices) public onlyOwner {
rentPrices = _rentPrices;
emit RentPriceChanged(_rentPrices);
}
/**
* @dev Returns the pricing premium in wei.
*/
function premium(
string calldata name,
uint256 expires,
uint256 duration
) external view returns (uint256) {
uint256 weiPrice = attoUSDToWei(_premium(name, expires, duration));
return weiPrice;
}
/**
* @dev Returns the pricing premium in internal base units.
*/
function _premium(
string memory name,
uint256 expires,
uint256 duration
) internal view virtual returns (uint256) {
return 0;
}
function attoUSDToWei(uint256 amount) internal view returns (uint256) {
uint256 ethPrice = uint256(usdOracle.latestAnswer()); //2
return amount.mul(1e8).div(ethPrice);
}
function weiToAttoUSD(uint256 amount) internal view returns (uint256) {
uint256 ethPrice = uint256(usdOracle.latestAnswer());
return amount.mul(ethPrice).div(1e8);
}
function supportsInterface(bytes4 interfaceID)
public
view
virtual
returns (bool)
{
return interfaceID == INTERFACE_META_ID || interfaceID == ORACLE_ID;
}
}
pragma solidity >=0.8.4;
library StringUtils {
/**
* @dev Returns the length of a given string
*
* @param s The string to measure the length of
* @return The length of the input string
*/
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++) {
bytes1 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;
}
}
File 4 of 5: EACAggregatorProxy
pragma solidity 0.6.6;
/**
* @title The Owned contract
* @notice A contract with helpers for basic contract ownership.
*/
contract Owned {
address payable public owner;
address private pendingOwner;
event OwnershipTransferRequested(
address indexed from,
address indexed to
);
event OwnershipTransferred(
address indexed from,
address indexed to
);
constructor() public {
owner = msg.sender;
}
/**
* @dev Allows an owner to begin transferring ownership to a new address,
* pending.
*/
function transferOwnership(address _to)
external
onlyOwner()
{
pendingOwner = _to;
emit OwnershipTransferRequested(owner, _to);
}
/**
* @dev Allows an ownership transfer to be completed by the recipient.
*/
function acceptOwnership()
external
{
require(msg.sender == pendingOwner, "Must be proposed owner");
address oldOwner = owner;
owner = msg.sender;
pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
/**
* @dev Reverts if called by anyone other than the contract owner.
*/
modifier onlyOwner() {
require(msg.sender == owner, "Only callable by owner");
_;
}
}
interface AggregatorInterface {
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
function latestRound() external view returns (uint256);
function getAnswer(uint256 roundId) external view returns (int256);
function getTimestamp(uint256 roundId) external view returns (uint256);
event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
{
}
/**
* @title A trusted proxy for updating where current answers are read from
* @notice This contract provides a consistent address for the
* CurrentAnwerInterface but delegates where it reads from to the owner, who is
* trusted to update it.
*/
contract AggregatorProxy is AggregatorV2V3Interface, Owned {
struct Phase {
uint16 id;
AggregatorV2V3Interface aggregator;
}
Phase private currentPhase;
AggregatorV2V3Interface public proposedAggregator;
mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
uint256 constant private PHASE_OFFSET = 64;
uint256 constant private PHASE_SIZE = 16;
uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
constructor(address _aggregator) public Owned() {
setAggregator(_aggregator);
}
/**
* @notice Reads the current answer from aggregator delegated to.
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestAnswer()
public
view
virtual
override
returns (int256 answer)
{
return currentPhase.aggregator.latestAnswer();
}
/**
* @notice Reads the last updated height from aggregator delegated to.
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestTimestamp()
public
view
virtual
override
returns (uint256 updatedAt)
{
return currentPhase.aggregator.latestTimestamp();
}
/**
* @notice get past rounds answers
* @param _roundId the answer number to retrieve the answer for
*
* @dev #[deprecated] Use getRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended getRoundData
* instead which includes better verification information.
*/
function getAnswer(uint256 _roundId)
public
view
virtual
override
returns (int256 answer)
{
if (_roundId > MAX_ID) return 0;
(uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
if (address(aggregator) == address(0)) return 0;
return aggregator.getAnswer(aggregatorRoundId);
}
/**
* @notice get block timestamp when an answer was last updated
* @param _roundId the answer number to retrieve the updated timestamp for
*
* @dev #[deprecated] Use getRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended getRoundData
* instead which includes better verification information.
*/
function getTimestamp(uint256 _roundId)
public
view
virtual
override
returns (uint256 updatedAt)
{
if (_roundId > MAX_ID) return 0;
(uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
if (address(aggregator) == address(0)) return 0;
return aggregator.getTimestamp(aggregatorRoundId);
}
/**
* @notice get the latest completed round where the answer was updated. This
* ID includes the proxy's phase, to make sure round IDs increase even when
* switching to a newly deployed aggregator.
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestRound()
public
view
virtual
override
returns (uint256 roundId)
{
Phase memory phase = currentPhase; // cache storage reads
return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
}
/**
* @notice get data about a round. Consumers are encouraged to check
* that they're receiving fresh data by inspecting the updatedAt and
* answeredInRound return values.
* Note that different underlying implementations of AggregatorV3Interface
* have slightly different semantics for some of the return values. Consumers
* should determine what implementations they expect to receive
* data from and validate that they can properly handle return data from all
* of them.
* @param _roundId the requested round ID as presented through the proxy, this
* is made up of the aggregator's round ID with the phase ID encoded in the
* two highest order bytes
* @return roundId is the round ID from the aggregator for which the data was
* retrieved combined with an phase to ensure that round IDs get larger as
* time moves forward.
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @dev Note that answer and updatedAt may change between queries.
*/
function getRoundData(uint80 _roundId)
public
view
virtual
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
(uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
(
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 ansIn
) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
}
/**
* @notice get data about the latest round. Consumers are encouraged to check
* that they're receiving fresh data by inspecting the updatedAt and
* answeredInRound return values.
* Note that different underlying implementations of AggregatorV3Interface
* have slightly different semantics for some of the return values. Consumers
* should determine what implementations they expect to receive
* data from and validate that they can properly handle return data from all
* of them.
* @return roundId is the round ID from the aggregator for which the data was
* retrieved combined with an phase to ensure that round IDs get larger as
* time moves forward.
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @dev Note that answer and updatedAt may change between queries.
*/
function latestRoundData()
public
view
virtual
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
Phase memory current = currentPhase; // cache storage reads
(
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 ansIn
) = current.aggregator.latestRoundData();
return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
}
/**
* @notice Used if an aggregator contract has been proposed.
* @param _roundId the round ID to retrieve the round data for
* @return roundId is the round ID for which data was retrieved
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
*/
function proposedGetRoundData(uint80 _roundId)
public
view
virtual
hasProposal()
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return proposedAggregator.getRoundData(_roundId);
}
/**
* @notice Used if an aggregator contract has been proposed.
* @return roundId is the round ID for which data was retrieved
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
*/
function proposedLatestRoundData()
public
view
virtual
hasProposal()
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return proposedAggregator.latestRoundData();
}
/**
* @notice returns the current phase's aggregator address.
*/
function aggregator()
external
view
returns (address)
{
return address(currentPhase.aggregator);
}
/**
* @notice returns the current phase's ID.
*/
function phaseId()
external
view
returns (uint16)
{
return currentPhase.id;
}
/**
* @notice represents the number of decimals the aggregator responses represent.
*/
function decimals()
external
view
override
returns (uint8)
{
return currentPhase.aggregator.decimals();
}
/**
* @notice the version number representing the type of aggregator the proxy
* points to.
*/
function version()
external
view
override
returns (uint256)
{
return currentPhase.aggregator.version();
}
/**
* @notice returns the description of the aggregator the proxy points to.
*/
function description()
external
view
override
returns (string memory)
{
return currentPhase.aggregator.description();
}
/**
* @notice Allows the owner to propose a new address for the aggregator
* @param _aggregator The new address for the aggregator contract
*/
function proposeAggregator(address _aggregator)
external
onlyOwner()
{
proposedAggregator = AggregatorV2V3Interface(_aggregator);
}
/**
* @notice Allows the owner to confirm and change the address
* to the proposed aggregator
* @dev Reverts if the given address doesn't match what was previously
* proposed
* @param _aggregator The new address for the aggregator contract
*/
function confirmAggregator(address _aggregator)
external
onlyOwner()
{
require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
delete proposedAggregator;
setAggregator(_aggregator);
}
/*
* Internal
*/
function setAggregator(address _aggregator)
internal
{
uint16 id = currentPhase.id + 1;
currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
}
function addPhase(
uint16 _phase,
uint64 _originalId
)
internal
view
returns (uint80)
{
return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
}
function parseIds(
uint256 _roundId
)
internal
view
returns (uint16, uint64)
{
uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
uint64 aggregatorRoundId = uint64(_roundId);
return (phaseId, aggregatorRoundId);
}
function addPhaseIds(
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound,
uint16 phaseId
)
internal
view
returns (uint80, int256, uint256, uint256, uint80)
{
return (
addPhase(phaseId, uint64(roundId)),
answer,
startedAt,
updatedAt,
addPhase(phaseId, uint64(answeredInRound))
);
}
/*
* Modifiers
*/
modifier hasProposal() {
require(address(proposedAggregator) != address(0), "No proposed aggregator present");
_;
}
}
interface AccessControllerInterface {
function hasAccess(address user, bytes calldata data) external view returns (bool);
}
/**
* @title External Access Controlled Aggregator Proxy
* @notice A trusted proxy for updating where current answers are read from
* @notice This contract provides a consistent address for the
* Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
* trusted to update it.
* @notice Only access enabled addresses are allowed to access getters for
* aggregated answers and round information.
*/
contract EACAggregatorProxy is AggregatorProxy {
AccessControllerInterface public accessController;
constructor(
address _aggregator,
address _accessController
)
public
AggregatorProxy(_aggregator)
{
setController(_accessController);
}
/**
* @notice Allows the owner to update the accessController contract address.
* @param _accessController The new address for the accessController contract
*/
function setController(address _accessController)
public
onlyOwner()
{
accessController = AccessControllerInterface(_accessController);
}
/**
* @notice Reads the current answer from aggregator delegated to.
* @dev overridden function to add the checkAccess() modifier
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestAnswer()
public
view
override
checkAccess()
returns (int256)
{
return super.latestAnswer();
}
/**
* @notice get the latest completed round where the answer was updated. This
* ID includes the proxy's phase, to make sure round IDs increase even when
* switching to a newly deployed aggregator.
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestTimestamp()
public
view
override
checkAccess()
returns (uint256)
{
return super.latestTimestamp();
}
/**
* @notice get past rounds answers
* @param _roundId the answer number to retrieve the answer for
* @dev overridden function to add the checkAccess() modifier
*
* @dev #[deprecated] Use getRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended getRoundData
* instead which includes better verification information.
*/
function getAnswer(uint256 _roundId)
public
view
override
checkAccess()
returns (int256)
{
return super.getAnswer(_roundId);
}
/**
* @notice get block timestamp when an answer was last updated
* @param _roundId the answer number to retrieve the updated timestamp for
* @dev overridden function to add the checkAccess() modifier
*
* @dev #[deprecated] Use getRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended getRoundData
* instead which includes better verification information.
*/
function getTimestamp(uint256 _roundId)
public
view
override
checkAccess()
returns (uint256)
{
return super.getTimestamp(_roundId);
}
/**
* @notice get the latest completed round where the answer was updated
* @dev overridden function to add the checkAccess() modifier
*
* @dev #[deprecated] Use latestRoundData instead. This does not error if no
* answer has been reached, it will simply return 0. Either wait to point to
* an already answered Aggregator or use the recommended latestRoundData
* instead which includes better verification information.
*/
function latestRound()
public
view
override
checkAccess()
returns (uint256)
{
return super.latestRound();
}
/**
* @notice get data about a round. Consumers are encouraged to check
* that they're receiving fresh data by inspecting the updatedAt and
* answeredInRound return values.
* Note that different underlying implementations of AggregatorV3Interface
* have slightly different semantics for some of the return values. Consumers
* should determine what implementations they expect to receive
* data from and validate that they can properly handle return data from all
* of them.
* @param _roundId the round ID to retrieve the round data for
* @return roundId is the round ID from the aggregator for which the data was
* retrieved combined with a phase to ensure that round IDs get larger as
* time moves forward.
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @dev Note that answer and updatedAt may change between queries.
*/
function getRoundData(uint80 _roundId)
public
view
checkAccess()
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return super.getRoundData(_roundId);
}
/**
* @notice get data about the latest round. Consumers are encouraged to check
* that they're receiving fresh data by inspecting the updatedAt and
* answeredInRound return values.
* Note that different underlying implementations of AggregatorV3Interface
* have slightly different semantics for some of the return values. Consumers
* should determine what implementations they expect to receive
* data from and validate that they can properly handle return data from all
* of them.
* @return roundId is the round ID from the aggregator for which the data was
* retrieved combined with a phase to ensure that round IDs get larger as
* time moves forward.
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @dev Note that answer and updatedAt may change between queries.
*/
function latestRoundData()
public
view
checkAccess()
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return super.latestRoundData();
}
/**
* @notice Used if an aggregator contract has been proposed.
* @param _roundId the round ID to retrieve the round data for
* @return roundId is the round ID for which data was retrieved
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
*/
function proposedGetRoundData(uint80 _roundId)
public
view
checkAccess()
hasProposal()
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return super.proposedGetRoundData(_roundId);
}
/**
* @notice Used if an aggregator contract has been proposed.
* @return roundId is the round ID for which data was retrieved
* @return answer is the answer for the given round
* @return startedAt is the timestamp when the round was started.
* (Only some AggregatorV3Interface implementations return meaningful values)
* @return updatedAt is the timestamp when the round last was updated (i.e.
* answer was last computed)
* @return answeredInRound is the round ID of the round in which the answer
* was computed.
*/
function proposedLatestRoundData()
public
view
checkAccess()
hasProposal()
override
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
)
{
return super.proposedLatestRoundData();
}
/**
* @dev reverts if the caller does not have access by the accessController
* contract or is the contract itself.
*/
modifier checkAccess() {
AccessControllerInterface ac = accessController;
require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
_;
}
}File 5 of 5: ENSRegistryWithFallback
// File: @ensdomains/ens/contracts/ENS.sol
pragma solidity >=0.4.24;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when an operator is added or removed.
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);
}
// File: @ensdomains/ens/contracts/ENSRegistry.sol
pragma solidity ^0.5.0;
/**
* The ENS registry contract.
*/
contract ENSRegistry is ENS {
struct Record {
address owner;
address resolver;
uint64 ttl;
}
mapping (bytes32 => Record) records;
mapping (address => mapping(address => bool)) operators;
// Permits modifications only by the owner of the specified node.
modifier authorised(bytes32 node) {
address owner = records[node].owner;
require(owner == msg.sender || operators[owner][msg.sender]);
_;
}
/**
* @dev Constructs a new ENS registrar.
*/
constructor() public {
records[0x0].owner = msg.sender;
}
/**
* @dev Sets the record for a node.
* @param node The node to update.
* @param owner The address of the new owner.
* @param resolver The address of the resolver.
* @param ttl The TTL in seconds.
*/
function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external {
setOwner(node, owner);
_setResolverAndTTL(node, resolver, ttl);
}
/**
* @dev Sets the record for a subnode.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
* @param resolver The address of the resolver.
* @param ttl The TTL in seconds.
*/
function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external {
bytes32 subnode = setSubnodeOwner(node, label, owner);
_setResolverAndTTL(subnode, resolver, ttl);
}
/**
* @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
* @param node The node to transfer ownership of.
* @param owner The address of the new owner.
*/
function setOwner(bytes32 node, address owner) public authorised(node) {
_setOwner(node, owner);
emit Transfer(node, owner);
}
/**
* @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
*/
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public authorised(node) returns(bytes32) {
bytes32 subnode = keccak256(abi.encodePacked(node, label));
_setOwner(subnode, owner);
emit NewOwner(node, label, owner);
return subnode;
}
/**
* @dev Sets the resolver address for the specified node.
* @param node The node to update.
* @param resolver The address of the resolver.
*/
function setResolver(bytes32 node, address resolver) public authorised(node) {
emit NewResolver(node, resolver);
records[node].resolver = resolver;
}
/**
* @dev Sets the TTL for the specified node.
* @param node The node to update.
* @param ttl The TTL in seconds.
*/
function setTTL(bytes32 node, uint64 ttl) public authorised(node) {
emit NewTTL(node, ttl);
records[node].ttl = ttl;
}
/**
* @dev Enable or disable approval for a third party ("operator") to manage
* all of `msg.sender`'s ENS records. Emits the ApprovalForAll event.
* @param operator Address to add to the set of authorized operators.
* @param approved True if the operator is approved, false to revoke approval.
*/
function setApprovalForAll(address operator, bool approved) external {
operators[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
*/
function owner(bytes32 node) public view returns (address) {
address addr = records[node].owner;
if (addr == address(this)) {
return address(0x0);
}
return addr;
}
/**
* @dev Returns the address of the resolver for the specified node.
* @param node The specified node.
* @return address of the resolver.
*/
function resolver(bytes32 node) public view returns (address) {
return records[node].resolver;
}
/**
* @dev Returns the TTL of a node, and any records associated with it.
* @param node The specified node.
* @return ttl of the node.
*/
function ttl(bytes32 node) public view returns (uint64) {
return records[node].ttl;
}
/**
* @dev Returns whether a record has been imported to the registry.
* @param node The specified node.
* @return Bool if record exists
*/
function recordExists(bytes32 node) public view returns (bool) {
return records[node].owner != address(0x0);
}
/**
* @dev Query if an address is an authorized operator for another address.
* @param owner The address that owns the records.
* @param operator The address that acts on behalf of the owner.
* @return True if `operator` is an approved operator for `owner`, false otherwise.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool) {
return operators[owner][operator];
}
function _setOwner(bytes32 node, address owner) internal {
records[node].owner = owner;
}
function _setResolverAndTTL(bytes32 node, address resolver, uint64 ttl) internal {
if(resolver != records[node].resolver) {
records[node].resolver = resolver;
emit NewResolver(node, resolver);
}
if(ttl != records[node].ttl) {
records[node].ttl = ttl;
emit NewTTL(node, ttl);
}
}
}
// File: @ensdomains/ens/contracts/ENSRegistryWithFallback.sol
pragma solidity ^0.5.0;
/**
* The ENS registry contract.
*/
contract ENSRegistryWithFallback is ENSRegistry {
ENS public old;
/**
* @dev Constructs a new ENS registrar.
*/
constructor(ENS _old) public ENSRegistry() {
old = _old;
}
/**
* @dev Returns the address of the resolver for the specified node.
* @param node The specified node.
* @return address of the resolver.
*/
function resolver(bytes32 node) public view returns (address) {
if (!recordExists(node)) {
return old.resolver(node);
}
return super.resolver(node);
}
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
*/
function owner(bytes32 node) public view returns (address) {
if (!recordExists(node)) {
return old.owner(node);
}
return super.owner(node);
}
/**
* @dev Returns the TTL of a node, and any records associated with it.
* @param node The specified node.
* @return ttl of the node.
*/
function ttl(bytes32 node) public view returns (uint64) {
if (!recordExists(node)) {
return old.ttl(node);
}
return super.ttl(node);
}
function _setOwner(bytes32 node, address owner) internal {
address addr = owner;
if (addr == address(0x0)) {
addr = address(this);
}
super._setOwner(node, addr);
}
}