// 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);
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
function setResolver(bytes32 node, address resolver) external;
function setOwner(bytes32 node, address owner) external;
function setTTL(bytes32 node, uint64 ttl) 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);
}
// File: contracts/ResolverBase.sol
pragma solidity ^0.5.0;
contract ResolverBase {
bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == INTERFACE_META_ID;
}
function isAuthorised(bytes32 node) internal view returns(bool);
modifier authorised(bytes32 node) {
require(isAuthorised(node));
_;
}
function bytesToAddress(bytes memory b) internal pure returns(address a) {
require(b.length == 20);
assembly {
a := div(mload(add(b, 32)), exp(256, 12))
}
}
function addressToBytes(address a) internal pure returns(bytes memory b) {
b = new bytes(20);
assembly {
mstore(add(b, 32), mul(a, exp(256, 12)))
}
}
}
// File: contracts/profiles/ABIResolver.sol
pragma solidity ^0.5.0;
contract ABIResolver is ResolverBase {
bytes4 constant private ABI_INTERFACE_ID = 0x2203ab56;
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
mapping(bytes32=>mapping(uint256=>bytes)) abis;
/**
* Sets the ABI associated with an ENS node.
* Nodes may have one ABI of each content type. To remove an ABI, set it to
* the empty string.
* @param node The node to update.
* @param contentType The content type of the ABI
* @param data The ABI data.
*/
function setABI(bytes32 node, uint256 contentType, bytes calldata data) external authorised(node) {
// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);
abis[node][contentType] = data;
emit ABIChanged(node, contentType);
}
/**
* Returns the ABI associated with an ENS node.
* Defined in EIP205.
* @param node The ENS node to query
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
* @return contentType The content type of the return value
* @return data The ABI data
*/
function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory) {
mapping(uint256=>bytes) storage abiset = abis[node];
for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {
return (contentType, abiset[contentType]);
}
}
return (0, bytes(""));
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == ABI_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/AddrResolver.sol
pragma solidity ^0.5.8;
contract AddrResolver is ResolverBase {
bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant private ADDRESS_INTERFACE_ID = 0xf1cb7e06;
uint constant private COIN_TYPE_ETH = 60;
event AddrChanged(bytes32 indexed node, address a);
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
mapping(bytes32=>mapping(uint=>bytes)) _addresses;
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param a The address to set.
*/
function setAddr(bytes32 node, address a) external authorised(node) {
setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) public view returns (address) {
bytes memory a = addr(node, COIN_TYPE_ETH);
if(a.length == 0) {
return address(0);
}
return bytesToAddress(a);
}
function setAddr(bytes32 node, uint coinType, bytes memory a) public authorised(node) {
emit AddressChanged(node, coinType, a);
if(coinType == COIN_TYPE_ETH) {
emit AddrChanged(node, bytesToAddress(a));
}
_addresses[node][coinType] = a;
}
function addr(bytes32 node, uint coinType) public view returns(bytes memory) {
return _addresses[node][coinType];
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == ADDR_INTERFACE_ID || interfaceID == ADDRESS_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/ContentHashResolver.sol
pragma solidity ^0.5.0;
contract ContentHashResolver is ResolverBase {
bytes4 constant private CONTENT_HASH_INTERFACE_ID = 0xbc1c58d1;
event ContenthashChanged(bytes32 indexed node, bytes hash);
mapping(bytes32=>bytes) hashes;
/**
* Sets the contenthash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The contenthash to set
*/
function setContenthash(bytes32 node, bytes calldata hash) external authorised(node) {
hashes[node] = hash;
emit ContenthashChanged(node, hash);
}
/**
* Returns the contenthash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function contenthash(bytes32 node) external view returns (bytes memory) {
return hashes[node];
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == CONTENT_HASH_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/InterfaceResolver.sol
pragma solidity ^0.5.0;
contract InterfaceResolver is ResolverBase, AddrResolver {
bytes4 constant private INTERFACE_INTERFACE_ID = bytes4(keccak256("interfaceImplementer(bytes32,bytes4)"));
bytes4 private constant INTERFACE_META_ID = 0x01ffc9a7;
event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);
mapping(bytes32=>mapping(bytes4=>address)) interfaces;
/**
* Sets an interface associated with a name.
* Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
* @param node The node to update.
* @param interfaceID The EIP 168 interface ID.
* @param implementer The address of a contract that implements this interface for this node.
*/
function setInterface(bytes32 node, bytes4 interfaceID, address implementer) external authorised(node) {
interfaces[node][interfaceID] = implementer;
emit InterfaceChanged(node, interfaceID, implementer);
}
/**
* Returns the address of a contract that implements the specified interface for this name.
* If an implementer has not been set for this interfaceID and name, the resolver will query
* the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
* contract implements EIP168 and returns `true` for the specified interfaceID, its address
* will be returned.
* @param node The ENS node to query.
* @param interfaceID The EIP 168 interface ID to check for.
* @return The address that implements this interface, or 0 if the interface is unsupported.
*/
function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address) {
address implementer = interfaces[node][interfaceID];
if(implementer != address(0)) {
return implementer;
}
address a = addr(node);
if(a == address(0)) {
return address(0);
}
(bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", INTERFACE_META_ID));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// EIP 168 not supported by target
return address(0);
}
(success, returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// Specified interface not supported by target
return address(0);
}
return a;
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == INTERFACE_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/NameResolver.sol
pragma solidity ^0.5.0;
contract NameResolver is ResolverBase {
bytes4 constant private NAME_INTERFACE_ID = 0x691f3431;
event NameChanged(bytes32 indexed node, string name);
mapping(bytes32=>string) names;
/**
* Sets the name associated with an ENS node, for reverse records.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param name The name to set.
*/
function setName(bytes32 node, string calldata name) external authorised(node) {
names[node] = name;
emit NameChanged(node, name);
}
/**
* Returns the name associated with an ENS node, for reverse records.
* Defined in EIP181.
* @param node The ENS node to query.
* @return The associated name.
*/
function name(bytes32 node) external view returns (string memory) {
return names[node];
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == NAME_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/PubkeyResolver.sol
pragma solidity ^0.5.0;
contract PubkeyResolver is ResolverBase {
bytes4 constant private PUBKEY_INTERFACE_ID = 0xc8690233;
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
struct PublicKey {
bytes32 x;
bytes32 y;
}
mapping(bytes32=>PublicKey) pubkeys;
/**
* Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query
* @param x the X coordinate of the curve point for the public key.
* @param y the Y coordinate of the curve point for the public key.
*/
function setPubkey(bytes32 node, bytes32 x, bytes32 y) external authorised(node) {
pubkeys[node] = PublicKey(x, y);
emit PubkeyChanged(node, x, y);
}
/**
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @param node The ENS node to query
* @return x, y the X and Y coordinates of the curve point for the public key.
*/
function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y) {
return (pubkeys[node].x, pubkeys[node].y);
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == PUBKEY_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/profiles/TextResolver.sol
pragma solidity ^0.5.0;
contract TextResolver is ResolverBase {
bytes4 constant private TEXT_INTERFACE_ID = 0x59d1d43c;
event TextChanged(bytes32 indexed node, string indexedKey, string key);
mapping(bytes32=>mapping(string=>string)) texts;
/**
* Sets the text data associated with an ENS node and key.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param key The key to set.
* @param value The text data value to set.
*/
function setText(bytes32 node, string calldata key, string calldata value) external authorised(node) {
texts[node][key] = value;
emit TextChanged(node, key, key);
}
/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(bytes32 node, string calldata key) external view returns (string memory) {
return texts[node][key];
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == TEXT_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
// File: contracts/PublicResolver.sol
pragma solidity ^0.5.0;
/**
* A simple resolver anyone can use; only allows the owner of a node to set its
* address.
*/
contract PublicResolver is ABIResolver, AddrResolver, ContentHashResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {
ENS ens;
/**
* A mapping of authorisations. An address that is authorised for a name
* may make any changes to the name that the owner could, but may not update
* the set of authorisations.
* (node, owner, caller) => isAuthorised
*/
mapping(bytes32=>mapping(address=>mapping(address=>bool))) public authorisations;
event AuthorisationChanged(bytes32 indexed node, address indexed owner, address indexed target, bool isAuthorised);
constructor(ENS _ens) public {
ens = _ens;
}
/**
* @dev Sets or clears an authorisation.
* Authorisations are specific to the caller. Any account can set an authorisation
* for any name, but the authorisation that is checked will be that of the
* current owner of a name. Thus, transferring a name effectively clears any
* existing authorisations, and new authorisations can be set in advance of
* an ownership transfer if desired.
*
* @param node The name to change the authorisation on.
* @param target The address that is to be authorised or deauthorised.
* @param isAuthorised True if the address should be authorised, or false if it should be deauthorised.
*/
function setAuthorisation(bytes32 node, address target, bool isAuthorised) external {
authorisations[node][msg.sender][target] = isAuthorised;
emit AuthorisationChanged(node, msg.sender, target, isAuthorised);
}
function isAuthorised(bytes32 node) internal view returns(bool) {
address owner = ens.owner(node);
return owner == msg.sender || authorisations[node][owner][msg.sender];
}
}
{
"compilationTarget": {
"PublicResolver.sol": "PublicResolver"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"}]