Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ThreeDNSRegControl
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {IThreeDNSAuthority} from "src/utils/access/interfaces/IThreeDNSAuthority.sol";
import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {CommitmentOrderflow} from "src/regcontrol/modules/CommitmentOrderflow.sol";
import {DomainController} from "src/regcontrol/modules/DomainController.sol";
import {PaymentProcessor} from "src/regcontrol/modules/PaymentProcessor.sol";
import {RegistrarController} from "src/regcontrol/modules/RegistrarController.sol";
import {Multicall} from "src/regcontrol/modules/Multicall.sol";
import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";
import {ReentrancyGuardStorage} from "src/utils/access/storage/ReentrancyGuardStorage.sol";
/// Diamond Params --------------------------------------------------------------------------------
import {IDiamondCut} from "src/regcontrol/interfaces/diamond/IDiamondCut.sol";
import {LibDiamond} from "src/regcontrol/libraries/LibDiamond.sol";
/// Errors ----------------------------------------------------------------------------------------
error ThreeDNSRegControl_accessDenied();
contract ThreeDNSRegControl is
Initializable,
ThreeDNSAccessControlled
// CommitmentOrderflow -> Moved into diamond facets
// CommitmentOrderflowExtensions -> Moved into diamond facets
// DomainController -> Moved into diamond facets
// RegistrarController, -> Moved into diamond facets
// Multicall -> Moved into diamond facets
{
/// Initialization Functions ------------------------------------------------------------------
/// @dev Disable initializers for template contracts, as they are not meant to be initialized.
constructor() {
_disableInitializers();
}
function initialize(
IThreeDNSAuthority _authority,
address resolver_,
string memory domainName_,
string memory domainVersion_,
uint64 chainId_,
IERC20 usdc_
) public initializer {
ThreeDNSAccessControlled.__ThreeDNSAccessControlled_init(_authority);
// Moved into diamond facets
// CommitmentOrderflow.__CommitmentOrderflow_init(domainName_, domainVersion_, chainId_, usdc_);
ReentrancyGuardStorage.initialize();
RegControlStorage.setPrimaryResolver(resolver_);
}
/// @note Have done 5 initializations
// next -> function initializeV6(...) public reinitializer(5) { }
/// Diamond Fallback Functions ----------------------------------------------------------------
// Find facet for function that is called and execute the
// function if a facet is found and return any value.
fallback() external payable {
LibDiamond.DiamondStorage storage ds;
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
assembly {
ds.slot := position
}
address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
require(facet != address(0), "Diamond: Function does not exist");
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
receive() external payable {
// require(msg.sender == address(WETH));
}
/// Diamond Management Functions --------------------------------------------------------------
function diamondCut(IDiamondCut.FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata) external {
_callerIsProxyAdmin__validate();
LibDiamond.diamondCut(_diamondCut, _init, _calldata);
}
function trackInterface(bytes4 interfaceId_, bool enabled_) external {
// Run access control validation
_callerIsProxyAdmin__validate();
// Track interface
LibDiamond.diamondStorage().supportedInterfaces[interfaceId_] = enabled_;
}
/// ERC165 Functions --------------------------------------------------------------------------
/// @dev ERC165 introspection support.
function supportsInterface(bytes4 interfaceId_) public view returns (bool) {
return LibDiamond.diamondStorage().supportedInterfaces[interfaceId_];
}
/// Access Control Functions ------------------------------------------------------------------
function _callerIsProxyAdmin__validate() internal view {
if (!authority().isRole(authority().ROLE__PROXY_ADMIN(), msg.sender)) {
revert ThreeDNSRegControl_accessDenied();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IThreeDNSAuthority {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/// @notice Event raised when a new gateway URL is set.
event OperatorChanged(address previousOperator, address newOperator);
event RoleAdded(bytes32 indexed role, address indexed manager);
event RoleRemoved(bytes32 indexed role, address indexed manager);
/*//////////////////////////////////////////////////////////////
External Administration Functions
//////////////////////////////////////////////////////////////*/
function setRole(bytes32 _role, address _sender) external;
function removeRole(bytes32 _role, address _sender) external;
function isRole(bytes32 _role, address _sender) external view returns (bool);
/*//////////////////////////////////////////////////////////////
External View Functions
//////////////////////////////////////////////////////////////*/
function operator() external view returns (address);
/*//////////////////////////////////////////////////////////////
External View Functions
//////////////////////////////////////////////////////////////*/
/// @dev Super Admin
function ROLE__OPERATOR() external view returns (bytes32);
/// @dev Management Admin
function ROLE__MANAGER_ADMIN() external view returns (bytes32);
/// @dev Management roles
function ROLE__DEPLOYMENT_MANAGER() external view returns (bytes32);
function ROLE__SIGNER_MANAGER() external view returns (bytes32);
function ROLE__ISSUER_MANAGER() external view returns (bytes32);
/// @dev Auditor roles
function ROLE__AUDITOR() external view returns (bytes32);
/// @dev Constant specifing action specific roles
function ROLE__DEPLOYER() external view returns (bytes32);
function ROLE__PROXY_ADMIN() external view returns (bytes32);
function ROLE__REGISTRAR_ADMIN() external view returns (bytes32);
function ROLE__SIGNER() external view returns (bytes32);
function ROLE__ISSUER() external view returns (bytes32);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
// import {IThreeDNSAccessControlled} from "./interfaces/IThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "./interfaces/IThreeDNSAuthority.sol";
import {IThreeDNSAccessControlled} from "./interfaces/IThreeDNSAccessControlled.sol";
import {
AccessControlledStorage as Storage
} from "./storage/AccessControlledStorage.sol";
/// Errors ---------------------------------------------------------------------------
error ThreeDNSAccessControlled_unauthorized(address);
error ThreeDNSAccessControlled_invalidAuthority();
contract ThreeDNSAccessControlled is
Initializable,
IThreeDNSAccessControlled
{
/// Modifiers ------------------------------------------------------------------------------
modifier onlyOperator() {
_callerIsOperator__validate();
_;
}
/// @dev Included in AccessControlEnumerable
// modifier onlyRole(bytes32 _role)
/// Initializer ----------------------------------------------------------------------------
function __ThreeDNSAccessControlled_init(IThreeDNSAuthority _newAuthority) internal onlyInitializing {
// Set the authority
_changeAuthority(_newAuthority);
}
/// Accessor Function -------------------------------------------------------------------------
function authority()
public view
override
returns (IThreeDNSAuthority)
{
return Storage.authority();
}
/// External Admin Functions ==================================================================
function changeAuthority(IThreeDNSAuthority _newAuthority) external override onlyOperator {
_changeAuthority(_newAuthority);
}
/// Internal Admin Functions ==================================================================
function _setInitialAuthority(IThreeDNSAuthority _newAuthority) internal {
if (address(Storage.authority()) != address(0))
revert ThreeDNSAccessControlled_invalidAuthority();
_changeAuthority(_newAuthority);
}
/// Private Admin Functions -------------------------------------------------------------------
function _changeAuthority(IThreeDNSAuthority _newAuthority) private {
if (address(_newAuthority) == address(0))
revert ThreeDNSAccessControlled_invalidAuthority();
// Get the current authority contract
IThreeDNSAuthority _oldAuthority = Storage.authority();
// Set the new authority contract
Storage.changeAuthority(_newAuthority);
// Log the mutation
emit AuthorityChanged(_oldAuthority, _newAuthority);
}
/// Access Control Functions ==================================================================
function _callerIsOperator__validate() internal view {
if (!_isOperator())
revert ThreeDNSAccessControlled_unauthorized(msg.sender);
}
/// Administrative Action Validators ==========================================================
function _isOperator() internal view returns (bool) {
return Storage.authority().operator() == msg.sender;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {ICommitmentOrderflow} from "src/regcontrol/interfaces/ICommitmentOrderflow.sol";
import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {PaymentProcessor} from "src/regcontrol/modules/PaymentProcessor.sol";
import {RegistrationAuthorizor} from "src/regcontrol/modules/types/RegistrationAuthorizor.sol";
import {ReentrancyGuardDiamond} from "src/utils/access/ReentrancyGuardDiamond.sol";
import {SponsorShieldDiamond} from "src/utils/access/SponsorShieldDiamond.sol";
import {Registry} from "src/regcontrol/modules/types/Registry.sol";
import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {CommitmentStorage as Storage} from "src/regcontrol/storage/Storage.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {IWETH} from "src/utils/interfaces/IWETH.sol";
/// Errors -------------------------------------------------------------------------------------
error CommitmentOrderflow_invalidCommitter();
error CommitmentOrderflow_accessDenied();
error CommitmentOrderflow_transferDoesNotExist();
error CommitmentOrderflow_notCalledThroughMulticall();
error CommitmentOrderflow_invalidCommitmentType(Datastructures.CommitmentType commitmentType_);
error CommitmentOrderflow_invalidDuration(uint64 duration_);
error CommitmentOrderflow_invalidPaymentType(Datastructures.PaymentType paymentType_);
error CommitmentOrderflow_invalidNonce();
error CommitmentOrderflow_commitmentTypeNonRefundable(Datastructures.CommitmentType commitmentType_);
error CommitmentOrderflow_commitmentDoesNotExist(bytes32 commitmentHash_);
error CommitmentOrderflow_commitmentAlreadyExists(bytes32 commitmentHash_);
error CommitmentOrderflow_commitmentNotRefundable(bytes32 commitmentHash_);
error CommitmentOrderflow_commitmentNotRevokable(bytes32 commitmentHash_, uint64 revokableAt_);
/// Contract -----------------------------------------------------------------------------------
contract CommitmentOrderflow is
Initializable,
ICommitmentOrderflow,
RegistrationAuthorizor,
PaymentProcessor,
Registry,
// Access Control
ThreeDNSAccessControlled,
ReentrancyGuardDiamond,
SponsorShieldDiamond
{
/// Constants ------------------------------------------------------------------------------
address private constant WETH = 0x4200000000000000000000000000000000000006;
/// Initialization Functions ==================================================================
function __CommitmentOrderflow_init(string memory domainName_, string memory domainVersion_, uint64 chainId_, IERC20 usdc_)
internal
onlyInitializing
{
// Initialize the RegistrationAuthorizor contract
RegistrationAuthorizor.__RegistrationAuthorizor_init(domainName_, domainVersion_, chainId_);
PaymentProcessor.__PaymentProcessor_init(usdc_);
ReentrancyGuardDiamond.__ReentrancyGuard_init();
SponsorShieldDiamond.__SponsorShield_init();
Storage.initialize();
}
/// Purchase Orderflows -----------------------------------------------------------------------
function validateCommitmentV2(
bytes calldata fqdn_,
address registrant_,
bytes32 nonce_,
Datastructures.RegistrationRequest memory req_
) public view returns (bytes32 secretHash_) {
// Validate the commitment
secretHash_ = _commitment__validate(fqdn_, registrant_, nonce_, req_);
// Prepare the commitment
_twoPhase__validateMake(_twoPhase__prepare(req_, secretHash_));
// Return the secret hash
return secretHash_;
}
function makeCommitmentV2(
bytes32 secretHash_,
Datastructures.RegistrationRequest memory req_,
Datastructures.AuthorizationSignature memory sig_,
address committer_
) public payable {
// If sender is not the committer, verify this is being called in a permit flow
if (msg.sender != committer_) {
// Track and validate the sponsored action
_trackSponsoredPayment(
committer_,
uint256(req_.registrationPayment.paymentType),
req_.registrationPayment.amount + req_.servicePayment.amount
);
}
// Verify this is only being called in a nonReentrant context
if (!_reentrancyGuardEntered())
revert CommitmentOrderflow_notCalledThroughMulticall();
// Prepare the commitment
bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);
// Validate commitment type is not offchain
if (_isOffchainCommitment(req_.commitmentType)) {
revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
}
// Validate the commitment
_twoPhase__validateMake(commitmentHash_);
// Verify the commitment
_commitment__verify(commitmentHash_, sig_);
// Handle the payment
_handlePayment(req_.registrationPayment, true, committer_);
if (req_.servicePayment.amount > 0) _handlePayment(req_.servicePayment, true, committer_);
// Handle and store the commitment
uint64 revocableAt_ = _commitment__store(commitmentHash_, req_.commitmentType, committer_);
// Emit the event
emit PendingCommitment(
commitmentHash_,
revocableAt_,
msg.sender,
req_.registrationPayment,
req_.servicePayment,
sig_.v,
sig_.r,
sig_.s
);
}
function processCommitmentV2(
bytes calldata fqdn_,
address registrant_,
bytes32 nonce_,
Datastructures.RegistrationRequest calldata req_,
uint64 customDuration_
) public {
// Run access control check
_callerIsIssuer__validate();
// Validate, prepare, and process the commitment
bytes32 commitmentHash_ = _commitment__process(_twoPhase__prepare(req_, _commitment__validate(fqdn_, registrant_, nonce_, req_)));
if (customDuration_ > req_.duration) {
revert CommitmentOrderflow_invalidDuration(customDuration_);
}
bytes32 tld_;
if(_isRegistrationCommitment(req_.commitmentType, false)) {
// Register the domain
(, tld_) = _createRegistration(
fqdn_, registrant_,
_setTraderTokenizationTier(0, _isTraderTokenization(req_.commitmentType)),
customDuration_
);
} else if (_isRenewalCommitment(req_.commitmentType, false)) {
// Parse the label from the fqdn
(, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Parse the tld from the fqdn
tld_ = BytesUtils.namehash(fqdn_, offset_);
// Extend the registration
_extendRegistration(labelHash_, tld_, customDuration_);
} else if (_isTransferCommitment(req_.commitmentType)) {
// Parse the label from the fqdn
(, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Parse the tld from the fqdn
tld_ = BytesUtils.namehash(fqdn_, offset_);
// Calculate the node
bytes32 node_ = _calculateNode(labelHash_, tld_);
// Track the transfer so it can be completed / claimed later
Storage.setDomainTransferFlag(registrant_, node_, customDuration_, _isTraderTokenization(req_.commitmentType));
} else {
revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
}
// Move the payment
_handlePayout(req_.registrationPayment, _getPayoutAddress(tld_));
if (req_.servicePayment.amount > 0) _handlePayout(req_.servicePayment, _getPayoutAddress(0x0));
// Emit the event
emit ProcessCommitment(commitmentHash_, msg.sender);
}
function refundCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external {
// Run access control check
_callerIsIssuer__validate();
// Prepare the commitment
bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);
// Verify the action
_twoPhase__validateRefund(commitmentHash_);
// Proccess the refund
address committer_ = _commitment__refund(commitmentHash_, req_);
// Emit the event
emit RefundCommitment(
commitmentHash_, msg.sender, committer_, req_.commitmentType, req_.registrationPayment, req_.servicePayment
);
}
function revokeCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external {
// Prepare the commitment
bytes32 commitmentHash_ = _twoPhase__prepare(req_, secretHash_);
// Verify the action
_twoPhase__validateRevoke(commitmentHash_);
// Proccess the refund
address committer_ = _commitment__refund(commitmentHash_, req_);
// Emit the event
emit RevokeCommitment(
commitmentHash_, committer_, req_.commitmentType, req_.registrationPayment, req_.servicePayment
);
}
function processOffchainCommitment(
bytes calldata fqdn_,
address registrant_,
uint64 duration_,
Datastructures.CommitmentType commitmentType_,
Datastructures.AuthorizationSignature memory sig_
) external {
// Calculate the node
bytes32 node_ = _calculateNode(fqdn_);
// Validate the request
_offchainCommitment__validate(node_, registrant_, duration_, commitmentType_, sig_);
if (_isRegistrationCommitment(commitmentType_, true)) {
// Create the registration
_createRegistration(
fqdn_, registrant_,
_setTraderTokenizationTier(0, _isTraderTokenization(commitmentType_)),
duration_
);
// Lock the domain
_lockRegistration(node_, 30 * 24 * 60 * 60);
// Emit the event
emit IssuedDomainName(node_, msg.sender);
} else if (_isRenewalCommitment(commitmentType_, true)) {
// Parse the label from the fqdn
(, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Parse the tld from the fqdn
bytes32 tld_ = BytesUtils.namehash(fqdn_, offset_);
// Extend the registration
_extendRegistration(labelHash_, tld_, duration_);
// If the renewal is a trader tokenization, downgrade the registration to the trader tier
if (_isTraderTokenization(commitmentType_)) {
// TODO: Implement downgrade
// _downgradeTraderTokenizationTier(labelHash_, tld_);
revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
}
} else {
revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
}
}
function issueTransferredDomainName(
bytes calldata fqdn_,
address registrant_
) external {
bytes32 node_ = _calculateNode(fqdn_);
// Validate the request
_transferCommitment__validate(node_, registrant_);
(uint64 duration_, bool isTrader_) = Storage.getDomainTransferFlag(registrant_, node_);
// Create the registration
_createRegistration(
fqdn_, registrant_,
_setTraderTokenizationTier(0, isTrader_),
duration_
);
// Remove the transfer flag
Storage.deleteDomainTransferFlag(registrant_, node_);
}
/// Access Control Functions ==================================================================
function _callerIsIssuer__validate() internal view {
if (!_isValidIssuer(msg.sender)) {
revert CommitmentOrderflow_accessDenied();
}
}
/// Validation Functions ----------------------------------------------------------------------
function _commitment__validate(
bytes calldata fqdn_,
address registrant_,
bytes32 nonce_,
Datastructures.RegistrationRequest memory req_
) internal view returns (bytes32 secretHash_) {
bytes32 tld_;
bytes32 node_;
// Validate the registration relative to the commitment type
if(_isRegistrationCommitment(req_.commitmentType, false) || _isTransferCommitment(req_.commitmentType)) {
bytes memory label_;
(label_, tld_) = _createRegistration__validate(fqdn_, registrant_, req_.duration);
// Calculate the target node
node_ = _calculateNode(label_, tld_);
} else if (_isRenewalCommitment(req_.commitmentType, false)) {
// Parse the label from the fqdn
(, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Parse the tld from the fqdn
tld_ = BytesUtils.namehash(fqdn_, offset_);
// Validate the renewal
_extendRegistration__validate(labelHash_, tld_, req_.duration);
// Calculate the node
node_ = _calculateNode(labelHash_, tld_);
} else {
revert CommitmentOrderflow_invalidCommitmentType(req_.commitmentType);
}
// Validate the request
_validateRegistrationRequest(tld_, req_);
// Validate nonce is not null nonce
if (nonce_ == NULL_NONCE)
revert CommitmentOrderflow_invalidNonce();
// Build the secret
Datastructures.RegistrationSecret memory secret_;
secret_.registrant = registrant_;
secret_.node = node_;
secret_.nonce = nonce_;
// Calculate the secret hash
return _calculateSecretHash(secret_);
}
bytes32 constant private NULL_NONCE = 0xf490de2920c8a35fabeb13208852aa28c76f9be9b03a4dd2b3c075f7a26923b4;
function _offchainCommitment__validate(
bytes32 node_,
address registrant_,
uint64 duration_,
Datastructures.CommitmentType commitmentType_,
Datastructures.AuthorizationSignature memory sig_
) internal view {
// Run access control check
_callerIsIssuer__validate();
// Validate the commitment type
if (!_isOffchainCommitment(commitmentType_)) {
revert CommitmentOrderflow_invalidCommitmentType(commitmentType_);
}
// Build the issue domain request
Datastructures.RegistrationRequest memory req_;
req_.commitmentType = commitmentType_;
req_.duration = duration_;
// Build the secret
Datastructures.RegistrationSecret memory secret_;
secret_.registrant = registrant_;
secret_.node = node_;
secret_.nonce = NULL_NONCE;
// Build and verify the commitment hash
_commitment__verify(
_twoPhase__prepare(req_, _calculateSecretHash(secret_)),
sig_
);
}
function _transferCommitment__validate(bytes32 node_, address registrant_) internal view {
// Run access control check
_callerIsIssuer__validate();
// Confirm that the registrant has a transfer flag enabled for the node
if (!Storage.hasDomainTransferFlag(registrant_, node_))
revert CommitmentOrderflow_transferDoesNotExist();
}
function _commitment__verify(bytes32 commitmentHash_, Datastructures.AuthorizationSignature memory sig_)
internal
view
{
// Build the RegistrationAuthorization struct
RegistrationAuthorization memory authorization_;
authorization_.commitmentHash_ = commitmentHash_;
authorization_.issuedAt = sig_.issuedAt;
authorization_.expiresAt = sig_.expiresAt;
// Validate the signature
_validateSignature(authorization_, sig_.v, sig_.r, sig_.s);
}
function _commitment__store(
bytes32 commitmentHash_,
Datastructures.CommitmentType commitmentType_,
address committer_
) private returns (uint64 revocableAt_) {
// Calculate recovableAt from COMMITMENT_HALF_LIFE
revocableAt_ = uint64(block.timestamp + Storage.COMMITMENT_HALF_LIFE());
// Store the commitment
Storage.setCommitmentData(commitmentHash_, committer_, revocableAt_);
}
function _commitment__process(bytes32 commitmentHash_) private returns (bytes32) {
// Get the commitment data
(address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
// Validate the commitment
if (committer_ == address(0) || revokableAt_ == 0) {
revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
}
// Remove the commitment
Storage.deleteCommitment(commitmentHash_);
return commitmentHash_;
}
function _commitment__refund(bytes32 commitmentHash_, Datastructures.RegistrationRequest calldata req_)
private
returns (address recipient_)
{
// Get the commitment data
(address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
// Validate the commitment
if (committer_ == address(0) || revokableAt_ == 0) {
revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
}
// Remove the commitment
Storage.deleteCommitment(commitmentHash_);
// Refund the registration payment & service payment
if (_isTransferCommitment(req_.commitmentType)) {
_handlePayout(req_.registrationPayment, _getPayoutAddress(0x0));
} else {
_handlePayout(req_.registrationPayment, committer_);
}
if (req_.servicePayment.amount > 0) _handlePayout(req_.servicePayment, committer_);
return committer_;
}
/// Two Phase Helpers ///
function _twoPhase__prepare(Datastructures.RegistrationRequest memory req_, bytes32 secretHash_)
private
pure
returns (bytes32 commitmentHash_)
{
// Build the secret hash & the commitment hash
//
// The secret hash shields the registration details from the public
// and the commitment hash binds the payment to the secret hash.
// The commitment hash is valid until the commitment is either
// processed, extended, or revoked.
//
// The commitment hash half life is calculated when the commitment
// is made ~ it is valid till block.timestamp + COMMITMENT_HALF_LIFE.
Datastructures.InternalCommitment memory commitment_;
commitment_.request = req_;
commitment_.secretHash_ = secretHash_;
return _calculateCommitmentHash(commitment_);
}
function _twoPhase__validateMake(bytes32 commitmentHash_) private view {
(address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
// Validate the uniqueness of the commitment
if (committer_ != address(0) || revokableAt_ != 0) {
revert CommitmentOrderflow_commitmentAlreadyExists(commitmentHash_);
}
}
function _twoPhase__validateRefund(bytes32 commitmentHash_) private view {
// Get the commitment data
(address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
// Validate the commitment exists
if (committer_ == address(0) || revokableAt_ == 0) {
revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
}
// Verify the commitment has not expired, if so, let the user revoke it
if (block.timestamp >= revokableAt_) {
revert CommitmentOrderflow_commitmentNotRefundable(commitmentHash_);
}
}
function _twoPhase__validateRevoke(bytes32 commitmentHash_) private view {
// Get the commitment data
(address committer_, uint64 revokableAt_) = Storage.getCommitmentData(commitmentHash_);
// Validate the commitment exists
if (committer_ == address(0) || revokableAt_ == 0) {
revert CommitmentOrderflow_commitmentDoesNotExist(commitmentHash_);
}
// Verify the commitment has expired, if not, reject the revocation
if (block.timestamp < revokableAt_) {
revert CommitmentOrderflow_commitmentNotRevokable(commitmentHash_, revokableAt_);
}
}
/// Accessor Functions ------------------------------------------------------------------------
/// ... ///
/// Helper Functions --------------------------------------------------------------------------
function _setTraderTokenizationTier(uint32 controlBitmap_, bool isTrader_) internal returns (uint32) {
return isTrader_ ? controlBitmap_ | 1 << 16 : controlBitmap_; // & ~(1 << 16);
}
function _isRegistrationCommitment(Datastructures.CommitmentType commitmentType_, bool offchain_) internal pure returns (bool) {
return offchain_ ? (
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__FULL_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION
) : (
commitmentType_ == Datastructures.CommitmentType.REGISTRATION__FULL_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.REGISTRATION__TRADER_TOKENIZATION
);
}
function _isTransferCommitment(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
return
commitmentType_ == Datastructures.CommitmentType.TRANSFER__FULL_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.TRANSFER__TRADER_TOKENIZATION;
}
function _isRenewalCommitment(Datastructures.CommitmentType commitmentType_, bool offchain_) internal pure returns (bool) {
return offchain_ ? (
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION
) : (
commitmentType_ == Datastructures.CommitmentType.RENEWAL ||
commitmentType_ == Datastructures.CommitmentType.RENEWAL__TRADER_TOKENIZATION
);
}
function _isTraderTokenization(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
return commitmentType_ == Datastructures.CommitmentType.REGISTRATION__TRADER_TOKENIZATION||
commitmentType_ == Datastructures.CommitmentType.TRANSFER__TRADER_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.RENEWAL__TRADER_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION;
}
function _isOffchainCommitment(Datastructures.CommitmentType commitmentType_) internal pure returns (bool) {
return commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__FULL_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN__TRADER_TOKENIZATION ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL ||
commitmentType_ == Datastructures.CommitmentType.OFFCHAIN_RENEWAL__TRADER_TOKENIZATION;
}
/// Misc Validators ---------------------------------------------------------------------------
function _validateRegistrationRequest(bytes32 tld_, Datastructures.RegistrationRequest memory req_) internal view {
// Validate the commitment type
/// @note duration is validated in _createRegistration__validate
// Validate the registration & service payments
_validateRegistrationPayment(req_.registrationPayment, tld_, req_.duration);
_validatePayment(req_.servicePayment, true);
// Validate the service payment type matches the registration
if (req_.registrationPayment.paymentType != req_.servicePayment.paymentType) {
revert CommitmentOrderflow_invalidPaymentType(req_.servicePayment.paymentType);
}
}
/// Administrative Action Validators ==========================================================
/// @dev Message signature function override for signer role check.
function _isValidSigner(address signer_) internal view override returns (bool) {
return authority().isRole(authority().ROLE__SIGNER(), signer_);
}
/// @dev Internal function for issuer role check.
function _isValidIssuer(address issuer_) internal view returns (bool) {
return authority().isRole(authority().ROLE__ISSUER(), issuer_);
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {IERC165Upgradeable as IERC165} from "openzeppelin-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import {IERC721, IERC721Metadata} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI} from "src/regcontrol/interfaces/tokens/IERC1155.sol";
/// Internal References ---------------------------------------------------------------------------
import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {CustomToken} from "src/regcontrol/modules/types/custom/CustomToken.sol";
import {CustomENS} from "src/regcontrol/modules/types/custom/CustomENS.sol";
import {IDomainController} from "src/regcontrol/interfaces/IDomainController.sol";
import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";
import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";
/// Errors ----------------------------------------------------------------------------------------
contract DomainController is
IDomainController,
CustomToken,
CustomENS,
ThreeDNSAccessControlled
{
/// Management Functions ----------------------------------------------------------------------
function setPrimaryResolver(address resolver_) external {
// Run access control validation
_callerIsOperator__validate();
RegControlStorage.setPrimaryResolver(resolver_);
}
/// Shared Management Functions ---------------------------------------------------------------
function setApprovalForAll(address operator_, bool approval) public override(IDomainController, IENS, ICustomToken) {
// Function uses msg.sender for account indexed operations
_setAccountOperatorApproval(operator_, approval);
}
function isApprovedForAll(address account_, address operator_) public view override(IDomainController, IENS, ICustomToken) returns (bool) {
return _isApprovedAccountOperator(account_, operator_);
}
function tokenData(uint256 node_) external view returns (address registrant, uint32 controlBitmap, uint64 expiration) {
return _getNodeData(bytes32(node_));
}
/// Accessor Functions ------------------------------------------------------------------------
function _tokenExists(uint256 node_) internal view override returns (bool) {
return _getRegistrant(bytes32(node_)) != address(0x00);
}
/// ERC165 Functions ---------------------------------------------------------------------------
/// @dev ERC165 introspection support.
function supportsInterface(bytes4 interfaceId_) public view returns (bool) {
return
interfaceId_ == type(IENS).interfaceId ||
interfaceId_ == type(IERC1155).interfaceId ||
interfaceId_ == type(IERC1155MetadataURI).interfaceId ||
interfaceId_ == type(IERC721).interfaceId ||
interfaceId_ == type(IERC721Metadata).interfaceId ||
interfaceId_ == type(IERC165).interfaceId;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {AbstractPaymentProcessor} from "src/regcontrol/modules/types/abstracts/AbstractPaymentProcessor.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {PaymentStorage as Storage} from "src/regcontrol/storage/Storage.sol";
import {IWETH} from "src/utils/interfaces/IWETH.sol";
/// Errors -------------------------------------------------------------------------------------
error PaymentProcessor_insufficientPayment(
Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_insufficientBalance(
Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_insufficientAllowance(
Datastructures.PaymentType paymentType, uint256 paymentAmount, uint256 amount
);
error PaymentProcessor_invalidPaymentType(Datastructures.PaymentType paymentType);
error PaymentProcessor_transferFailed();
error PaymentProcessor_permitFailed();
contract PaymentProcessor is Initializable, AbstractPaymentProcessor {
/// Constants ------------------------------------------------------------------------------
address payable constant private WETH = payable(0x4200000000000000000000000000000000000006);
bytes32 internal constant _TLD_NODE__BOX = 0x665b1306e8eb7fc67d224df1c4ceb9003655ecffaf26d78c2832fe4788a22617;
address internal constant _WITHDRAWL_ADDRESS__3DNS = 0xBBa294D303555032C6BD1021C639654b95e77Fa8;
address internal constant _WITHDRAWL_ADDRESS__BOX = 0xBff9E8b1F5eBd6B248238fAAF02F6eC09255ad51;
/// Initialization Functions ==================================================================
function __PaymentProcessor_init(IERC20 _usdc) internal onlyInitializing {
Storage.initialize(_usdc);
}
/// Abstract Payment Function Implemantations =================================================
function _validateRegistrationPayment(Datastructures.OrderPayment memory payment_, bytes32 tld_, uint64 duration_)
internal
view
override
{
// TODO: Validate the payment amount relative to the tld
// Validate the payment
_validatePayment(payment_, false);
}
function _validatePayment(Datastructures.OrderPayment memory payment_, bool zeroPayments_)
internal
pure
override
{
// Validate that the payment currency is supported
if (
payment_.paymentType != Datastructures.PaymentType.ETH
&& payment_.paymentType != Datastructures.PaymentType.USDC
) {
revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
}
// Validate the payment amount
if (!zeroPayments_ && payment_.amount == 0) {
revert PaymentProcessor_insufficientPayment(payment_.paymentType, 0, 0);
}
}
function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_)
internal
override
{
return _handlePayment(payment_, isCommitment_, msg.sender);
}
function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_, address payee_)
internal
{
uint256 amount_;
// TODO: Add onchain bounds and handling for the payment amount
// If this is a commitment payment, then this contract becomes the recipient of the funds
address recipient_ = isCommitment_ ? address(this) : _WITHDRAWL_ADDRESS__3DNS;
// Handle the payment
if (payment_.paymentType == Datastructures.PaymentType.ETH) {
// ETH payments are processed in WETH
if ((amount_ = IWETH(WETH).balanceOf(address(this))) < payment_.amount) {
revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
}
// Unwrap the WETH
IWETH(WETH).withdraw(payment_.amount);
if (!isCommitment_) {
(bool success,) = payable(recipient_).call{value: payment_.amount}("");
if (!success) revert PaymentProcessor_transferFailed();
}
} else if (payment_.paymentType == Datastructures.PaymentType.USDC) {
if ((amount_ = Storage.ERC20_USDC_ADDRESS().balanceOf(payee_)) < payment_.amount) {
revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
}
if ((amount_ = Storage.ERC20_USDC_ADDRESS().allowance(payee_, address(this))) < payment_.amount) {
revert PaymentProcessor_insufficientAllowance(payment_.paymentType, uint256(payment_.amount), amount_);
}
// Pull USDC from the caller
Storage.ERC20_USDC_ADDRESS().transferFrom(payee_, recipient_, uint256(payment_.amount));
} else {
revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
}
}
function _handlePayout(Datastructures.OrderPayment memory payment_, address recipient_) internal override {
uint256 amount_;
if (payment_.paymentType == Datastructures.PaymentType.ETH) {
if (address(this).balance < payment_.amount) {
revert PaymentProcessor_insufficientPayment(
payment_.paymentType, uint256(payment_.amount), address(this).balance
);
}
// Transfer ETH to the recipient
(bool success_,) = payable(recipient_).call{value: payment_.amount}("");
if (!success_) revert PaymentProcessor_transferFailed();
} else if (payment_.paymentType == Datastructures.PaymentType.USDC) {
if ((amount_ = Storage.ERC20_USDC_ADDRESS().balanceOf(address(this))) < payment_.amount) {
revert PaymentProcessor_insufficientBalance(payment_.paymentType, uint256(payment_.amount), amount_);
}
// Send USDC from the contract to the recipient
bool success_ = Storage.ERC20_USDC_ADDRESS().transfer(recipient_, uint256(payment_.amount));
if (!success_) revert PaymentProcessor_transferFailed();
} else {
revert PaymentProcessor_invalidPaymentType(payment_.paymentType);
}
}
function _getPayoutAddress(bytes32 tld_) internal pure override returns (address) {
// TODO: Update this to the root owner / custodian
if (tld_ == _TLD_NODE__BOX) return _WITHDRAWL_ADDRESS__BOX;
return _WITHDRAWL_ADDRESS__3DNS;
}
/// Accessor Functions ------------------------------------------------------------------------
function ERC20_USDC_ADDRESS() public view override returns (IERC20) {
return Storage.ERC20_USDC_ADDRESS();
}
// function rentPrice(
// string memory label_,
// bytes32 tld_,
// uint256 duration_,
// Datastructures.PaymentType paymentType_
// ) external view returns (uint256 amount_) {
// revert PaymentModule_notSupported();
// }
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {IRegistrarController} from "src/regcontrol/interfaces/IRegistrarController.sol";
// import {AbstractAccessControlled} from "src/utils/access/abstracts/AbstractAccessControlled.sol";
import {ThreeDNSAccessControlled} from "src/utils/access/ThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "src/utils/access/interfaces/IThreeDNSAuthority.sol";
import {Registry} from "src/regcontrol/modules/types/Registry.sol";
import {RegistryStorage, RegistrarStorage, PaymentStorage} from "src/regcontrol/storage/Storage.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {HybridMetadataStorage} from "src/regcontrol/storage/Storage.sol";
/// Errors ----------------------------------------------------------------------------------------
error RegistrarController_accessDenied();
error RegistrarController_tldExists();
error RegistrarController_tldDoesntExist();
error RegistrarController_invalidLabel(bytes label);
/// Contract --------------------------------------------------------------------------------------
contract RegistrarController is
IRegistrarController,
Initializable,
ThreeDNSAccessControlled,
Registry
{
constructor(IThreeDNSAuthority _authority) initializer {
ThreeDNSAccessControlled.__ThreeDNSAccessControlled_init(_authority);
}
/// Management Functions ----------------------------------------------------------------------
function registerTLD(bytes calldata tld_) external {
// Run access control check
_callerIsRegistrarAdmin__validate();
// Validate & register the tld
_registerTLD(tld_);
}
function setTLDMetadata(bytes32 tld_, string calldata baseUrl_, string calldata description_) external {
// Run access control check
_callerIsRegistrarAdmin__validate();
// Validate tld is registered
if (tld_ != bytes32(0) && !_isRegisteredTLD(tld_))
revert RegistrarController_tldDoesntExist();
// Set the metadata
HybridMetadataStorage.setMetadata(tld_, baseUrl_, description_);
}
// TODO: Add updateTLD and disableTLD functions
/// Inforcement Functions ---------------------------------------------------------------------
event UDRPDecision(bytes32 indexed node, address recipient, string caseLink);
function processUDRPdecision(bytes32 node_, address recipient_, string memory caseLink_) external {
// Run access control check
_callerIsRegistrarAdmin__validate();
// If recipient address is 0, burn the domain
if (recipient_ == address(0)) {
// Burn the domain
_burnRegistration(node_);
} else {
// Transfer the domain to the recipient
_transferRegistration(node_, recipient_);
}
emit UDRPDecision(node_, recipient_, caseLink_);
}
function lockRegistration(bytes32 node_, uint64 duration_) external {
// Run access control check
_callerIsRegistrarAdmin__validate();
// Lock the domain
_lockRegistration(node_, duration_);
}
function unlockRegistration(bytes32 node_) external {
// Run access control check
_callerIsRegistrarAdmin__validate();
// Unlock the domain
_removeRegistrationLock(node_);
}
/// Accessor Functions ------------------------------------------------------------------------
function getTLDData(bytes32 tld_) external view returns (bool enabled_) {
// Return the tld data
return _isRegisteredTLD(tld_);
}
function getTLDMetadata(bytes32 tld_) external view returns (string memory baseUrl_, string memory description_) {
// Validate tld is registered
if (!_isRegisteredTLD(tld_))
revert RegistrarController_tldExists();
return HybridMetadataStorage.getMetadata(tld_);
}
/// Internal Helper Functions -----------------------------------------------------------------
function _registerTLD(bytes calldata tld_) internal {
// Validate the tld & accessory data
bytes32 node_ = _tld__prepare(tld_);
// Validate uniqueness and register the tld
_tld__register(tld_, node_);
// Emit events //
// ERC721 Event
emit Transfer(address(0x00), address(this), uint256(node_));
// ERC1155 Event
emit TransferSingle(msg.sender, address(0x00), address(this), uint256(node_), 1);
// ENS Event
emit NewOwner(bytes32(0x00), keccak256(tld_), address(this));
emit Transfer(node_, address(this));
}
/// Validation Functions ----------------------------------------------------------------------
function _tld__prepare(bytes calldata tld_) internal pure returns (bytes32 node_) {
// Validate the tld
if (!_isValidTLDLabel(tld_)) {
revert RegistrarController_invalidLabel(tld_);
}
// Calculate node
node_ = _calculateNode(tld_, bytes32(0));
// TODO: Add additional state specific validations
// Return the node
return node_;
}
/// Private State Management Functions --------------------------------------------------------
function _tld__register(bytes calldata label_, bytes32 node_) private {
// Validate tld is not already registered
if (_isRegisteredTLD(node_))
revert RegistrarController_tldExists();
/// @dev Registry Storage
// Store node in root registry with a parent of 0x00
// Initialize the record data
// Set the registrant as self and the expiration to max uint64
RegistryStorage.createNewRecord(node_, address(this), 0, ~uint64(0));
// Track the ownership
RegistryStorage.trackNewOwnership(node_, address(this));
// Build a reverse record mapping for the tld to the root label
RegistryStorage.trackReverseRecord(bytes32(0x00), label_);
/// @dev Registrar Storage
// Register the tld in the registrar
RegistrarStorage.registerTLD(node_);
}
/// Validation Helper Functions ---------------------------------------------------------------
function _isRegisteredTLD(bytes32 node_) internal view returns (bool) {
(bool enabled) = RegistrarStorage.getTLDData(node_);
return enabled;
}
function _isValidTLDLabel(bytes calldata label_) internal pure returns (bool) {
// Check if label is less than 2 or exceeds 18 characters
if (label_.length < 0x02 || label_.length > 0x12) return false;
// Check if label contains invalid characters
for (uint256 i = 0; i < label_.length; i++) {
bytes1 char_ = label_[i];
// Ensure alphanumeric.
if (!(char_ >= 0x61 && char_ <= 0x7A)) {
return false;
}
}
return true;
}
/// Access Control Functions ------------------------------------------------------------------
function _callerIsRegistrarAdmin__validate() internal view {
if (!_isValidRegistrarAdmin(msg.sender)) {
revert RegistrarController_accessDenied();
}
}
/// Administrative Action Validators ----------------------------------------------------------
function _isValidRegistrarAdmin(address sender_) internal view returns (bool) {
return authority().isRole(authority().ROLE__REGISTRAR_ADMIN(), sender_);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {ReentrancyGuardDiamond} from "src/utils/access/ReentrancyGuardDiamond.sol";
import {SponsorShieldDiamond} from "src/utils/access/SponsorShieldDiamond.sol";
import {IMulticall} from "src/regcontrol/interfaces/IMulticall.sol";
import {IWETH} from "src/utils/interfaces/IWETH.sol";
// import {RegControl} from "src/regcontrol/RegControl.sol";
/// Multicall ----------------------------------------------------------------------------------
contract Multicall is
IMulticall,
Initializable,
ReentrancyGuardDiamond,
SponsorShieldDiamond
{
/// @dev Disable initializers for template contracts, as they are not meant to be initialized.
constructor(bool embed) {
if (!embed) __Multicall_init__self();
}
function __Multicall_init__self() internal initializer {
__ReentrancyGuard_init();
}
/// @dev Initializes the contract state.
function __Multicall_init() internal onlyInitializing {
__ReentrancyGuard_init();
}
/// @dev WETH address
address payable private constant WETH = payable(0x4200000000000000000000000000000000000006);
/// @dev Receives and executes a batch of function calls on this contract.
function multicall(bytes[] calldata data) external payable override nonReentrant returns (bytes[] memory results) {
bool hasValue_ = false;
if (msg.value > 0) {
// Take passed ETH and convert to WETH
IWETH(WETH).deposit{value: msg.value}();
hasValue_ = true;
}
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
// @audit 'delegatecall' forwards 'msg.value'
results[i] = AddressUpgradeable.functionDelegateCall(address(this), data[i]);
}
// Clear hooks
_clearHooks();
// Transfer any remaining WETH back to the sender
if (hasValue_ && IWETH(WETH).balanceOf(address(this)) > 0) {
IWETH(WETH).transfer(msg.sender, IWETH(WETH).balanceOf(address(this)));
}
return results;
}
function _clearHooks() private {
// Clear sponsor shield hook
_cleanupSponsorShield();
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.18; import "./types/CommitmentStorage.sol"; import "./types/PaymentStorage.sol"; import "./types/RebateIssuerStorage.sol"; import "./types/RegistryStorage.sol"; import "./types/RegistrarStorage.sol"; import "./types/RegControlStorage.sol"; import "./types/MetadataStorage.sol"; import "./types/HybridMetadataStorage.sol"; import "./types/IAMStorage.sol";
// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {IThreeDNSAuthority} from "../interfaces/IThreeDNSAuthority.sol";
library ReentrancyGuardStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__REENTRANCY_GUARD_STORAGE__V1 =
keccak256("3dns.access_controlled.reentrancy_guard.v1.state");
/// Constants ---------------------------------------------------------------------------------
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 internal constant _NOT_ENTERED = 1;
uint256 internal constant _ENTERED = 2;
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
uint256 status;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__REENTRANCY_GUARD_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize() internal {
_setStatus(_NOT_ENTERED);
}
/// Helper Functions --------------------------------------------------------------------------
function _setStatus(uint256 status) internal {
layout().status = status;
}
function _getStatus() internal view returns (uint256) {
return layout().status;
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.18; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ interface IDiamondCut { enum FacetCutAction {Add, Replace, Remove} // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.18; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import "src/regcontrol/interfaces/diamond/IDiamondCut.sol"; error LibDiamondCut_facetAlreadyExists(address addr, bytes4 selector); error LibDiamondCut_facetDoesNotExist(address addr, bytes4 selector); error LibDiamondCut_immutableFunction(address addr, bytes4 selector); // LibDiamondCut: Incorrect FacetCutAction // LibDiamondCut: No selectors in facet to cut // LibDiamondCut: Add facet can't be address(0) // LibDiamondCut: New facet has no code // LibDiamondCut: Can't add function that already exists // LibDiamondCut: No selectors in facet to cut // LibDiamondCut: Add facet can't be address(0) // LibDiamondCut: New facet has no code // LibDiamondCut: Can't replace function with same function // LibDiamondCut: No selectors in facet to cut // LibDiamondCut: Remove facet address must be address(0) // LibDiamondCut: Can't remove function that doesn't exist // LibDiamondCut: Can't remove immutable function // LibDiamondCut: _init is address(0) but_calldata is not empty // LibDiamondCut: _calldata is empty but _init is not address(0) // LibDiamondCut: _init address has no code // LibDiamondCut: _init function reverted library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndPosition { address facetAddress; uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } struct FacetFunctionSelectors { bytes4[] functionSelectors; uint16 facetAddressPosition; // position of facetAddress in facetAddresses array } struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function enforceIsContractOwner() internal view { require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner"); } event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // uint16 selectorCount = uint16(diamondStorage().selectors.length); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code"); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length); ds.facetAddresses.push(_facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; if (oldFacetAddress != address(0)) revert LibDiamondCut_facetAlreadyExists(oldFacetAddress, selector); // require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists"); ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector); ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress; ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition; selectorPosition++; } } function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)"); uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length); // add new facet address if it does not exist if (selectorPosition == 0) { enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code"); ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length); ds.facetAddresses.push(_facetAddress); } for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function"); removeFunction(oldFacetAddress, selector); // add function ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector); ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress; selectorPosition++; } } function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal { require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut"); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)"); for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress; removeFunction(oldFacetAddress, selector); } } function removeFunction(address _facetAddress, bytes4 _selector) internal { DiamondStorage storage ds = diamondStorage(); if (_facetAddress == address(0)) revert LibDiamondCut_facetDoesNotExist(_facetAddress, _selector); // an immutable function is a function defined directly in a diamond if (_facetAddress == address(this)) revert LibDiamondCut_immutableFunction(_facetAddress, _selector); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition; uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector; ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint16(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = uint16(facetAddressPosition); } ds.facetAddresses.pop(); delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition; } } function initializeDiamondCut(address _init, bytes memory _calldata) internal { if (_init == address(0)) { require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty"); } else { require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)"); if (_init != address(this)) { enforceHasContractCode(_init, "LibDiamondCut: _init address has no code"); } (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up the error revert(string(error)); } else { revert("LibDiamondCut: _init function reverted"); } } } } function enforceHasContractCode(address _contract, string memory _errorMessage) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IThreeDNSAuthority} from "./IThreeDNSAuthority.sol";
interface IThreeDNSAccessControlled {
event AuthorityChanged(IThreeDNSAuthority indexed previousAuthority, IThreeDNSAuthority indexed newAuthority);
function authority() external view returns (IThreeDNSAuthority);
function changeAuthority(IThreeDNSAuthority _newAuthority) external;
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {IThreeDNSAuthority} from "../interfaces/IThreeDNSAuthority.sol";
library AccessControlledStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__ACCESS_CONTROLLED_STORAGE__V1 =
keccak256("3dns.access_controlled.authority.v1.state");
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
/// @dev authority contract
IThreeDNSAuthority authority;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__ACCESS_CONTROLLED_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize(IThreeDNSAuthority authority_) internal {
changeAuthority(authority_);
}
/// Accessor Functions ------------------------------------------------------------------------
function authority() internal view returns (IThreeDNSAuthority) {
return layout().authority;
}
function changeAuthority(IThreeDNSAuthority newAuthority_) internal {
if (address(newAuthority_) == address(0)) {
revert();
}
layout().authority = newAuthority_;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
interface ICommitmentOrderflow {
/// Events ---------------------------------------------------------------------------------
/// Two Phase Commitments ///
// Commitment V1 Signature
// event PendingCommitment(
// bytes32 indexed commitmentHash_, uint64 indexed revocableAt_, address indexed committer,
// Datastructures.OrderPayment payment,
// uint8 v_, bytes32 r_, bytes32 s_
// );
//
// event RefundCommitment(
// bytes32 indexed commitmentHash_, address indexed issuer, address indexed committer,
// Datastructures.OrderPayment payment
// );
//
// event RevokeCommitment(
// bytes32 indexed commitmentHash_, address indexed committer,
// Datastructures.OrderPayment payment
// );
event PendingCommitment(
bytes32 indexed commitmentHash_,
uint64 indexed revocableAt_,
address indexed committer,
Datastructures.OrderPayment registrationPayment,
Datastructures.OrderPayment servicePayment,
uint8 v_,
bytes32 r_,
bytes32 s_
);
event RefundCommitment(
bytes32 indexed commitmentHash_,
address indexed issuer,
address indexed committer,
Datastructures.CommitmentType commitmentType,
Datastructures.OrderPayment registrationPayment,
Datastructures.OrderPayment servicePayment
);
event RevokeCommitment(
bytes32 indexed commitmentHash_,
address indexed committer,
Datastructures.CommitmentType commitmentType,
Datastructures.OrderPayment registrationPayment,
Datastructures.OrderPayment servicePayment
);
event ProcessCommitment(bytes32 indexed commitmentHash_, address indexed processor);
/// Offchain Commitments ///
event IssuedDomainName(bytes32 indexed node_, address indexed issuer_);
// event IssuedDomainName(bytes32 indexed node_, address indexed issuer_, uint64 indexed lockedUntil_);
/// Service Orderflows ///
event PurchasedService(
bytes32 indexed commitment_, address indexed registrant_, Datastructures.OrderPayment payment
);
/// Purchase Orderflows -----------------------------------------------------------------------
/// Two Phase Orderflows ///
function validateCommitmentV2(
bytes calldata fqdn_,
address registrant_,
bytes32 nonce_,
Datastructures.RegistrationRequest memory req_
) external view returns (bytes32 secretHash_);
function makeCommitmentV2(
bytes32 secretHash_,
Datastructures.RegistrationRequest memory req_,
Datastructures.AuthorizationSignature memory sig_,
address committer_
) external payable;
// // Purchasing a domain will trigger a series of events:
// // 1. A NewRegistration event will be emitted
// // 2. A TransferSingle event will be emitted
// // 3. A Renewed event will be emitted with the expiry date of the domain
// // function validateCommitment(
// // bytes calldata fqdn_,
// // address registrant_,
// // uint64 duration_,
// // bytes32 nonce_,
// // Datastructures.OrderPayment calldata payment_
// // ) external view returns (bytes32 secretHash_);
// function validateCommitmentV2(
// bytes calldata fqdn_,
// address registrant_,
// bytes32 nonce_,
// Datastructures.RegistrationRequest calldata req_
// ) external view returns (bytes32 secretHash_);
// // function makeCommitment(
// // bytes32 secretHash_,
// // uint64 duration_,
// // Datastructures.OrderPayment calldata payment_,
// // uint64 issuedAt_,
// // uint64 expiresAt_,
// // uint8 v_,
// // bytes32 r_,
// // bytes32 s_
// // ) external payable;
// function processCommitment(
// bytes calldata fqdn_,
// address registrant_,
// bytes32 nonce_,
// Datastructures.RegistrationRequest calldata req_
// ) external;
// function refundCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external;
// function revokeCommitment(Datastructures.RegistrationRequest calldata req_, bytes32 secretHash_) external;
/// Off-Chain Issuance ------------------------------------------------------------------------
/// Off-Chain Orderflows ///
// // Issued domain names cant be transferred for the first 30 days
// function issueDomainName(
// bytes calldata fqdn_, address registrant_, uint64 duration_,
// Datastructures.AuthorizationSignature memory sig_
// ) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
import {TypedDataSignature} from "src/utils/signature/TypedDataSignature.sol";
abstract contract RegistrationAuthorizor is TypedDataSignature {
/// Datastructures ----------------------------------------------------------------------------
/// @title RegistrationAuthorization
/// @notice Represents the details of a typed data signature.
/// @param commitment The commitment being signed.
/// @param payment The payment details for the order.
/// @param issuedAt The timestamp of when the signature was issued.
/// @param expiresAt The timestamp of when the signature expires.
struct RegistrationAuthorization {
Datastructures.InternalCommitment commitment;
uint64 issuedAt;
uint64 expiresAt;
bytes32 commitmentHash_;
}
/// Peusdo Constants ---------------------------------------------------------------------------
// Define the EIP712 Type for the TypedDataSignature struct
bytes32 public immutable override TYPED_DATA_SIGNATURE_TYPEHASH;
constructor() {
TYPED_DATA_SIGNATURE_TYPEHASH = keccak256(
"RegistrationAuthorizationV2(InternalCommitment commitment,uint64 issuedAt,uint64 expiresAt)InternalCommitment(RegistrationRequest request,RegistrationSecret secret)RegistrationRequest(CommitmentType commitmentType,uint64 duration,OrderPayment registrationPayment,OrderPayment servicePayment)RegistrationSecret(address registrant,bytes32 node,bytes32 nonce)OrderPayment(PaymentType paymentType,uint248 amount)"
);
}
/// Initializer ----------------------------------------------------------------------------
function __RegistrationAuthorizor_init(
string memory domainName_,
string memory domainVersion_,
uint64 chainId_
) internal onlyInitializing {
TypedDataSignature.__TypedDataSignature_init(domainName_, domainVersion_, chainId_);
}
/// Typed Data Signature Functions ============================================================
function _validateSignature(RegistrationAuthorization memory sig_, uint8 v_, bytes32 r_, bytes32 s_) internal view {
_validateSignature(
abi.encode(sig_),
v_, r_, s_
);
}
function _calculateTypeHash(bytes memory data_) internal view override returns (bytes32) {
RegistrationAuthorization memory sig_ = abi.decode(data_, (RegistrationAuthorization));
if (sig_.commitmentHash_ == bytes32(0))
sig_.commitmentHash_ = _calculateCommitmentHash(sig_.commitment);
// Return the internale type-hash of the data
return keccak256(
abi.encode(
TYPED_DATA_SIGNATURE_TYPEHASH,
sig_.commitmentHash_,
sig_.issuedAt,
sig_.expiresAt
)
);
}
function _calculateCommitmentHash(Datastructures.InternalCommitment memory commitment_) internal pure returns (bytes32) {
if (commitment_.secretHash_ == bytes32(0))
commitment_.secretHash_ = _calculateSecretHash(commitment_.secret);
// Return the internale type-hash of the commitment
return keccak256(
abi.encode(
_calculateRequestHash(commitment_.request),
commitment_.secretHash_
)
);
}
function _calculateRequestHash(Datastructures.RegistrationRequest memory req) internal pure returns (bytes32) {
// Return the internale type-hash of the req
return keccak256(
abi.encode(
req.commitmentType,
req.duration,
_calculatePaymentHash(req.registrationPayment),
_calculatePaymentHash(req.servicePayment)
)
);
}
function _calculateSecretHash(Datastructures.RegistrationSecret memory secret) internal pure returns (bytes32) {
// Return the internale type-hash of the secret
return keccak256(
abi.encode(
secret.registrant,
secret.node,
secret.nonce
)
);
}
function _calculatePaymentHash(Datastructures.OrderPayment memory payment_) internal pure returns (bytes32) {
// Return the internale type-hash of the payment
return keccak256(
abi.encode(
payment_.paymentType,
payment_.amount
)
);
}
function _validPayload(bytes memory data_) internal view virtual override returns (bool) {
RegistrationAuthorization memory sig_ = abi.decode(data_, (RegistrationAuthorization));
// Verify that the signature is not expired and not issued in the future
return (block.timestamp < sig_.expiresAt) && (block.timestamp > sig_.issuedAt);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {ReentrancyGuardStorage as Storage} from "src/utils/access/storage/ReentrancyGuardStorage.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardDiamond is Initializable {
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
Storage.initialize();
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(Storage._getStatus() != Storage._ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
Storage._setStatus(Storage._ENTERED);
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
Storage._setStatus(Storage._NOT_ENTERED);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return Storage._getStatus() == Storage._ENTERED;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {SponsorShieldStorage as Storage} from "src/utils/access/storage/SponsorShieldStorage.sol";
error sponsorShield_invalidPaymentType();
error sponsorShield_insufficientAmount();
error sponsorShield_alreadySponsored();
error sponsorShield_unsponsoredPayment();
abstract contract SponsorShieldDiamond is Initializable {
function __SponsorShield_init() internal onlyInitializing {
__SponsorShield_init_unchained();
}
function __SponsorShield_init_unchained() internal onlyInitializing {
Storage.initialize();
}
function _startSponsorShield(address payee_, uint256 paymentType_, uint256 paymentAmount_) internal {
// Validate guard is not already active
if (Storage._getStatus() == Storage._SPONSORED)
revert sponsorShield_alreadySponsored();
// Start guard
Storage._setStatus(Storage._SPONSORED);
// Track action
Storage._setPayee(payee_);
Storage._setPaymentType(paymentType_);
Storage._setPaymentAmount(paymentAmount_);
}
function _trackSponsoredPayment(address payee_, uint256 paymentType_, uint256 paymentAmount_) internal {
// Validate guard is active
if (Storage._getStatus() != Storage._SPONSORED)
revert sponsorShield_unsponsoredPayment();
// Track action
if (Storage._getPayee() != payee_)
revert sponsorShield_unsponsoredPayment();
if (Storage._getPaymentType() != paymentType_)
revert sponsorShield_invalidPaymentType();
if (!Storage._decrementPaymentAmount(paymentAmount_))
revert sponsorShield_insufficientAmount();
}
function _cleanupSponsorShield() internal {
if (Storage._getStatus() == Storage._SPONSORED) {
// Cleanup guard
Storage._setStatus(Storage._NOT_SPONSORED);
Storage._clearPayment();
}
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {
RegistryStorage as Storage,
RegistrarStorage
} from "src/regcontrol/storage/Storage.sol";
import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";
import {Enforcer} from "src/regcontrol/modules/types/Enforcer.sol";
import "src/regcontrol/modules/types/Errors.sol";
/// Contract -----------------------------------------------------------------------------------
contract Registry is AccessManagement, Enforcer {
/// Internal Functions ------------------------------------------------------------------------
function _createRegistration(bytes calldata fqdn_, address registrant_, uint32 controlBitmap_, uint64 duration_)
internal
returns (bytes32 node_, bytes32 tld_)
{
// Validate the registration
bytes memory label_;
(label_, tld_) = _createRegistration__validate(fqdn_, registrant_, duration_);
// Update internal state to track the registration
uint64 expiration_ = uint64(block.timestamp) + uint64(duration_);
(node_) = _createRegistration__private(label_, tld_, registrant_, controlBitmap_, expiration_);
// Emit a RegistrationCreated event
emit RegistrationCreated(node_, tld_, fqdn_, registrant_, controlBitmap_, expiration_);
// ERC721 Event
emit Transfer(address(0x00), registrant_, uint256(node_));
// ERC1155 Event
emit TransferSingle(msg.sender, address(0x00), registrant_, uint256(node_), 1);
// ENS Event
emit NewOwner(tld_, keccak256(label_), registrant_);
emit Transfer(node_, registrant_);
}
function _extendRegistration(bytes32 labelHash_, bytes32 tld_, uint64 duration_) internal {
// Validate the registration duration extension
(bytes32 node_, uint64 newExpiry_) = _extendRegistration__validate(labelHash_, tld_, duration_);
// Update internal state to track the new expiry
_extendRegistration__private(node_, newExpiry_);
// Emit a RegistrationExtended event
emit RegistrationExtended(node_, duration_, newExpiry_);
}
function _transferRegistration(bytes32 node_, address newRegistrant_) internal {
// Validate the transfer
_transferRegistration__validate(node_, newRegistrant_);
// Update internal state to track the transfer
address oldRegistrant_ = _transferRegistration__private(node_, newRegistrant_);
// Emit a RegistrationTransferred event
emit RegistrationTransferred(node_, newRegistrant_, msg.sender);
// ERC721 Event
emit Transfer(oldRegistrant_, newRegistrant_, uint256(node_));
// ERC1155 Event
emit TransferSingle(msg.sender, oldRegistrant_, newRegistrant_, uint256(node_), 1);
// ENS Event
emit Transfer(node_, newRegistrant_);
}
function _burnRegistration(bytes32 node_) internal {
// Validate the registration exits and has no subdomains
_burnRegistration__validate(node_);
// Update internal state to remove the registration
address registrant_ = _burnRegistration__private(node_);
// Emit a RegistrationBurned event
emit RegistrationBurned(node_, msg.sender);
// ERC721 Event
emit Transfer(registrant_, address(0x00), uint256(node_));
// ERC1155 Event
emit TransferSingle(msg.sender, registrant_, address(0x00), uint256(node_), 1);
// ENS Event
emit Transfer(node_, address(0x00));
}
/// Validators --------------------------------------------------------------------------------
function _createRegistration__validate(bytes calldata fqdn_, address registrant_, uint64 duration_)
internal
view
returns (bytes memory label_, bytes32 tld_)
{
bytes32 labelHash_;
uint256 offset_;
// Parse the label from the fqdn
(label_, labelHash_, offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Validate the label
if (!_isValidDomainLabel(label_)) {
revert BaseRegControl_invalidLabel(label_);
}
// Parse the tld from the fqdn
tld_ = BytesUtils.namehash(fqdn_, offset_);
// Validate the tld
if (!_isTLDEnabled(tld_)) {
revert BaseRegControl_invalidTLD(tld_);
}
// Validate the uniqueness of the node
if (!_isSubdomainAvailable(labelHash_, tld_)) {
revert BaseRegControl_subdomainUnavailable(label_, tld_);
}
// Validate the registrant is not the zero address
if (registrant_ == address(0x00)) {
revert BaseRegControl_invalidRegistrant(registrant_);
}
// Validate the duration
if (!_isValidRegistrationDuration(duration_)) {
revert BaseRegControl_invalidDuration(duration_);
}
return (label_, tld_);
}
function _extendRegistration__validate(bytes32 labelHash_, bytes32 tld_, uint64 duration_)
internal
view
returns (bytes32 node_, uint64 newExpiry_)
{
// Calculate the node
node_ = _calculateNode(labelHash_, tld_);
// Validate the node exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the node has not already expired
if (_isNodeExpired(node_)) {
revert BaseRegControl_nodeExpired(node_);
}
// Validate the tld is enabled
if (!_isTLDEnabled(tld_)) {
revert BaseRegControl_invalidTLD(tld_);
}
// TODO: Validate the tld is not locked
// Validate the new expiry
bool valid_;
(valid_, newExpiry_) = _isValidRegistrationDurationExtension(node_, duration_);
if (!valid_) {
revert BaseRegControl_invalidDurationExtension(duration_);
}
return (node_, newExpiry_);
}
function _transferRegistration__validate(bytes32 node_, address newRegistrant_) internal view {
// Validate the node exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the node is transferable (not expired or locked)
if (!_isNodeTransferable(node_)) {
revert BaseRegControl_nodeNotTransferable(node_);
}
// Validate the new registrant is not the zero address
if (newRegistrant_ == address(0x00)) {
revert BaseRegControl_invalidRegistrant(newRegistrant_);
}
}
function _burnRegistration__validate(bytes32 node_) internal view {
// Validate the node exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the node has not already expired
if (_isNodeExpired(node_)) {
revert BaseRegControl_nodeExpired(node_);
}
// Validate the node has no children/subdomains
if (_hasSubdomains(node_)) {
revert BaseRegControl_nodeHasSubdomains(node_);
}
}
/// Private Functions -------------------------------------------------------------------------
function _createRegistration__private(
bytes memory label_,
bytes32 parent_,
address registrant_,
uint32 controlBitmap_,
uint64 expiration_
) private returns (bytes32 node_) {
// Calculate the node
node_ = _calculateNode(keccak256(label_), parent_);
// Initialize the record data
(address owner_,,) = Storage.getRecordData(node_);
if (owner_ == address(0)) {
// Create the new record
Storage.createNewRecord(node_, registrant_, controlBitmap_, expiration_);
// Build a reverse record mapping for the node to the parent
Storage.trackReverseRecord(parent_, label_);
} else {
// Update the record data
Storage.setRecordData(node_, registrant_, controlBitmap_, expiration_);
// Renounce it from the previous owner
Storage.renounceOwnership(node_, registrant_);
}
// Track the ownership
Storage.trackNewOwnership(node_, registrant_);
// Remove approvals
_clearRegistrationApprovals(node_);
}
function _extendRegistration__private(bytes32 node_, uint64 newExpiry_) private {
// Get the current record data
(address registrant_, uint32 controlBitmap_,) = Storage.getRecordData(node_);
// Update the current expiry of the node
Storage.setRecordData(node_, registrant_, controlBitmap_, newExpiry_);
}
function _transferRegistration__private(bytes32 node_, address newRegistrant_) private returns (address) {
// Get the current registrant of the node
(address registrant_, uint32 controlBitmap, uint64 expiry_) = Storage.getRecordData(node_);
// Remove the node from the registrant's enumerable set
Storage.renounceOwnership(node_, registrant_);
// Update the registrant record
Storage.setRecordData(node_, newRegistrant_, controlBitmap, expiry_);
// Track the ownership with the new registrant
Storage.trackNewOwnership(node_, newRegistrant_);
// Remove approvals
_clearRegistrationApprovals(node_);
return registrant_;
}
function _burnRegistration__private(bytes32 node_) private returns (address) {
address registrant_ = _getRegistrant(node_);
// Renounce the ownership of the node
Storage.renounceOwnership(node_, registrant_);
// Remove the reverse record mapping
Storage.untrackReverseRecord(node_);
// Remove the node from the records mapping
Storage.deleteRecord(node_);
// Remove approval
_clearRegistrationApprovals(node_);
// Delete any locks on the domain
RegistrarStorage.setDomainLockData(node_, 0);
return registrant_;
}
/// Helper Functions --------------------------------------------------------------------------
function _isValidDomainLabel(bytes memory label_) internal pure returns (bool) {
// Check if label is empty or exceeds 63 characters
if (label_.length == 0x00 || label_.length > 0x3f) return false;
// Check first and last character for hyphen
if (label_[0] == 0x2d || label_[label_.length - 1] == 0x2d) return false;
// Check if label contains invalid characters
for (uint256 i = 0; i < label_.length; i++) {
bytes1 char_ = label_[i];
// Ensure alphanumeric and lowercase.
// ASCII values: 0-9 => 48-57, a-z => 97-122
// 45 is hyphen ("-")
if (
!(char_ >= 0x30 && char_ <= 0x39) // Check for 0-9
&& !(char_ >= 0x61 && char_ <= 0x7A) // Check for a-z
&& char_ != 0x2d
) {
// Check for hyphen, but we already checked the start and end
return false;
}
}
return true;
}
function _isValidRegistrationDuration(uint64 duration_) internal pure returns (bool) {
return duration_ > 0 && duration_ <= 10 * YEAR;
}
function _isValidRegistrationDurationExtension(bytes32 node_, uint64 durationExtension_)
internal
view
returns (bool valid_, uint64 newExpiry_)
{
// Renewal must be non zero and in years
// The new cumulative duration must be less than 10 years
// Get the current expiry & calculate the new expiry.
(,, newExpiry_) = Storage.getRecordData(node_);
newExpiry_ += durationExtension_;
// Validate the extension and the new expiry.
valid_ = _isValidRegistrationDuration(durationExtension_) && newExpiry_ <= (block.timestamp + 10 * YEAR);
// Return the validity and the new expiration.
return (valid_, newExpiry_);
}
function _isTLDEnabled(bytes32 tld_) internal view returns (bool) {
(bool enabled_) = RegistrarStorage.getTLDData(tld_);
return enabled_;
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
error IndexOutOfBounds(uint256 index, uint256 length);
error NoLabelAtSpecifiedIndex();
error SubstringOverflow();
error JunkAtEndOfName();
error BytesUtils_notFullyQualified();
library BytesUtils {
/*
* @dev Returns the keccak-256 hash of a byte range.
* @param self The byte string to hash.
* @param offset The position to start hashing at.
* @param len The number of bytes to hash.
* @return The hash of the byte range.
*/
function keccak(bytes memory self, uint256 offset, uint256 len) internal pure returns (bytes32 ret) {
if (offset + len > self.length) revert IndexOutOfBounds(offset + len, self.length);
assembly {
ret := keccak256(add(add(self, 32), offset), len)
}
}
/**
* @dev Returns the ENS namehash of a DNS-encoded name.
* @param self The DNS-encoded name to hash.
* @param offset The offset at which to start hashing.
* @return The namehash of the name.
*/
function namehash(bytes memory self, uint256 offset) internal pure returns (bytes32) {
(bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);
if (labelhash == bytes32(0)) {
if (offset != self.length - 1) revert JunkAtEndOfName();
return bytes32(0);
}
return keccak256(abi.encodePacked(namehash(self, newOffset), labelhash));
}
/**
* @dev Returns the keccak-256 hash of a DNS-encoded label, and the offset to the start of the next label.
* @param self The byte string to read a label from.
* @param idx The index to read a label at.
* @return labelhash The hash of the label at the specified index, or 0 if it is the last label.
* @return newIdx The index of the start of the next label.
*/
function readLabel(bytes memory self, uint256 idx) internal pure returns (bytes32 labelhash, uint256 newIdx) {
if (idx >= self.length) revert IndexOutOfBounds(idx, self.length);
uint256 len = uint256(uint8(self[idx]));
if (len > 0) {
labelhash = keccak(self, idx + 1, len);
} else {
labelhash = bytes32(0);
}
newIdx = idx + len + 1;
}
/**
* @dev Qualifies that the host is fully qualified relative to the parent node & returns the ending index of the label.
* @param self The wire-encoded host.
* @param parent The namehash of the parent node.
* @return hostNodes The namehash of all children leading up to the host.
*/
function validateHost(
bytes memory self,
bytes32 parent,
bool qualifyHost
) internal pure returns (bytes32[] memory hostNodes) {
// Calculate all label hashes
(bytes32[] memory labelhashes) = hashParts(self, 0);
// Calculate the namehash
bytes32 node;
bool qualified;
uint256 pos = labelhashes.length;
if (!qualifyHost) {
node = parent;
qualified = true;
hostNodes = new bytes32[](pos);
}
for (; pos > 0; pos--) {
node = keccak256(abi.encodePacked(node, labelhashes[pos - 1]));
if (!qualified) {
if (node == parent) {
qualified = true;
hostNodes = new bytes32[](pos - 1);
}
} else {
// Once we are qualified, we can start storing the host nodes
hostNodes[hostNodes.length - pos] = node;
}
}
// Ensure that the name is fully qualified
if (!qualified) revert BytesUtils_notFullyQualified();
return hostNodes;
}
/**
* @dev Returns the keccak-256 hash of a wire-encoded labeles.
* @param self The wire-encoded host.
* @param idx The index to start reading labels from.
* @return labelhashes The hash of the label from the wire-encoded host.
*/
function hashParts(
bytes memory self,
uint256 idx
) internal pure returns (bytes32[] memory labelhashes) {
// Count the number of labels
uint256 count;
uint256 offset = idx;
while (offset < self.length && self[offset] != 0x00) {
offset += uint256(uint8(self[offset])) + 1;
count++;
}
// Ensure that we consumed the entire input
require(isEnd(self, offset), "hashParts: Junk at end of name");
// Initialize the output array
labelhashes = new bytes32[](count);
// Hash the labels
offset = idx;
for (uint256 i = 0; i < count; i++) {
(labelhashes[i], offset) = readLabel(self, offset);
}
// Return the output
return labelhashes;
}
function isEnd(bytes memory self, uint256 offset) internal pure returns (bool) {
return offset == self.length - 1 && self[offset] == 0x00;
}
function readAndReturnLabel(bytes memory self, uint256 idx)
internal
pure
returns (bytes memory label, bytes32 labelhash, uint256 newIdx)
{
(labelhash, newIdx) = readLabel(self, idx);
if (idx == newIdx) {
revert NoLabelAtSpecifiedIndex();
}
label = substring(self, idx + 1, uint256(uint8(self[idx])));
}
/*
* @dev Copies a substring into a new byte string.
* @param self The byte string to copy from.
* @param offset The offset to start copying at.
* @param len The number of bytes to copy.
*/
function substring(bytes memory self, uint256 offset, uint256 len) internal pure returns (bytes memory) {
if (offset + len > self.length) revert SubstringOverflow();
bytes memory ret = new bytes(len);
uint256 dest;
uint256 src;
assembly {
dest := add(ret, 32)
src := add(add(self, 32), offset)
}
_memcpy(dest, src, len);
return ret;
}
function _memcpy(uint256 dest, uint256 src, uint256 len) private pure {
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
unchecked {
uint256 mask = (256 ** (32 - len)) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
library Datastructures {
/// Registration Datastructures ---------------------------------------------------------------
/// Payment Datastructures --------------------------------------------------------------------
/// @title OrderPayment
/// @notice Represents the details of the payment for an order.
/// @param paymentType The method/type of payment chosen.
/// @param amount The amount of the payment made, stored in the smallest unit (like wei for ETH).
struct OrderPayment {
PaymentType paymentType; // Type of payment (e.g., ETH or USDC)
uint248 amount; // Amount of payment made. Using uint248 can save storage if combined with other small types in future.
}
/// @title PaymentType
/// @notice Enumerated types of accepted payment methods.
enum PaymentType {
UNDEFINED,
USDC,
ETH
}
/// Commitment Datastructures -----------------------------------------------------------------
/// @title InternalCommitment
/// @notice Represents the details of a commitment.
/// @param secret The registration secret being committed to.
/// @param request The duration of the registration.
struct InternalCommitment {
RegistrationRequest request;
RegistrationSecret secret;
bytes32 secretHash_;
}
/// @title RegistrationRequest
/// @notice Represents the details of a registration request.
/// (uint8,uint64,(uint8,uint248),(uint8,uint248))
struct RegistrationRequest {
CommitmentType commitmentType;
uint64 duration;
OrderPayment registrationPayment;
OrderPayment servicePayment;
}
/// @title RegistrationSecret
/// @notice Represents the details of a registration secret.
/// @param registrant The address of the registrant.
/// @param node The namehash-encoded domain name being registered.
/// @param nonce The nonce of the registration secret.
struct RegistrationSecret {
address registrant;
bytes32 node;
bytes32 nonce;
}
/// @title CommitmentType
/// @notice Enumerated types of commitments.
enum CommitmentType {
UNDEFINED,
REGISTRATION__FULL_TOKENIZATION,
RENEWAL,
OFFCHAIN__FULL_TOKENIZATION,
TRANSFER__FULL_TOKENIZATION,
REGISTRATION__TRADER_TOKENIZATION,
OFFCHAIN__TRADER_TOKENIZATION,
TRANSFER__TRADER_TOKENIZATION,
OFFCHAIN_RENEWAL,
OFFCHAIN_RENEWAL__TRADER_TOKENIZATION,
RENEWAL__TRADER_TOKENIZATION,
SERVICE_PAYMENT
}
/// @title Signature
/// @notice
/// (uint64,uint64,uint8,bytes32,bytes32)
struct AuthorizationSignature {
uint64 issuedAt;
uint64 expiresAt;
uint8 v;
bytes32 r;
bytes32 s;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 wad) external;
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function totalSupply() external view returns (uint256);
function approve(address guy, uint256 wad) external returns (bool);
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(address src, address dst, uint256 wad) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import {IERC165Upgradeable as IERC165} from
"openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import {IERC165Upgradeable as IERC165} from
"openzeppelin-contracts-upgradeable/contracts/utils/introspection/IERC165Upgradeable.sol";
interface IERC1155 is IERC165 {
// /**
// * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
// */
// event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
// /**
// * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
// * transfers.
// */
// event TransferBatch(
// address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values
// );
// /**
// * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
// * `approved`.
// */
// event ApprovalForAll(address indexed account, address indexed operator, bool approved);
// /**
// * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
// *
// * If an {URI} event was emitted for `id`, the standard
// * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
// * returned by {IERC1155MetadataURI-uri}.
// */
// event URI(string value, uint256 indexed id);
// /**
// * @dev Returns the amount of tokens of token type `id` owned by `account`.
// *
// * Requirements:
// *
// * - `account` cannot be the zero address.
// */
function balanceOf(address account, uint256 id) external view returns (uint256);
// /**
// * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
// *
// * Requirements:
// *
// * - `accounts` and `ids` must have the same length.
// */
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
// /**
// * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
// *
// * Emits a {TransferSingle} event.
// *
// * Requirements:
// *
// * - `to` cannot be the zero address.
// * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
// * - `from` must have a balance of tokens of type `id` of at least `amount`.
// * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
// * acceptance magic value.
// */
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
// /**
// * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
// *
// * Emits a {TransferBatch} event.
// *
// * Requirements:
// *
// * - `ids` and `amounts` must have the same length.
// * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
// * acceptance magic value.
// */
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data)
external
returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";
import {IERC721, IERC721Receiver} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI, IERC1155Receiver} from "src/regcontrol/interfaces/tokens/IERC1155.sol";
import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";
import {HybridMetadataService} from "src/regcontrol/modules/types/metadata/HybridMetadataService.sol";
import {Registry} from "src/regcontrol/modules/types/Registry.sol";
import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";
import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";
/// Errors -------------------------------------------------------------------------------------
error CustomToken_ArrayLengthMismatch();
error CustomToken_InsufficientBalance();
error CustomToken_SenderNotOwnerOrOperator();
error CustomToken_ZeroAddress();
error CustomToken_InvalidAddress();
error CustomToken_ERC721ReceiverRejectedTokens();
error CustomToken_ERC1155ReceiverRejectedTokens();
error CustomToken_NotTokenReceiver();
abstract contract CustomToken is
ICustomToken,
AccessManagement,
Registry,
HybridMetadataService
{
/// Libraries ---------------------------------------------------------------------------------
using AddressUpgradeable for address;
/// Accessor Functions ------------------------------------------------------------------------
function _getFQDN(bytes32 node_) internal view override returns (string memory fqdn_, bytes32 tld_) {
if (node_ == bytes32(0x00)) {
return ("", bytes32(0x00));
}
(fqdn_, tld_) = _getFQDN(_getParent(node_));
if (tld_ == bytes32(0x00)) {
tld_ = _getParent(node_);
}
if (bytes(fqdn_).length == 0) {
fqdn_ = string(_getLabel(node_));
} else {
fqdn_ = string(abi.encodePacked(_getLabel(node_), ".", fqdn_));
}
return (fqdn_, tld_);
}
/// Approval Functions ------------------------------------------------------------------------
function approve(address to, uint256 tokenId) external override {
// Validate caller has permission to approve the operator
if (!_permissionCheck_registration(bytes32(tokenId), msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
revert CustomToken_SenderNotOwnerOrOperator();
}
// Function uses msg.sender for account indexed operations
_setRegistrationApproval(bytes32(tokenId), to);
}
function getApproved(uint256 tokenId) external view returns (address operator) {
if ((operator = ownerOf(tokenId)) == address(0)) {
revert CustomToken_ZeroAddress();
}
return _getApprovedRegistrationOperator(bytes32(tokenId));
}
/// ERC721 ------------------------------------------------------------------------------------
function totalSupply() external view returns (uint256) {
return _getRecordCount();
}
function ownerOf(uint256 tokenId) public view returns (address) {
return _getRegistrant(bytes32(tokenId));
}
function balanceOf(address owner_) external view returns (uint256) {
if (owner_ == address(0)) {
revert CustomToken_ZeroAddress();
}
return _getDomainNameOwnershipCount(owner_);
}
function transferFrom(address from_, address to_, uint256 tokenId_) external override {
// Run access control check
_transfer__validate(from_, to_, tokenId_, 1);
// Execute the transfer
_transfer__execute(from_, to_, tokenId_);
}
function safeTransferFrom(address from_, address to_, uint256 tokenId_, bytes calldata data_) external override {
// Run access control check
_transfer__validate(from_, to_, tokenId_, 1);
// Execute the transfer
_transfer__execute(from_, to_, tokenId_);
// Run the callback
_transfer__callback(from_, to_, tokenId_, data_);
}
function safeTransferFrom(address from_, address to_, uint256 tokenId_) external override {
// Run access control check
_transfer__validate(from_, to_, tokenId_, 1);
// Execute the transfer
_transfer__execute(from_, to_, tokenId_);
// Run the callback
_transfer__callback(from_, to_, tokenId_, "");
}
/// ERC1155 Methods ---------------------------------------------------------------------------
/// @dev See {IERC1155-balanceOf}.
function balanceOf(address account_, uint256 id_) public view virtual override returns (uint256) {
if (account_ == address(0)) {
revert CustomToken_ZeroAddress();
}
return account_ == ownerOf(id_) ? 1 : 0;
}
/// @dev See {IERC1155-balanceOfBatch}.
function balanceOfBatch(address[] calldata accounts_, uint256[] calldata ids_)
public
view
virtual
override
returns (uint256[] memory balances_)
{
if (accounts_.length != ids_.length) {
revert CustomToken_ArrayLengthMismatch();
}
balances_ = new uint256[](accounts_.length);
for (uint256 i = 0; i < accounts_.length; ++i) {
balances_[i] = balanceOf(accounts_[i], ids_[i]);
}
}
/// @dev See {IERC1155-safeTransferFrom}.
function safeTransferFrom(address from_, address to_, uint256 id_, uint256 amount_, bytes calldata data_)
public
virtual
override
{
_transfer__validate(from_, to_, id_, amount_);
_transfer__execute(from_, to_, id_);
_transfer__callback(from_, to_, id_, data_);
}
/// @dev See {IERC1155-safeBatchTransferFrom_}.
function safeBatchTransferFrom(
address from_,
address to_,
uint256[] calldata ids_,
uint256[] calldata amounts_,
bytes calldata data_
) public virtual override {
if (ids_.length != amounts_.length) {
revert CustomToken_ArrayLengthMismatch();
}
uint256 index_ = 0;
for (; index_ < ids_.length; ++index_) {
uint256 id_ = ids_[index_];
// Validate the transfer
_transfer__validate(from_, to_, id_, amounts_[index_]);
// Execute the transfer
_transfer__execute(from_, to_, id_);
}
// emit TransferBatch(msg.sender, from_, to_, ids_, amounts_);
_doSafeBatchTransferAcceptanceCheck(msg.sender, from_, to_, ids_, amounts_, data_);
}
/// Transfer Functions ------------------------------------------------------------------------
function _transfer__validate(address from_, address to_, uint256 id_, uint256 amount_) internal view virtual {
if (from_ == address(0) || to_ == address(0)) {
revert CustomToken_ZeroAddress();
}
if (amount_ != 1) {
revert CustomToken_ArrayLengthMismatch();
}
if (from_ != _getRegistrant(bytes32(id_))) {
revert CustomToken_InsufficientBalance();
}
// Caller is node operator
if(!_permissionCheck_registration(bytes32(id_), msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
revert CustomToken_SenderNotOwnerOrOperator();
}
}
function _transfer__execute(address from_, address to_, uint256 id_) internal {
if (from_ == to_) {
return;
}
// TODO: Determine if other checks are needed
_transferRegistration(bytes32(id_), to_);
}
/// @dev internal helper function for transfering a node
function _transfer__callback(address from_, address to_, uint256 id_, bytes memory data_) internal {
_doSafeTransferAcceptanceCheck(msg.sender, from_, to_, id_, 1, data_);
}
/// Internal Helper Functions =================================================================
/// @dev internal helper function for performing a post transfer check on non-EOA receivers.
function _doSafeTransferAcceptanceCheck(
address operator_,
address from_,
address to_,
uint256 id_,
uint256 amount_,
bytes memory data_
) private {
if (to_.isContract()) {
/* ERC1155 handling */
(bool success1, bytes memory data1) = to_.call(abi.encodeCall(IERC1155Receiver.onERC1155Received, (operator_, from_, id_, amount_, data_)));
if (success1 && data1.length != 0) { // success AND has return data -> check return data, expect it to have 4 bytes
if (abi.decode(data1, (bytes4)) != IERC1155Receiver.onERC1155Received.selector) {
revert CustomToken_ERC1155ReceiverRejectedTokens();
}
} else { // failure OR no return data: fallback OR low-level failure (without error message) OR high-level error message
/* ERC721 handling */
(bool success2, bytes memory data2) = to_.call(abi.encodeCall(IERC721Receiver.onERC721Received, (operator_, from_, id_, data_)));
if (data2.length != 0) { // has return data
if (success2) { // success -> check return data, expect it to have 4 bytes
if (abi.decode(data2, (bytes4)) != IERC721Receiver.onERC721Received.selector) {
revert CustomToken_ERC721ReceiverRejectedTokens();
}
}
else { // failure -> forward error message
/// @solidity memory-safe-assembly
assembly {
revert(add(32, data2), mload(data2))
}
}
} else { // no return data: failure without error message -> forward previous error message
if (data1.length != 0) {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, data1), mload(data1))
}
}
else {
revert CustomToken_NotTokenReceiver();
}
}
}
}
}
/// @dev internal helper function for performing a post batch-transfer check on non-EOA receivers.
function _doSafeBatchTransferAcceptanceCheck(
address operator_,
address from,
address to_,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data_
) private {
if (to_.isContract()) {
try IERC1155Receiver(to_).onERC1155BatchReceived(operator_, from, ids, amounts, data_) returns (
bytes4 response
) {
if (response != IERC1155Receiver(to_).onERC1155BatchReceived.selector) {
revert CustomToken_ERC1155ReceiverRejectedTokens();
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert CustomToken_NotTokenReceiver();
}
}
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";
import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";
import {AccessManagement} from "src/regcontrol/modules/types/AccessManagement.sol";
import {Registry} from "src/regcontrol/modules/types/Registry.sol";
import {RegControlStorage} from "src/regcontrol/storage/Storage.sol";
/// Errors -------------------------------------------------------------------------------------
error DomainController_accessDenied();
error DomainController_notSupported();
abstract contract CustomENS is
IENS,
AccessManagement,
Registry
{
/// Constants ---------------------------------------------------------------------------------
uint64 public constant DEFAULT_TTL = 3600;
/// User Functions ----------------------------------------------------------------------------
function transfer(bytes32 node_, address recipient_) external {
// Run access control check
if (!_permissionCheck_registration(node_, msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
revert DomainController_accessDenied();
}
// Transfer
_transferRegistration(node_, recipient_);
}
/// Approval Functions ------------------------------------------------------------------------
function setRecord(
bytes32 node,
address owner,
address resolver,
uint64 ttl
) external override {
revert DomainController_notSupported();
}
function setSubnodeRecord(
bytes32 node,
bytes32 label,
address owner,
address resolver,
uint64 ttl
) external override {
revert DomainController_notSupported();
}
function setSubnodeOwner(
bytes32 node,
bytes32 label,
address owner
) external override returns (bytes32) {
revert DomainController_notSupported();
}
function setResolver(bytes32 node, address resolver) external override {
revert DomainController_notSupported();
}
function setOwner(bytes32 node_, address owner_) external override {
// Run access control check
if (!_permissionCheck_registration(node_, msg.sender, IIAM.IAMRole.ADMIN, IIAM.IAMPermission.MANAGE)) {
revert DomainController_accessDenied();
}
// Transfer
_transferRegistration(node_, owner_);
}
function setTTL(bytes32 node, uint64 ttl) external override {
revert DomainController_notSupported();
}
/// Accessor Functions ------------------------------------------------------------------------
function owner(bytes32 node) public view override returns (address) {
return _getRegistrant(node);
}
function resolver(bytes32 node) external view override returns (address) {
return _resolver(node);
}
function ttl(bytes32 node) external view override returns (uint64) {
return DEFAULT_TTL;
}
function recordExists(bytes32 node) external view override returns (bool) {
return !_isNodeAvailable(node);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {IENS} from "src/regcontrol/interfaces/tokens/IENS.sol";
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";
interface IDomainController is
IENS,
ICustomToken
{
function setApprovalForAll(address operator_, bool approved_) external override(IENS, ICustomToken);
function isApprovedForAll(address account_, address operator_)
external
view
override(IENS, ICustomToken)
returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IENS {
// /// Events ---------------------------------------------------------------------------------
// // 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
// );
/// Management Functions ----------------------------------------------------------------------
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;
/// Accessor Functions ------------------------------------------------------------------------
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);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {IERC721, IERC721Metadata} from "src/regcontrol/interfaces/tokens/IERC721.sol";
import {IERC1155, IERC1155MetadataURI} from "src/regcontrol/interfaces/tokens/IERC1155.sol";
interface ICustomToken is IERC721Metadata, IERC1155MetadataURI {
/// Shared Function Overrides -----------------------------------------------------------------
function setApprovalForAll(address operator_, bool approved_) external override(IERC721, IERC1155);
function isApprovedForAll(address account_, address operator_)
external
view
override(IERC721, IERC1155)
returns (bool);
/// ERC-1155 Compliance -----------------------------------------------------------------------
function uri(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// Internal References ---------------------------------------------------------------------------
import {IPaymentProcessor} from "src/regcontrol/interfaces/IPaymentProcessor.sol";
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
/// Errors -------------------------------------------------------------------------------------
error PaymentModule_notSupported();
abstract contract AbstractPaymentProcessor is IPaymentProcessor {
/// Internal Payment Functions ================================================================
function _validateRegistrationPayment(
Datastructures.OrderPayment memory payment_,
bytes32 tld_, uint64 duration_
) internal view virtual;
function _validatePayment(
Datastructures.OrderPayment memory payment_,
bool zeroPayments_
) internal pure virtual;
function _handlePayment(Datastructures.OrderPayment memory payment_, bool isCommitment_) internal virtual;
function _handlePayout(Datastructures.OrderPayment memory payment_, address recipient_) internal virtual;
function _getPayoutAddress(bytes32 tld_) internal virtual returns (address);
// function _handleGaslessApproval(
// Datastructures.PaymentType payment_,
// address from_,
// address sponsor_,
// uint256 permitAmount_,
// uint256 permitFee_,
// uint256 deadline_,
// bytes memory permitSig_
// ) internal virtual;
/// Accessor Functions ------------------------------------------------------------------------
// function rentPrice(
// string memory label_,
// bytes32 tld_,
// uint256 duration_,
// Datastructures.PaymentType paymentType_
// ) external view returns (uint256 amount_) {
// revert PaymentModule_notSupported();
// }
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IRegistrarController {
/// Registration Functions --------------------------------------------------------------------
function registerTLD(bytes calldata tld_) external;
function setTLDMetadata(bytes32 tld_, string calldata baseUrl_, string calldata description_) external;
// TODO: Add updateTLD and disableTLD functions
/// Accessor Functions ------------------------------------------------------------------------
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {AddressUpgradeable} from "openzeppelin-upgradeable/utils/AddressUpgradeable.sol";
import {IWETH} from "src/utils/interfaces/IWETH.sol";
/// Multicall ----------------------------------------------------------------------------------
interface IMulticall {
/// @dev Receives and executes a batch of function calls on this contract. Payable. All ETH
/// paid via msg.value is wrapped to WETH and used to execute the function calls. Any
/// remaining WETH is returned to the sender.
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";
library CommitmentStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__COMMITMENT_STORAGE__V1 = keccak256("3dns.reg_control.commitment.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// @dev Struct used to define a payment object...
struct RegistrationCommitment {
// 32 Bytes Packed Data
// | 32 bits | address - 160 bits | uint64 - 64 bits |
// | ... | Owner Address | Expiration (unix seconds) |
bytes32 data;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the commitment store.
struct Layout {
/// @param commitments Mapping of commitment hash to commitment data.
mapping (bytes32 => RegistrationCommitment) commitments;
uint64 commitmentHalfLife;
uint64 signatureHalfLife;
uint64 transferCommitmentHalfLife;
/// @param domainTransferFlags Mapping of pending transfers for a user.
mapping (address => mapping (bytes32 => uint72)) domainTransferFlags;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__COMMITMENT_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize() internal {
layout().commitmentHalfLife = 90 minutes;
layout().transferCommitmentHalfLife = 30 minutes;
layout().signatureHalfLife = 5 minutes;
}
/// Shared Helper Functions -------------------------------------------------------------------
function setCommitmentData(bytes32 commitmentHash_, address committer_, uint64 revokableAt_) internal {
bytes32 commitmentData_;
assembly {
commitmentData_ := shl(64, committer_)
commitmentData_ := or(commitmentData_, revokableAt_)
}
layout().commitments[commitmentHash_].data = commitmentData_;
}
function getCommitmentData(bytes32 commitmentHash_) internal view returns (address committer_, uint64 revokableAt_) {
bytes32 commitmentData_ = layout().commitments[commitmentHash_].data;
assembly {
committer_ := shr(64, commitmentData_)
revokableAt_ := commitmentData_
}
}
function deleteCommitment(bytes32 commitmentHash_) internal {
delete layout().commitments[commitmentHash_];
}
function setDomainTransferFlag(address registrant_, bytes32 commitmentHash_, uint64 duration_, bool isTrader_) internal {
layout().domainTransferFlags[registrant_][commitmentHash_] = duration_ | (isTrader_ ? 1 << 64 : 0);
}
function hasDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal view returns (bool) {
(uint64 duration_, ) = getDomainTransferFlag(registrant_, commitmentHash_);
return duration_ > 0;
}
function getDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal view returns (uint64, bool) {
uint64 flag = uint64(layout().domainTransferFlags[registrant_][commitmentHash_]);
bool isTrader = layout().domainTransferFlags[registrant_][commitmentHash_] & (1 << 64) > 0;
return (flag, isTrader);
}
function deleteDomainTransferFlag(address registrant_, bytes32 commitmentHash_) internal {
delete layout().domainTransferFlags[registrant_][commitmentHash_];
}
/// Accessor Functions ------------------------------------------------------------------------
function COMMITMENT_HALF_LIFE() internal view returns (uint64) {
return layout().commitmentHalfLife;
}
function MAX_SIG_HALF_LIFE() internal view returns (uint64) {
return layout().signatureHalfLife;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {IERC20Upgradeable as IERC20} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";
library PaymentStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__PAYMENT_STORAGE__V1 = keccak256("3dns.reg_control.payment.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// @dev Struct used to define a payment object...
struct Payment {
// 32 Bytes Packed Data
// | address - 160 bits | uint32 - 32 bits | uint64 - 64 bits |
// | Owner Address | Control Bitmap | Expiration (unix seconds) |
bytes32 data;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
/// @param payments Mapping of subdomain payment rules from a corresponding node.
mapping (bytes32 => Payment) payments;
// Supported Payment Types
IERC20 usdc;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__PAYMENT_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize(IERC20 _usdc) internal {
setUSDCTokenAddress(_usdc);
}
/// Shared Helper Functions -------------------------------------------------------------------
function setUSDCTokenAddress(IERC20 usdc) internal {
layout().usdc = IERC20(usdc);
}
/// Accessor Functions ------------------------------------------------------------------------
function ERC20_USDC_ADDRESS() internal view returns (IERC20) {
return layout().usdc;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
library RebateIssuerStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__REBATE_ISSUER_STORAGE__V1 = keccak256("3dns.reg_control.rebate_issuer.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// @dev Struct used to define a payment object...
struct Rebate {
uint256 oustanding;
uint256 claimed;
uint32[] indexes;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the rebate issuer.
struct Layout {
/// @param rebates Mapping of address to rebate.
mapping (address => Rebate) rebates;
uint32 domains;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__REBATE_ISSUER_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// Shared Helper Functions -------------------------------------------------------------------
///
function getRebate(address registrant_) internal view returns (Rebate storage rebate) {
return layout().rebates[registrant_];
}
function incrementOutstandingRebate(address registrant_, uint256 amount) internal {
Rebate storage rebate = getRebate(registrant_);
rebate.oustanding += amount;
}
function addIndex(address registrant_) internal {
Rebate storage rebate = getRebate(registrant_);
rebate.indexes.push(uint32(rebate.indexes.length + 1));
}
function resetOutstandingRebate(address registrant_) internal {
Rebate storage rebate = getRebate(registrant_);
rebate.oustanding = 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {EnumerableSetUpgradeable} from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";
library RegistryStorage {
// Libraries -------------------------------------------------------------------------------
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using LeadingHashStorage for LeadingHashStorage.LHBytes;
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the registry state
bytes32 public constant THREE_DNS__REGISTRY_STORAGE__V1 = keccak256("3dns.reg_control.registry.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// @dev Struct used to define a record, the base notion of ownership for a zone (primary/apex domain name).
struct Record {
// 32 Bytes Packed Data
// | address - 160 bits | uint32 - 32 bits | uint64 - 64 bits |
// | Owner Address | Control Bitmap | Expiration (unix seconds) |
bytes32 data;
// An enumerable set of all subdomains
EnumerableSetUpgradeable.Bytes32Set children;
}
/// @dev Mapping of child node to its parent node & label. keccak256(parent, keccak256(label)) <=> node
struct ReverseRecord {
// The parent node
bytes32 parent;
// The label
LeadingHashStorage.LHBytes label;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
/// @param records Mapping of zone (notioned as node) to its record.
mapping(bytes32 => Record) records;
uint256 recordCount;
/// @param reverseRecords Mapping of child node to its parent node. It also stores the label.
mapping(bytes32 => ReverseRecord) reverseRecords;
/// @param ownershipEnumerations Mapping of address (owner) to an enumerable set of owned
/// zones (notioned as node).
mapping(address => EnumerableSetUpgradeable.Bytes32Set) ownershipEnumerations;
/// @param operators Mapping of owner to an enumerable set of authorized operators.
mapping(address => EnumerableSetUpgradeable.AddressSet) accountOperators;
/// @param approvals Mapping of registration to an approved operator
mapping(bytes32 => address) registrationOperatorApprovals;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__REGISTRY_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// Shared Helper Functions -------------------------------------------------------------------
function recordCount() internal view returns (uint256) {
return layout().recordCount;
}
/// Ownership State Actions ///
function trackNewOwnership(bytes32 node, address registrant) internal {
return _trackNewOwnership(layout().ownershipEnumerations[registrant], node);
}
function renounceOwnership(bytes32 node, address registrant) internal {
return _renounceOwnership(layout().ownershipEnumerations[registrant], node);
}
function getOwnershipCount(address registrant) internal view returns (uint256) {
return _getOwnershipCount(layout().ownershipEnumerations[registrant]);
}
/// Operator State Actions ///
// Registrant => Account Operator Approval (can manage all of the users domains)
function addAccountOperatorApproval(address registrant, address operator) internal {
return _registerOperator(
layout().accountOperators[registrant],
operator
);
}
function removeAccountOperatorApproval(address registrant, address operator) internal {
return _removeOperator(
layout().accountOperators[registrant],
operator
);
}
function isApprovedAccountOperator(address registrant, address operator) internal view returns (bool) {
return _isApprovedAccountOperator(
layout().accountOperators[registrant],
operator
);
}
// Registration => Operator Approval
function approveRegistrationOperator(bytes32 node, address addr) internal {
layout().registrationOperatorApprovals[node] = addr;
}
function removeApprovedRegistrationOperator(bytes32 node) internal {
delete layout().registrationOperatorApprovals[node];
}
function getApprovedRegistrationOperator(bytes32 node) internal view returns (address) {
return layout().registrationOperatorApprovals[node];
}
/// Record State Actions ///
function createNewRecord(bytes32 node, address owner, uint32 controlBitmap, uint64 expiration) internal {
// Increment the record count
layout().recordCount++;
// Set the record data
_setRecordData(layout().records[node], owner, controlBitmap, expiration);
}
function setRecordData(bytes32 node, address owner, uint32 controlBitmap, uint64 expiration) internal {
_setRecordData(layout().records[node], owner, controlBitmap, expiration);
}
function deleteRecord(bytes32 node) internal {
// Revert if the record has children
if (recordHasChildren(node)) revert();
// Decrement the record count
layout().recordCount--;
// Delete the record
delete layout().records[node];
}
/// Reverse Record State Actions ///
function trackReverseRecord(bytes32 parent, bytes memory label) internal {
// Calculate the node from the parent and label
bytes32 node_ = keccak256(abi.encodePacked(parent, keccak256(label)));
// Register the reverse record
_addReverseRecord(node_, parent, label);
}
function untrackReverseRecord(bytes32 node) internal {
// Delete the reverse record & mapping
_removeReverseRecord(node);
}
function getParent_reverseRecord(bytes32 node) internal view returns (bytes32) {
return layout().reverseRecords[node].parent;
}
function getLabel_reverseRecord(bytes32 node) internal view returns (bytes memory) {
return layout().reverseRecords[node].label.get();
}
/// Record Specific Functions =================================================================
// Data Helper Functions
function getRecord(bytes32 node) internal view returns (Record storage) {
return layout().records[node];
}
function getRecordData(bytes32 node)
internal
view
returns (address owner, uint32 controlBitmap, uint64 expiration)
{
return _getRecordData(layout().records[node]);
}
function getRecordChildren(bytes32 node) internal view returns (EnumerableSetUpgradeable.Bytes32Set storage) {
return _getRecordChildren(layout().records[node]);
}
function recordHasChildren(bytes32 node) internal view returns (bool) {
return _recordHasChildren(layout().records[node]);
}
/// Children Helper Functions
function addChild(bytes32 node, bytes32 child) internal {
return _addChild(layout().records[node], child);
}
function removeChild(bytes32 node, bytes32 child) internal {
return _removeChild(layout().records[node], child);
}
function getChildAtIndex(bytes32 node, uint256 index) internal view returns (bytes32) {
return _getChildAtIndex(layout().records[node], index);
}
function containsChild(bytes32 node, bytes32 child) internal view returns (bool) {
return _containsChild(layout().records[node], child);
}
/// Record Storage Functions ///
function _getRecordData(Record storage r_)
private
view
returns (address owner, uint32 controlBitmap, uint64 expiration)
{
bytes32 data_ = r_.data;
assembly {
owner := shr(96, data_)
controlBitmap := shr(64, data_)
expiration := data_
}
}
function _setRecordData(Record storage r_, address owner_, uint32 controlBitmap_, uint64 expiration_) private {
// bytes32 data_;
// assembly {
// // Zero out any extra bits by shifting right then left
// let ownerMasked := shl(96, shr(96, owner_))
// let controlBitmapMasked := shl(64, shr(192, controlBitmap_))
// let expirationMasked := shl(0, shr(192, expiration_))
// // Combine the masked and shifted values
// data_ := or(or(ownerMasked, controlBitmapMasked), expirationMasked)
// data_ := or(or(shl(96, owner_), shl(64, controlBitmap_)), expiration_)
// }
// r_.data = data_;
r_.data = bytes32(uint256(uint160(owner_))) << 96 | (bytes32(uint256(controlBitmap_)) << 64)
| bytes32(uint256(expiration_));
}
function _getRecordChildren(Record storage r_) private view returns (EnumerableSetUpgradeable.Bytes32Set storage) {
return r_.children;
}
function _recordHasChildren(Record storage r_) private view returns (bool) {
return r_.children.length() > 0;
}
/// Children Storage Functions ///
function _addChild(Record storage r_, bytes32 child) private {
r_.children.add(child);
}
function _removeChild(Record storage r_, bytes32 child) private {
r_.children.remove(child);
}
function _getChildAtIndex(Record storage r_, uint256 index) private view returns (bytes32) {
return r_.children.at(index);
}
function _containsChild(Record storage r_, bytes32 child) private view returns (bool) {
return r_.children.contains(child);
}
/// Ownership Enumeration Storage Functions ///
function _trackNewOwnership(EnumerableSetUpgradeable.Bytes32Set storage s_, bytes32 node_) private {
s_.add(node_);
}
function _renounceOwnership(EnumerableSetUpgradeable.Bytes32Set storage s_, bytes32 node_) private {
s_.remove(node_);
}
function _getOwnershipCount(EnumerableSetUpgradeable.Bytes32Set storage s_) private view returns (uint256) {
return s_.length();
}
/// Operator Storage Functions ///
function _registerOperator(EnumerableSetUpgradeable.AddressSet storage s_, address registrant_) private {
s_.add(registrant_);
}
function _removeOperator(EnumerableSetUpgradeable.AddressSet storage s_, address registrant_) private {
s_.remove(registrant_);
}
function _isApprovedAccountOperator(EnumerableSetUpgradeable.AddressSet storage s_, address operator_)
private
view
returns (bool)
{
return s_.contains(operator_);
}
/// Reverse Record Storage Functions ///
function _addReverseRecord(bytes32 node, bytes32 parent, bytes memory label) private {
// Register node as child of parent
addChild(parent, node);
// Set the reverse record
_setReverseRecord(layout().reverseRecords[node], parent, label);
}
function _removeReverseRecord(bytes32 node) private {
// Remove node as child of parent
removeChild(layout().reverseRecords[node].parent, node);
// Delete the reverse record
delete layout().reverseRecords[node];
}
function _setReverseRecord(ReverseRecord storage rr_, bytes32 parent, bytes memory label) private {
rr_.parent = parent;
rr_.label.set(label);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
library RegistrarStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the registry state
bytes32 public constant THREE_DNS__REGISTRAR_STORAGE__V1 = keccak256("3dns.reg_control.registrar.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// @dev Struct used to define a record, the base notion of ownership for a zone (primary/apex domain name).
struct TopLevelDomain {
// 32 Bytes Packed Data
// | address | uint64 | bytes4 |
// | x[20] | x[8] | x[3] | Enabled Flag |
// | IPremium | Base Price | Accessory Data + Enabled Flag |
bytes32 data;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
/// @param tlds Mapping of node to TopLevelDomain definition.
mapping(bytes32 => TopLevelDomain) tlds;
/// @param domainLocks Mapping of domain to 32 byte slot
/// | uint192 | uint64 |
/// | ... | settlementTimestamp |
mapping(bytes32 => bytes32) domainLocks;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__REGISTRAR_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// State Management Functions ----------------------------------------------------------------
/// TLD Actions ///
function registerTLD(bytes32 tld) internal {
bytes32 data_ = bytes32(uint256(1));
return _registerTLD(layout().tlds[tld], data_);
}
function getTLDData(bytes32 tld) internal view returns (bool enabled) {
return _getTLDData(layout().tlds[tld]);
}
function disableTLD(bytes32 tld) internal {
return _disableTLD(layout().tlds[tld]);
}
/// DomainLocks Actions ///
function getDomainLockData(bytes32 node_) internal view returns (uint64 settlementTimestamp) {
return _getDomainLockData(layout().domainLocks[node_]);
}
function setDomainLockData(bytes32 node_, uint64 settlementTimestamp) internal {
_setDomainLockData(node_, settlementTimestamp);
}
/// Attribute Specific Helper Functions -------------------------------------------------------
/// TLD Actions ///
function _registerTLD(TopLevelDomain storage tld_, bytes32 data_) private {
tld_.data = data_;
}
function _getTLDData(TopLevelDomain storage tld_) private view returns (bool enabled_) {
bytes32 data_ = tld_.data;
assembly {
enabled_ := shr(7, shl(255, data_))
}
return enabled_;
}
function _disableTLD(TopLevelDomain storage tld_) private {
tld_.data = tld_.data & ~bytes32(uint256(1));
}
/// DomainLocks Actions ///
function _getDomainLockData(bytes32 domainLock_) private pure returns (uint64 settlementTimestamp) {
assembly {
settlementTimestamp := shr(192, domainLock_)
}
}
function _setDomainLockData(bytes32 node_, uint64 settlementTimestamp_) private {
bytes32 data_;
assembly {
data_ := shl(192, settlementTimestamp_)
}
layout().domainLocks[node_] = data_;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import { EnumerableSetUpgradeable } from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";
library RegControlStorage {
// Libraries ----------------------------------------------------------------------------------
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.Bytes32Set;
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
using LeadingHashStorage for LeadingHashStorage.LHBytes;
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the registry state
bytes32 public constant THREE_DNS__REG_CONTROL_CORE_STORAGE__V1 = keccak256("3dns.reg_control.core.v1.state");
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the core 3dns registry controller.
struct Layout {
/// @dev default & primary resolver for all nodes.
address primaryResolver;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__REG_CONTROL_CORE_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// State Management Functions ----------------------------------------------------------------
function primaryResolver() internal view returns (address) {
return layout().primaryResolver;
}
function setPrimaryResolver(address resolver_) internal {
if (address(resolver_) == address(0))
revert();
layout().primaryResolver = resolver_;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import { LeadingHashStorage } from "src/utils/storage/LeadingHashStorage.sol";
library MetadataStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__BASIC_METADATA_STORAGE__V1 = keccak256("3dns.nft.metadata.basic.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns token metadata.
struct Layout {
string baseUri;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__BASIC_METADATA_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize(string memory _baseUri) internal {
layout().baseUri = _baseUri;
}
/// Shared Helper Functions -------------------------------------------------------------------
/// Accessor Functions ------------------------------------------------------------------------
function baseURI() internal view returns (string memory) {
return layout().baseUri;
}
function setBaseURI(string memory _baseUri) internal {
layout().baseUri = _baseUri;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";
library HybridMetadataStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__HYBRID_METADATA_STORAGE__V1 = keccak256("3dns.nft.metadata.hybrid.v1.state");
/// Datastructures ----------------------------------------------------------------------------
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns token metadata.
struct Layout {
mapping(bytes32 => string) baseUrl;
mapping(bytes32 => string) description;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__HYBRID_METADATA_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// Shared Helper Functions -------------------------------------------------------------------
function name() internal pure returns (string memory) {
return "3DNS Powered Domain Name";
}
function symbol() internal pure returns (string memory) {
return "3DNS";
}
function setMetadata(bytes32 tld_, string memory baseUrl_, string memory description_) internal {
layout().baseUrl[tld_] = baseUrl_;
layout().description[tld_] = description_;
}
function getMetadata(bytes32 tld_) internal view returns (string memory baseUrl_, string memory description_) {
baseUrl_ = layout().baseUrl[tld_];
description_ = layout().description[tld_];
}
/// Accessor Functions ------------------------------------------------------------------------
function baseUrl(bytes32 tld_) internal view returns (string memory resp) {
resp = layout().baseUrl[tld_];
if (bytes(resp).length == 0) {
resp = layout().baseUrl[bytes32(0x00)];
}
}
function description(bytes32 tld_) internal view returns (string memory resp) {
resp = layout().description[tld_];
if (bytes(resp).length == 0) {
resp = layout().description[bytes32(0x00)];
}
}
/// Bytes32 encoding --------------------------------------------------------------------------
function bytes32ToHexString(bytes32 data_) internal pure returns (string memory hex_) {
bytes memory byteArray = new bytes(64);
for (uint256 i = 0; i < 32; i++) {
bytes1 b = data_[i];
bytes1 hi = bytes1(uint8(b) / 16);
bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
byteArray[i * 2] = _char(hi);
byteArray[i * 2 + 1] = _char(lo);
}
return string(byteArray);
}
function _char(bytes1 b_) private pure returns (bytes1 c) {
if (uint8(b_) < 10) return bytes1(uint8(b_) + 0x30);
else return bytes1(uint8(b_) + 0x57);
}
/// Base64 encoding ---------------------------------------------------------------------------
string private constant _B64_CHARACTER_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function base64(bytes memory data_) internal pure returns (string memory) {
if (data_.length == 0) return "";
// load the table into memory
string memory table = _B64_CHARACTER_TABLE;
// multiply by 4/3 rounded up
uint256 encodedLen = 4 * ((data_.length + 2) / 3);
// add some extra buffer at the end required for the writing
string memory result_ = new string(encodedLen + 32);
assembly {
// set the actual output length
mstore(result_, encodedLen)
// prepare the lookup table
let tablePtr := add(table, 1)
// input ptr
let dataPtr := data_
let endPtr := add(dataPtr, mload(data_))
// result ptr, jump over length
let resultPtr := add(result_, 32)
// run over the input, 3 bytes at a time
for {} lt(dataPtr, endPtr) {} {
dataPtr := add(dataPtr, 3)
// read 3 bytes
let input := mload(dataPtr)
// write 4 characters
mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(18, input), 0x3F)))))
resultPtr := add(resultPtr, 1)
mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(12, input), 0x3F)))))
resultPtr := add(resultPtr, 1)
mstore(resultPtr, shl(248, mload(add(tablePtr, and(shr(6, input), 0x3F)))))
resultPtr := add(resultPtr, 1)
mstore(resultPtr, shl(248, mload(add(tablePtr, and(input, 0x3F)))))
resultPtr := add(resultPtr, 1)
}
// padding with '='
switch mod(mload(data_), 3)
case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result_;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {EnumerableSetUpgradeable} from "openzeppelin-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {LeadingHashStorage} from "src/utils/storage/LeadingHashStorage.sol";
library IAMStorage {
// Libraries -------------------------------------------------------------------------------
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the iam state
bytes32 public constant THREE_DNS__IAM_STORAGE__V1 = keccak256("3dns.reg_control.iam.v1.state");
/// Datastructures ----------------------------------------------------------------------------
struct IAMProfiles {
EnumerableSetUpgradeable.AddressSet profiles;
mapping(address => bytes32) permissions;
}
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
/// @param approvals Mapping of token to IAM permissions
mapping(bytes32 => mapping(uint256 => IAMProfiles)) iamProfiles;
mapping(bytes32 => uint256) iamProfilesVersion;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__IAM_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
/// Shared Helper Functions -------------------------------------------------------------------
function getIAMProfilesVersion(bytes32 node) internal view returns (uint256) {
return layout().iamProfilesVersion[node];
}
function clearIAMProfiles(bytes32 node) internal {
layout().iamProfilesVersion[node]++;
}
function hasIAMProfile(bytes32 node, address user) internal view returns (bool) {
return layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.contains(user);
}
function getIAMProfiles(bytes32 node) internal view returns (address[] memory) {
return layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.values();
}
function getIAMProfile(bytes32 node, address user) internal view returns (bytes32) {
return layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user];
}
function setIAMProfile(bytes32 node, address user, bytes32 profile) internal {
if (profile == 0) {
deleteIAMProfile(node, user);
} else {
if (!hasIAMProfile(node, user)) {
layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.add(user);
}
layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user] = profile;
}
}
function deleteIAMProfile(bytes32 node, address user) internal {
layout().iamProfiles[node][getIAMProfilesVersion(node)].profiles.remove(user);
delete layout().iamProfiles[node][getIAMProfilesVersion(node)].permissions[user];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// External References ---------------------------------------------------------------------------
import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol";
/// Internal References ---------------------------------------------------------------------------
import {BaseSignature} from "src/utils/signature/BaseSignature.sol";
abstract contract TypedDataSignature is Initializable, BaseSignature {
function signatureType() public override pure returns (string memory) {
return "EIP712";
}
/// Domain Variables --------------------------------------------------------------------------
/// @dev Internal variable calculated from the domain name, version, chainId, and contract address.
bytes32 public DOMAIN_SEPARATOR;
/// @dev Internal variable specifing the domain name of the 712 typed signature.
string public DOMAIN_NAME;
/// @dev Internal variable specifing the version of the 712 typed signature.
string public DOMAIN_VERSION;
/// @dev Internal variable specifing the chainId of the 712 typed signature.
uint64 public CHAIN_ID;
function TYPED_DATA_SIGNATURE_TYPEHASH() external view virtual returns (bytes32);
/// Initializer ----------------------------------------------------------------------------
/// @dev Initializes an internal helper contract used for verifying 712 typed signatures.
function __TypedDataSignature_init(
string memory domainName_,
string memory domainVersion_,
uint64 chainId_
) internal onlyInitializing {
DOMAIN_NAME = domainName_;
DOMAIN_VERSION = domainVersion_;
CHAIN_ID = chainId_;
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint64 chainId,address verifyingContract)"
),
keccak256(bytes(DOMAIN_NAME)),
keccak256(bytes(DOMAIN_VERSION)),
CHAIN_ID,
address(this)
)
);
}
function getDomainSeparator() public view returns (bytes32) {
return DOMAIN_SEPARATOR;
}
function _calculateDigest(
bytes memory data_
) internal view override returns (bytes32) {
return
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
_calculateTypeHash(data_)
)
);
}
/// Abstract Function Declarations ============================================================
function _calculateTypeHash(bytes memory data_) internal view virtual returns (bytes32);
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {IThreeDNSAuthority} from "../interfaces/IThreeDNSAuthority.sol";
library SponsorShieldStorage {
/// SLO Offsets -------------------------------------------------------------------------------
/// @dev Constant specifing the storage location of the payment state
bytes32 public constant THREE_DNS__SPONSOR_SHIELD_STORAGE__V1 =
keccak256("3dns.access_controlled.sponsor_shield.v1.state");
/// Constants ---------------------------------------------------------------------------------
uint256 internal constant _NOT_SPONSORED = 1;
uint256 internal constant _SPONSORED = 2;
/// Contract State ----------------------------------------------------------------------------
/// @dev Struct used to define the state variables for the 3dns registry.
struct Layout {
uint256 status;
address payee;
uint256 paymentType;
uint256 paymentAmount;
}
function layout() internal pure returns (Layout storage l) {
bytes32 slot = THREE_DNS__SPONSOR_SHIELD_STORAGE__V1;
/// @solidity memory-safe-assembly
assembly {
l.slot := slot
}
}
function initialize() internal {
_setStatus(_NOT_SPONSORED);
}
/// Helper Functions --------------------------------------------------------------------------
function _setStatus(uint256 status) internal {
layout().status = status;
}
function _setPayee(address payee) internal {
layout().payee = payee;
}
function _getPayee() internal view returns (address) {
return layout().payee;
}
function _setPaymentType(uint256 paymentType) internal {
layout().paymentType = paymentType;
}
function _getPaymentType() internal view returns (uint256) {
return layout().paymentType;
}
function _setPaymentAmount(uint256 paymentAmount) internal {
layout().paymentAmount = paymentAmount;
}
function _decrementPaymentAmount(uint256 amount) internal returns (bool) {
if (layout().paymentAmount < amount) {
return false;
}
layout().paymentAmount -= amount;
return true;
}
function _clearPayment() internal {
layout().paymentType = 0;
layout().paymentAmount = 0;
}
function _getStatus() internal view returns (uint256) {
return layout().status;
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {
IAMStorage as Storage,
RegistryStorage
} from "src/regcontrol/storage/Storage.sol";
import {IIAM} from "src/regcontrol/interfaces/IIAM.sol";
import {RegControlBase} from "src/regcontrol/modules/types/RegControlBase.sol";
import "src/regcontrol/modules/types/Errors.sol";
/// Contract -----------------------------------------------------------------------------------
contract AccessManagement is RegControlBase {
/// Authorization Functions -------------------------------------------------------------------
function _permissionCheck_registration(
bytes32 node_, address operator_, IIAM.IAMRole role_, IIAM.IAMPermission perm_
) internal view returns (bool) {
if (perm_ == IIAM.IAMPermission.UNDEFINED) {
revert BaseRegControl_invalidPermission();
}
// Operators and controlers are treated as accounts with ADMIN role
// - Controllers are account level administrators
// - Operators are token level administrators
if (_isApprovedRegistrationOperator(node_, operator_) || _isApprovedAccountOperator(node_, operator_)) {
return true;
}
// Check if the operator has the required role
return _checkRegistrationIAM_hasRole(node_, operator_, role_, perm_);
}
/// Administrative Functions ------------------------------------------------------------------
function _clearRegistrationApprovals(bytes32 node_) internal {
// Remove the registration approval
_setRegistrationApproval(node_, address(0));
// Clear the registration IAM profiles
_clearRegistrationIAMProfiles(node_);
}
function _clearRegistrationIAMProfiles(bytes32 node_) internal {
// Increment the version number of the IAM profiles to invalidate all existing profiles
Storage.clearIAMProfiles(node_);
// Emit event
emit RegistrationIAMCleared(node_);
}
// Token Operator Compliance //
function _setRegistrationApproval(bytes32 node_, address operator_) internal {
// Validate operation
_setRegistrationApproval__validate(node_, operator_);
if (operator_ == address(0)) {
// Remove the operator
RegistryStorage.removeApprovedRegistrationOperator(node_);
} else {
// Approve the operator
RegistryStorage.approveRegistrationOperator(node_, operator_);
}
(address registrant_, ,) = RegistryStorage.getRecordData(node_);
// Emit approval events
// ERC721 & ERC1155 events are the same
emit Approval(registrant_, operator_, uint256(node_));
}
// Account Operator //
function _setAccountOperatorApproval(address operator_, bool approval_) internal {
// Validate operation
_setAccountOperatorApproval__validate(msg.sender, operator_, approval_);
// Process request
_setAccountOperatorApproval__private(msg.sender, operator_, approval_);
// Emit approval events
// ENS & ERC721 & ERC1155 events are the same
emit ApprovalForAll(msg.sender, operator_, approval_);
}
// IAM Roles //
function _setRegistrationIAMAuthorization(
bytes32 node_,
address account_,
IIAM.IAMAuthorization[] memory profile_
) internal {
bytes32 perms_;
// Build the permissions
for (uint8 i = 0; i < profile_.length; i++) {
// If the permission has already been set, revert
if ((perms_ >> (uint8(profile_[i].role) * 2) & bytes32(uint256(3))) > 0)
revert BaseRegControl_invalidPermission();
perms_ |= bytes32(uint256(uint8(profile_[i].permission)) << (uint8(profile_[i].role) * 2));
}
// Set the IAM profile permissions
Storage.setIAMProfile(node_, account_, perms_);
// Emit event
emit RegistrationIAMAuthorization(node_, account_, perms_);
}
function _setRegistrationIAMRolePermission(
bytes32 node_,
address account_,
IIAM.IAMRole role_,
IIAM.IAMPermission perm_
) internal {
// Grab the current permissions
bytes32 perms_ = Storage.getIAMProfile(node_, account_);
perms_ &= ~bytes32(uint256(uint8(3) << (uint8(role_) * 2)));
perms_ |= bytes32(uint256(uint8(perm_) << (uint8(role_) * 2)));
// Update the permissions
Storage.setIAMProfile(node_, account_, perms_);
// Emit event
emit RegistrationIAMAuthorization(node_, account_, perms_);
}
/// Internal Functions ------------------------------------------------------------------------
// function _getRegistrationIAMProfileAccounts(bytes32 node_) internal view returns (address[] memory) {
// return Storage.getIAMProfiles(node_);
// }
function _getRegistrationIAMProfiles(bytes32 node_) internal view returns (IIAM.IAMProfile[] memory) {
// Get the accounts with IAM profiles
address[] memory accounts = Storage.getIAMProfiles(node_);
// Create the IAM profiles
IIAM.IAMProfile[] memory profiles = new IIAM.IAMProfile[](accounts.length);
for (uint256 i = 0; i < accounts.length; i++)
profiles[i] = IIAM.IAMProfile(accounts[i], _getRegistrationIAMProfile(node_, accounts[i]));
return profiles;
}
function _getRegistrationIAMProfile(bytes32 node_, address account_) internal view returns (IIAM.IAMAuthorization[] memory) {
// Grab the current profile permissions
bytes32 permissions_ = Storage.getIAMProfile(node_, account_);
// Create the IAM profile
IIAM.IAMAuthorization[] memory profile = new IIAM.IAMAuthorization[](4);
for (uint8 i = 0; i < 4; i++)
profile[i] = IIAM.IAMAuthorization(IIAM.IAMRole(i), IIAM.IAMPermission((uint256(permissions_) >> (i * 2)) & 0x03));
return profile;
}
function _getRegistrationIAMRole(
bytes32 node_,
address account_,
IIAM.IAMRole role_
) internal view returns (IIAM.IAMPermission) {
// Grab the current permissions
bytes32 currentPermissions = Storage.getIAMProfile(node_, account_);
uint8 role = uint8((uint256(currentPermissions) >> (uint8(role_) * 2)) & 0x03);
return IIAM.IAMPermission(role);
}
function _checkRegistrationIAM_hasRole(
bytes32 node_,
address account_,
IIAM.IAMRole role_,
IIAM.IAMPermission perm_
) internal view returns (bool) {
// If the current role is greater than or equal to the desired permission, return true
return _getRegistrationIAMRole(node_, account_, role_) >= perm_;
}
/// Validators --------------------------------------------------------------------------------
function _setAccountOperatorApproval__validate(
address account_, address operator_, bool approval_
) private {
// Validate the operator is not the sender or the zero address
if (account_ == operator_ || operator_ == address(0)) {
revert BaseRegControl_invalidOperator(operator_);
}
// Validate the operator is not the desired approval state
if (_isApprovedAccountOperator(account_, operator_) == approval_) {
revert BaseRegControl_operatorStateUnchanged(operator_, approval_);
}
}
function _setRegistrationApproval__validate(bytes32 node_, address operator_) private {
// Validate the operator is not the sender
address registrant_ = _getRegistrant(node_);
if (registrant_ != address(0) && registrant_ == operator_) {
revert BaseRegControl_invalidOperator(operator_);
}
// Validate the registration exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the operator is not the current approved address
if (operator_ != address(0) && _getApprovedRegistrationOperator(node_) == operator_) {
revert BaseRegControl_invalidOperator(operator_);
}
}
/// Private Functions -------------------------------------------------------------------------
function _setAccountOperatorApproval__private(
address registrant_, address operator_, bool approval_
) private {
// Update internal state to track the approval
if (approval_) {
RegistryStorage.addAccountOperatorApproval(registrant_, operator_);
} else {
RegistryStorage.removeAccountOperatorApproval(registrant_, operator_);
}
}
/// Accessor Functions ------------------------------------------------------------------------
function _isApprovedAccountOperator(bytes32 node_, address operator_) private view returns (bool) {
return _isApprovedAccountOperator(_getRegistrant(node_), operator_);
}
function _isApprovedAccountOperator(address owner_, address operator_) internal view returns (bool) {
// Return true if operator is the owner or the account operator
return owner_ == operator_ ||
RegistryStorage.isApprovedAccountOperator(owner_, operator_);
}
function _isApprovedRegistrationOperator(bytes32 node_, address operator_) private view returns (bool) {
// Return true if operator is account operator or token operator
return _getApprovedRegistrationOperator(node_) == operator_;
}
function _getApprovedRegistrationOperator(bytes32 node_) internal view returns (address) {
return RegistryStorage.getApprovedRegistrationOperator(node_);
}
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {
RegistryStorage as Storage,
RegistrarStorage
} from "src/regcontrol/storage/Storage.sol";
import {RegControlBase} from "src/regcontrol/modules/types/RegControlBase.sol";
import "src/regcontrol/modules/types/Errors.sol";
/// Contract -----------------------------------------------------------------------------------
contract Enforcer is RegControlBase {
/// Internal Functions ------------------------------------------------------------------------
function _lockRegistration(bytes32 node_, uint64 duration_) internal {
// Validate the registration exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the node has not already expired
if (_isNodeExpired(node_)) {
revert BaseRegControl_nodeExpired(node_);
}
uint64 lockedUtil_ = uint64(block.timestamp + duration_);
// Set the lock on the domain
RegistrarStorage.setDomainLockData(node_, lockedUtil_);
// Emit a RegistrationLocked event
emit RegistrationLocked(node_, duration_);
}
function _removeRegistrationLock(bytes32 node_) internal {
// Validate the registration exists
if (_isNodeAvailable(node_)) {
revert BaseRegControl_nodeDoesNotExist(node_);
}
// Validate the node has not already expired
if (_isNodeExpired(node_)) {
revert BaseRegControl_nodeExpired(node_);
}
// Remove the lock on the domain
RegistrarStorage.setDomainLockData(node_, 0);
// Emit a RegistrationUnlocked event
emit RegistrationUnlocked(node_);
}
/// Accessor Functions ------------------------------------------------------------------------
function _isNodeTransferable(bytes32 node_) internal view returns (bool) {
return !_isNodeExpired(node_) && !_isNodeLocked(node_);
}
function _isNodeLocked(bytes32 node_) internal view returns (bool) {
// TODO: Add controlBitmap check ~ when implemented
// Check the registrar storage for domain locks
(uint64 settlement_) = RegistrarStorage.getDomainLockData(node_);
return settlement_ > block.timestamp;
}
function _isNodeExpired(bytes32 node_) internal view returns (bool) {
(,, uint64 expiration_) = Storage.getRecordData(node_);
return expiration_ < block.timestamp;
}
}// solhint-disable func-name-mixedcase // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.18; /// Errors ------------------------------------------------------------------------------------- error BaseRegControl_nodeDoesNotExist(bytes32 node_); error BaseRegControl_nodeExpired(bytes32 node_); error BaseRegControl_nodeNotTransferable(bytes32 node_); error BaseRegControl_nodeHasSubdomains(bytes32 node_); error BaseRegControl_invalidTLD(bytes32 tld_); error BaseRegControl_invalidLabel(bytes label_); error BaseRegControl_subdomainUnavailable(bytes label_, bytes32 parent_); error BaseRegControl_invalidDuration(uint64 duration_); error BaseRegControl_invalidDurationExtension(uint64 duration_); error BaseRegControl_invalidRegistrant(address registrant_); error BaseRegControl_invalidOperator(address operator_); error BaseRegControl_operatorStateUnchanged(address operator_, bool approved_); error BaseRegControl_registrantNotCurrent(bytes32 node_, address registrant_); error BaseRegControl_invalidPermission(); error BaseRegControl_notImplemented();
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IIAM {
struct IAMProfile {
address account;
IAMAuthorization[] perms;
}
struct IAMAuthorization {
IAMRole role;
IAMPermission permission;
}
enum IAMRole {
ADMIN,
WEB_MANAGER,
IDENTITY_MANAGER,
OFFCHAIN_MANAGER
}
enum IAMPermission {
UNDEFINED,
VIEW,
PROPOSE,
MANAGE
}
// Delete all IAM profiles associated with the node
function clearIAMProfiles(bytes32 node_) external;
// Setting a profile to 0 will remove it
function setIAMProfile(bytes32 node_, address account_, IAMAuthorization[] memory perms_) external;
function setIAMPermission(
bytes32 node_,
address account_,
IAMRole role_,
IAMPermission perm_
) external;
function getIAMProfiles(bytes32 node_) external view returns (IAMProfile[] memory);
function getIAMProfile(bytes32 node_, address account_) external view returns (IAMAuthorization[] memory);
function getIAMPermission(
bytes32 node_,
address account_,
IAMRole role_
) external view returns (IAMPermission perm_);
function hasIAMRole(
bytes32 node_,
address account_,
IAMRole role_,
IAMPermission perm_
) external view returns (bool);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {StringsUpgradeable} from "openzeppelin-upgradeable/utils/StringsUpgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {ICustomToken} from "src/regcontrol/interfaces/tokens/ICustomToken.sol";
import {AbstractDomainController} from "src/regcontrol/modules/types/abstracts/AbstractDomainController.sol";
import {HybridMetadataStorage} from "src/regcontrol/storage/Storage.sol";
/// Errors -------------------------------------------------------------------------------------
error HybridMetadataService__uri__tokenDoesNotExist(uint256 tokenId_);
abstract contract HybridMetadataService is ICustomToken, AbstractDomainController {
/// Libraries ---------------------------------------------------------------------------------
using StringsUpgradeable for uint256;
/// Accessor Functions ---------------------------------------------------------------------
/// @dev See {IERC721Metadata-name}.
function name() external pure returns (string memory) {
return HybridMetadataStorage.name();
}
/// @dev See {IERC721Metadata-symbol}.
function symbol() external pure returns (string memory) {
return HybridMetadataStorage.symbol();
}
/// Function overrides -----------------------------------------------------------------------------
/// @dev See {IERC721Metadata-tokenURI}.
function tokenURI(uint256 tokenId_) public view returns (string memory) {
return uri(tokenId_);
}
/// @dev See {IERC1155MetadataURI-URI}.
function uri(uint256 tokenId_) public view returns (string memory) {
if (!_tokenExists(tokenId_)) {
revert HybridMetadataService__uri__tokenDoesNotExist(tokenId_);
}
(string memory fqdn_, bytes32 tld_) = _getFQDN(bytes32(tokenId_));
return string(
abi.encodePacked(
"data:application/json;base64,",
HybridMetadataStorage.base64(
abi.encodePacked(
'{"name":"',
fqdn_,
'","description":"',
_renderDescription(fqdn_, tld_),
'","traits":[],"image":"',
_imageUrl(tld_, bytes32(tokenId_)),
'"}'
)
)
)
);
}
function _imageUrl(bytes32 tld_, bytes32 node_) private view returns (string memory url_) {
return string(
abi.encodePacked(HybridMetadataStorage.baseUrl(tld_), HybridMetadataStorage.bytes32ToHexString(node_))
);
}
function _renderDescription(string memory fqdn_, bytes32 tld_) private view returns (string memory) {
return string(abi.encodePacked(fqdn_, HybridMetadataStorage.description(tld_)));
}
/// Abstract Accessor Functions ===============================================================
function _getFQDN(bytes32 node_) internal view virtual returns (string memory, bytes32);
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// External References ---------------------------------------------------------------------------
import {IERC20Upgradeable} from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol";
/// Internal References ---------------------------------------------------------------------------
import {Datastructures} from "src/regcontrol/storage/Datastructures.sol";
interface IPaymentProcessor {
/// Events ---------------------------------------------------------------------------------
/// Management Functions ----------------------------------------------------------------------
/// Accessor Functions ------------------------------------------------------------------------
function ERC20_USDC_ADDRESS() external returns (IERC20Upgradeable);
// function rentPrice(
// string memory label_,
// bytes32 tld_,
// uint256 duration_,
// Datastructures.PaymentType paymentType_
// ) external view returns (uint256 amount_);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSetUpgradeable {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
library LeadingHashStorage {
struct LHBytes {
bytes32 leadingHash;
bytes data;
}
function get(LHBytes storage self) internal view returns (bytes memory) {
return self.data;
}
function getLeadingHash(LHBytes storage self) internal view returns (bytes32) {
return self.leadingHash;
}
function set(LHBytes storage self, bytes memory data) internal {
self.leadingHash = keccak256(data);
self.data = data;
}
struct LHString {
LHBytes lhBytes;
}
function get(LHString storage self) internal view returns (string memory) {
return string(LeadingHashStorage.get(self.lhBytes));
}
function getLeadingHash(LHString storage self) internal view returns (bytes32) {
return LeadingHashStorage.getLeadingHash(self.lhBytes);
}
function set(LHString storage self, string memory data) internal {
LeadingHashStorage.set(self.lhBytes, bytes(data));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// Errors ---------------------------------------------------------------------------------
error InvalidPayload();
error InvalidSignature();
abstract contract BaseSignature {
/// Functions ------------------------------------------------------------------------------
function signatureType() public virtual pure returns (string memory) {
return "EIP191";
}
function _validateSignature(
bytes memory data_,
uint8 v_, bytes32 r_, bytes32 s_
) internal view {
// Verify payload
if (!_validPayload(data_))
revert InvalidPayload();
address signer_ = ecrecover(
_calculateDigest(data_),
v_, r_, s_
);
if (
signer_ == address(0) ||
!_isValidSigner(signer_)
) revert InvalidSignature();
}
/// Abstract Function Declarations ============================================================
function _validPayload(bytes memory data_) internal view virtual returns (bool);
function _calculateDigest(bytes memory data_) internal view virtual returns (bytes32);
function _isValidSigner(address signer) internal view virtual returns (bool);
}// solhint-disable func-name-mixedcase
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
/// Internal References ---------------------------------------------------------------------------
import {BytesUtils} from "src/regcontrol/libraries/BytesUtils.sol";
import {
RegistryStorage as Storage,
RegControlStorage
} from "src/regcontrol/storage/Storage.sol";
import {GlobalEvents} from "src/regcontrol/modules/types/GlobalEvents.sol";
import "src/regcontrol/modules/types/Errors.sol";
/// Contract -----------------------------------------------------------------------------------
contract RegControlBase is GlobalEvents {
/// Constants ------------------------------------------------------------------------------
uint64 internal constant YEAR = 31557600; // 365.25 * 24 * 60 * 60;
/// Accessor Functions ------------------------------------------------------------------------
function _getRegistrant(bytes32 node_) internal view returns (address registrant_) {
uint64 expiration_;
(registrant_,, expiration_) = Storage.getRecordData(node_);
if (expiration_ < block.timestamp) {
registrant_ = address(0x00);
}
return registrant_;
}
function _getNodeData(bytes32 node_) internal view returns (address registrant, uint32 controlBitmap, uint64 expiration) {
(registrant, controlBitmap, expiration) = Storage.getRecordData(node_);
if (expiration < block.timestamp) {
registrant = address(0x00);
}
return (registrant, controlBitmap, expiration);
}
function _getDomainNameOwnershipCount(address registrant_) internal view returns (uint256) {
return Storage.getOwnershipCount(registrant_);
}
function _getRecordCount() internal view returns (uint256) {
return Storage.recordCount();
}
function _getParent(bytes32 node_) internal view returns (bytes32) {
return Storage.getParent_reverseRecord(node_);
}
function _getLabel(bytes32 node_) internal view returns (bytes memory) {
return Storage.getLabel_reverseRecord(node_);
}
function _resolver(bytes32 node_) internal view returns (address) {
return RegControlStorage.primaryResolver();
}
/// Helper Functions --------------------------------------------------------------------------
function _isNodeAvailable(bytes32 node_) internal view returns (bool) {
(address registrant_,, uint64 expiration_) = Storage.getRecordData(node_);
return registrant_ == address(0x00) || expiration_ < block.timestamp;
}
function _isSubdomainAvailable(bytes32 labelHash_, bytes32 parent_) internal view returns (bool) {
return _isNodeAvailable(_calculateNode(labelHash_, parent_));
}
function _hasSubdomains(bytes32 node_) internal view returns (bool) {
return Storage.recordHasChildren(node_);
}
/// Helper Functions --------------------------------------------------------------------------
function _calculateNode(bytes calldata fqdn_) internal pure returns (bytes32) {
// Parse the label from the fqdn
(, bytes32 labelHash_, uint256 offset_) = BytesUtils.readAndReturnLabel(fqdn_, 0);
// Parse the tld from the fqdn
bytes32 tld_ = BytesUtils.namehash(fqdn_, offset_);
// Calculate the node
return _calculateNode(labelHash_, tld_);
}
function _calculateNode(bytes memory label_, bytes32 parent_) internal pure returns (bytes32) {
return _calculateNode(keccak256(label_), parent_);
}
function _calculateNode(bytes32 labelHash_, bytes32 parent_) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(parent_, labelHash_));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// Internal References ---------------------------------------------------------------------------
import {AbstractAccessControlled} from "src/utils/access/abstracts/AbstractAccessControlled.sol";
abstract contract AbstractDomainController /* is AbstractAccessControlled */ {
/// Accessor Functions ------------------------------------------------------------------------
function _tokenExists(uint256 node_) internal view virtual returns (bool);
// function _callerIsMetadataAdmin__validate() internal view virtual;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
contract GlobalEvents {
/// ERC721 ---------------------------------------------------------------------------------
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/// ERC1155 --------------------------------------------------------------------------------
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
// /**
// * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
// * transfers.
// */
// event TransferBatch(
// address indexed operator,
// address indexed from,
// address indexed to,
// uint256[] ids,
// uint256[] values
// );
// /**
// * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
// * `approved`.
// */
// event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/// 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
// );
/// 3DNS -----------------------------------------------------------------------------------
event RegistrationCreated(
bytes32 indexed node, bytes32 indexed tld, bytes fqdn, address registrant, uint32 controlBitmap, uint64 expiry
);
event RegistrationExtended(bytes32 indexed node, uint64 indexed duration, uint64 indexed newExpiry);
event RegistrationTransferred(bytes32 indexed node, address indexed newOwner, address indexed operator);
event RegistrationBurned(bytes32 indexed node, address indexed burner);
event RegistrationLocked(bytes32 indexed node, uint64 lockedUntil);
event RegistrationUnlocked(bytes32 indexed node);
event RegistrationIAMAuthorization(bytes32 indexed node, address indexed operator, bytes32 permissions);
event RegistrationIAMCleared(bytes32 indexed node);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/// Internal References ---------------------------------------------------------------------------
import {IThreeDNSAccessControlled} from "../interfaces/IThreeDNSAccessControlled.sol";
import {IThreeDNSAuthority} from "../interfaces/IThreeDNSAuthority.sol";
abstract contract AbstractAccessControlled is IThreeDNSAccessControlled {
/// Abstract Authority Accessor ===============================================================
function authority() public view virtual returns (IThreeDNSAuthority);
/// Access Control Functions ==================================================================
function _callerIsOperator__validate() internal view virtual;
}{
"remappings": [
"ds-test/=lib/solmate/lib/ds-test/src/",
"ens-contracts/=lib/ens-contracts/contracts/",
"ens/=lib/ens/contracts/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-not-upgradeable/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"solmate/=lib/solmate/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"create2deployer/=lib/create2deployer/",
"diamond-3/=lib/diamond-3/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_facetAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_facetDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LibDiamondCut_immutableFunction","type":"error"},{"inputs":[],"name":"ThreeDNSAccessControlled_invalidAuthority","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ThreeDNSAccessControlled_unauthorized","type":"error"},{"inputs":[],"name":"ThreeDNSRegControl_accessDenied","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IThreeDNSAuthority","name":"previousAuthority","type":"address"},{"indexed":true,"internalType":"contract IThreeDNSAuthority","name":"newAuthority","type":"address"}],"name":"AuthorityChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract IThreeDNSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IThreeDNSAuthority","name":"_newAuthority","type":"address"}],"name":"changeAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamondCut.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"internalType":"struct IDiamondCut.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"internalType":"address","name":"_init","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"diamondCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IThreeDNSAuthority","name":"_authority","type":"address"},{"internalType":"address","name":"resolver_","type":"address"},{"internalType":"string","name":"domainName_","type":"string"},{"internalType":"string","name":"domainVersion_","type":"string"},{"internalType":"uint64","name":"chainId_","type":"uint64"},{"internalType":"contract IERC20Upgradeable","name":"usdc_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"},{"internalType":"bool","name":"enabled_","type":"bool"}],"name":"trackInterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608060405234801561001057600080fd5b5061001961001e565b6100dd565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611d72806100ec6000396000f3fe6080604052600436106100595760003560e01c806301ffc9a71461010d578063116877cc1461017b5780631f931c1c1461019b5780633cbd93e6146101bb578063bf7e214f146101db578063c0d18dad1461020857610060565b3661006057005b600080356001600160e01b0319168152600080516020611cd1833981519152602081905260409091205481906001600160a01b0316806100e75760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f7420657869737460448201526064015b60405180910390fd5b3660008037600080366000845af43d6000803e808015610106573d6000f35b3d6000fd5b005b34801561011957600080fd5b5061016661012836600461150b565b6001600160e01b03191660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561018757600080fd5b5061010b610196366004611542565b610228565b3480156101a757600080fd5b5061010b6101b63660046115b3565b61023c565b3480156101c757600080fd5b5061010b6101d6366004611673565b610295565b3480156101e757600080fd5b506101f06102e8565b6040516001600160a01b039091168152602001610172565b34801561021457600080fd5b5061010b61022336600461178a565b6102f7565b610230610420565b61023981610449565b50565b6102446104c9565b61028e6102518587611863565b8484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506105cb92505050565b5050505050565b61029d6104c9565b6001600160e01b03199190911660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f60205260409020805460ff1916911515919091179055565b60006102f26107dc565b905090565b600054610100900460ff16158080156103175750600054600160ff909116105b806103315750303b158015610331575060005460ff166001145b6103945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016100de565b6000805460ff1916600117905580156103b7576000805461ff0019166101001790555b6103c08761080a565b6103c8610875565b6103d18661089d565b8015610417576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6104286108f4565b61044757604051636508181b60e01b81523360048201526024016100de565b565b6001600160a01b03811661047057604051630b208f6960e11b815260040160405180910390fd5b600061047a6107dc565b90506104858261096f565b816001600160a01b0316816001600160a01b03167f275720694d99bebae3e30a093350471a8a15db9c771974d841c724b07a55f39260405160405180910390a35050565b6104d16102e8565b6001600160a01b031663c33888306104e76102e8565b6001600160a01b0316636112f7076040518163ffffffff1660e01b8152600401602060405180830381865afa158015610524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105489190611999565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401602060405180830381865afa15801561058a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ae91906119b2565b610447576040516306a573bb60e41b815260040160405180910390fd5b60005b83518110156107915760008482815181106105eb576105eb6119cf565b60200260200101516020015190506000600281111561060c5761060c6119e5565b81600281111561061e5761061e6119e5565b0361066c57610667858381518110610638576106386119cf565b602002602001015160000151868481518110610656576106566119cf565b6020026020010151604001516109a9565b61077e565b6001816002811115610680576106806119e5565b036106c95761066785838151811061069a5761069a6119cf565b6020026020010151600001518684815181106106b8576106b86119cf565b602002602001015160400151610bc1565b60028160028111156106dd576106dd6119e5565b03610726576106678583815181106106f7576106f76119cf565b602002602001015160000151868481518110610715576107156119cf565b602002602001015160400151610e4b565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084016100de565b508061078981611a11565b9150506105ce565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516107c593929190611a7a565b60405180910390a16107d78282610f68565b505050565b7fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d84546001600160a01b031690565b600054610100900460ff166102305760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016100de565b61044760017efb1582097edca5730fdb99215e4455bb86a33d4dfb2e772de67f816dc82a6755565b6001600160a01b0381166108b057600080fd5b807f12ae3e04032463d545323c69dad532e95f65241ef43aee9d1febe281cd74afe95b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000336108ff6107dc565b6001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa15801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190611b7a565b6001600160a01b031614905090565b6001600160a01b03811661098257600080fd5b807fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d846108d3565b60008151116109ca5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b0383166109ff5760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610aa457610a4884604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610ac457610ac46119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03168015610b195780826040516379e539eb60e11b81526004016100de929190611c2e565b6001600160a01b03871660008181526001878101602090815260408084208054938401815584528184206008840401805463ffffffff60079095166004026101000a948502191660e089901c94909402939093179092556001600160e01b031986168352889052902080546001600160b01b031916909117600160a01b61ffff87160217905583610ba981611c51565b94505050508080610bb990611a11565b915050610aa7565b6000815111610be25760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b038316610c175760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610cbc57610c6084604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610cdc57610cdc6119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b039081169087168103610d875760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060648201526084016100de565b610d918183611196565b6001600160e01b03198216600081815260208781526040808320805461ffff60a01b1916600160a01b61ffff8b16021781556001600160a01b038c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b03191617905583610e3381611c51565b94505050508080610e4390611a11565b915050610cbf565b6000815111610e6c5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b03831615610ef15760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b60648201526084016100de565b60005b8251811015610f62576000838281518110610f1157610f116119cf565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610f4d8183611196565b50508080610f5a90611a11565b915050610ef4565b50505050565b6001600160a01b038216610fef57805115610feb5760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d7074790000000060648201526084016100de565b5050565b60008151116110665760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f74206164647265737328302900000060648201526084016100de565b6001600160a01b03821630146110985761109882604051806060016040528060288152602001611cf160289139611175565b600080836001600160a01b0316836040516110b39190611c72565b600060405180830381855af49150503d80600081146110ee576040519150601f19603f3d011682016040523d82523d6000602084013e6110f3565b606091505b509150915081610f625780511561111e578060405162461bcd60e51b81526004016100de9190611c8e565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b60648201526084016100de565b813b8181610f625760405162461bcd60e51b81526004016100de9190611c8e565b600080516020611cd18339815191526001600160a01b0383166111d057828260405163013e763960e21b81526004016100de929190611c2e565b306001600160a01b038416036111fd57828260405163c66c256160e01b81526004016100de929190611c2e565b6001600160e01b03198216600090815260208281526040808320546001600160a01b0387168452600180860190935290832054600160a01b90910461ffff16929161124791611ca1565b9050808214611333576001600160a01b0385166000908152600184016020526040812080548390811061127c5761127c6119cf565b600091825260208083206008830401546001600160a01b038a168452600188019091526040909220805460079092166004026101000a90920460e01b9250829190859081106112cd576112cd6119cf565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b031992909216825284905260409020805461ffff60a01b1916600160a01b61ffff8516021790555b6001600160a01b0385166000908152600184016020526040902080548061135c5761135c611cba565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319861682528490526040812080546001600160b01b031916905581900361028e5760028301546000906113ca90600190611ca1565b6001600160a01b038716600090815260018087016020526040909120015490915061ffff1680821461148957600085600201838154811061140d5761140d6119cf565b6000918252602090912001546002870180546001600160a01b03909216925082918490811061143e5761143e6119cf565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815260018781019092526040902001805461ffff191661ffff83161790555b8460020180548061149c5761149c611cba565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03891682526001878101909152604090912001805461ffff1916905550505050505050565b80356001600160e01b03198116811461150657600080fd5b919050565b60006020828403121561151d57600080fd5b611526826114ee565b9392505050565b6001600160a01b038116811461023957600080fd5b60006020828403121561155457600080fd5b81356115268161152d565b80356115068161152d565b60008083601f84011261157c57600080fd5b50813567ffffffffffffffff81111561159457600080fd5b6020830191508360208285010111156115ac57600080fd5b9250929050565b6000806000806000606086880312156115cb57600080fd5b853567ffffffffffffffff808211156115e357600080fd5b818801915088601f8301126115f757600080fd5b81358181111561160657600080fd5b8960208260051b850101111561161b57600080fd5b602083019750809650506116316020890161155f565b9450604088013591508082111561164757600080fd5b506116548882890161156a565b969995985093965092949392505050565b801515811461023957600080fd5b6000806040838503121561168657600080fd5b61168f836114ee565b9150602083013561169f81611665565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156116e3576116e36116aa565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611712576117126116aa565b604052919050565b600082601f83011261172b57600080fd5b813567ffffffffffffffff811115611745576117456116aa565b611758601f8201601f19166020016116e9565b81815284602083860101111561176d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156117a357600080fd5b86356117ae8161152d565b955060208701356117be8161152d565b9450604087013567ffffffffffffffff808211156117db57600080fd5b6117e78a838b0161171a565b955060608901359150808211156117fd57600080fd5b6118098a838b0161171a565b945060808901359150808216821461182057600080fd5b50915060a08701356118318161152d565b809150509295509295509295565b600067ffffffffffffffff821115611859576118596116aa565b5060051b60200190565b60006118766118718461183f565b6116e9565b83815260208082019190600586811b86013681111561189457600080fd5b865b8181101561198c57803567ffffffffffffffff808211156118b75760008081fd5b818a019150606082360312156118cd5760008081fd5b6118d56116c0565b82356118e08161152d565b815282870135600381106118f45760008081fd5b818801526040838101358381111561190c5760008081fd5b939093019236601f85011261192357600092508283fd5b833592506119336118718461183f565b83815292871b840188019288810190368511156119505760008081fd5b948901945b8486101561197557611966866114ee565b82529489019490890190611955565b918301919091525088525050948301948301611896565b5092979650505050505050565b6000602082840312156119ab57600080fd5b5051919050565b6000602082840312156119c457600080fd5b815161152681611665565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611a2357611a236119fb565b5060010190565b60005b83811015611a45578181015183820152602001611a2d565b50506000910152565b60008151808452611a66816020860160208601611a2a565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015611b4a57898403607f19018652815180516001600160a01b03168552838101518986019060038110611ae957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015611b355783516001600160e01b0319168252928601926001929092019190860190611b0b565b50978501979550505090820190600101611aa3565b50506001600160a01b038a16908801528681036040880152611b6c8189611a4e565b9a9950505050505050505050565b600060208284031215611b8c57600080fd5b81516115268161152d565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b600061ffff808316818103611c6857611c686119fb565b6001019392505050565b60008251611c84818460208701611a2a565b9190910192915050565b6020815260006115266020830184611a4e565b81810381811115611cb457611cb46119fb565b92915050565b634e487b7160e01b600052603160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a264697066735822122061949b18f6f37521360e5faa7c6a902adf83acbbb22fd9eb434375c31637950a64736f6c63430008120033
Deployed Bytecode
0x6080604052600436106100595760003560e01c806301ffc9a71461010d578063116877cc1461017b5780631f931c1c1461019b5780633cbd93e6146101bb578063bf7e214f146101db578063c0d18dad1461020857610060565b3661006057005b600080356001600160e01b0319168152600080516020611cd1833981519152602081905260409091205481906001600160a01b0316806100e75760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f7420657869737460448201526064015b60405180910390fd5b3660008037600080366000845af43d6000803e808015610106573d6000f35b3d6000fd5b005b34801561011957600080fd5b5061016661012836600461150b565b6001600160e01b03191660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f602052604090205460ff1690565b60405190151581526020015b60405180910390f35b34801561018757600080fd5b5061010b610196366004611542565b610228565b3480156101a757600080fd5b5061010b6101b63660046115b3565b61023c565b3480156101c757600080fd5b5061010b6101d6366004611673565b610295565b3480156101e757600080fd5b506101f06102e8565b6040516001600160a01b039091168152602001610172565b34801561021457600080fd5b5061010b61022336600461178a565b6102f7565b610230610420565b61023981610449565b50565b6102446104c9565b61028e6102518587611863565b8484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506105cb92505050565b5050505050565b61029d6104c9565b6001600160e01b03199190911660009081527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131f60205260409020805460ff1916911515919091179055565b60006102f26107dc565b905090565b600054610100900460ff16158080156103175750600054600160ff909116105b806103315750303b158015610331575060005460ff166001145b6103945760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016100de565b6000805460ff1916600117905580156103b7576000805461ff0019166101001790555b6103c08761080a565b6103c8610875565b6103d18661089d565b8015610417576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6104286108f4565b61044757604051636508181b60e01b81523360048201526024016100de565b565b6001600160a01b03811661047057604051630b208f6960e11b815260040160405180910390fd5b600061047a6107dc565b90506104858261096f565b816001600160a01b0316816001600160a01b03167f275720694d99bebae3e30a093350471a8a15db9c771974d841c724b07a55f39260405160405180910390a35050565b6104d16102e8565b6001600160a01b031663c33888306104e76102e8565b6001600160a01b0316636112f7076040518163ffffffff1660e01b8152600401602060405180830381865afa158015610524573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105489190611999565b6040516001600160e01b031960e084901b1681526004810191909152336024820152604401602060405180830381865afa15801561058a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ae91906119b2565b610447576040516306a573bb60e41b815260040160405180910390fd5b60005b83518110156107915760008482815181106105eb576105eb6119cf565b60200260200101516020015190506000600281111561060c5761060c6119e5565b81600281111561061e5761061e6119e5565b0361066c57610667858381518110610638576106386119cf565b602002602001015160000151868481518110610656576106566119cf565b6020026020010151604001516109a9565b61077e565b6001816002811115610680576106806119e5565b036106c95761066785838151811061069a5761069a6119cf565b6020026020010151600001518684815181106106b8576106b86119cf565b602002602001015160400151610bc1565b60028160028111156106dd576106dd6119e5565b03610726576106678583815181106106f7576106f76119cf565b602002602001015160000151868481518110610715576107156119cf565b602002602001015160400151610e4b565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b60648201526084016100de565b508061078981611a11565b9150506105ce565b507f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738383836040516107c593929190611a7a565b60405180910390a16107d78282610f68565b505050565b7fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d84546001600160a01b031690565b600054610100900460ff166102305760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016100de565b61044760017efb1582097edca5730fdb99215e4455bb86a33d4dfb2e772de67f816dc82a6755565b6001600160a01b0381166108b057600080fd5b807f12ae3e04032463d545323c69dad532e95f65241ef43aee9d1febe281cd74afe95b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000336108ff6107dc565b6001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa15801561093c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109609190611b7a565b6001600160a01b031614905090565b6001600160a01b03811661098257600080fd5b807fd130673014572f7121caf912a5f962365c11e8f2a364051a5111e361375c0d846108d3565b60008151116109ca5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b0383166109ff5760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610aa457610a4884604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610ac457610ac46119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b03168015610b195780826040516379e539eb60e11b81526004016100de929190611c2e565b6001600160a01b03871660008181526001878101602090815260408084208054938401815584528184206008840401805463ffffffff60079095166004026101000a948502191660e089901c94909402939093179092556001600160e01b031986168352889052902080546001600160b01b031916909117600160a01b61ffff87160217905583610ba981611c51565b94505050508080610bb990611a11565b915050610aa7565b6000815111610be25760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b038316610c175760405162461bcd60e51b81526004016100de90611be2565b6001600160a01b03831660009081526001820160205260408120549061ffff82169003610cbc57610c6084604051806060016040528060248152602001611d1960249139611175565b6002820180546001600160a01b038616600081815260018087016020908152604083208201805461ffff191661ffff90961695909517909455845490810185559381529190912090910180546001600160a01b03191690911790555b60005b835181101561028e576000848281518110610cdc57610cdc6119cf565b6020908102919091018101516001600160e01b031981166000908152918690526040909120549091506001600160a01b039081169087168103610d875760405162461bcd60e51b815260206004820152603860248201527f4c69624469616d6f6e644375743a2043616e2774207265706c6163652066756e60448201527f6374696f6e20776974682073616d652066756e6374696f6e000000000000000060648201526084016100de565b610d918183611196565b6001600160e01b03198216600081815260208781526040808320805461ffff60a01b1916600160a01b61ffff8b16021781556001600160a01b038c168085526001808c0185529285208054938401815585528385206008840401805463ffffffff60079095166004026101000a948502191660e08a901c94909402939093179092559390925287905281546001600160a01b03191617905583610e3381611c51565b94505050508080610e4390611a11565b915050610cbf565b6000815111610e6c5760405162461bcd60e51b81526004016100de90611b97565b600080516020611cd18339815191526001600160a01b03831615610ef15760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f76652066616365742061646472604482015275657373206d757374206265206164647265737328302960501b60648201526084016100de565b60005b8251811015610f62576000838281518110610f1157610f116119cf565b6020908102919091018101516001600160e01b031981166000908152918590526040909120549091506001600160a01b0316610f4d8183611196565b50508080610f5a90611a11565b915050610ef4565b50505050565b6001600160a01b038216610fef57805115610feb5760405162461bcd60e51b815260206004820152603c60248201527f4c69624469616d6f6e644375743a205f696e697420697320616464726573732860448201527f3029206275745f63616c6c64617461206973206e6f7420656d7074790000000060648201526084016100de565b5050565b60008151116110665760405162461bcd60e51b815260206004820152603d60248201527f4c69624469616d6f6e644375743a205f63616c6c6461746120697320656d707460448201527f7920627574205f696e6974206973206e6f74206164647265737328302900000060648201526084016100de565b6001600160a01b03821630146110985761109882604051806060016040528060288152602001611cf160289139611175565b600080836001600160a01b0316836040516110b39190611c72565b600060405180830381855af49150503d80600081146110ee576040519150601f19603f3d011682016040523d82523d6000602084013e6110f3565b606091505b509150915081610f625780511561111e578060405162461bcd60e51b81526004016100de9190611c8e565b60405162461bcd60e51b815260206004820152602660248201527f4c69624469616d6f6e644375743a205f696e69742066756e6374696f6e2072656044820152651d995c9d195960d21b60648201526084016100de565b813b8181610f625760405162461bcd60e51b81526004016100de9190611c8e565b600080516020611cd18339815191526001600160a01b0383166111d057828260405163013e763960e21b81526004016100de929190611c2e565b306001600160a01b038416036111fd57828260405163c66c256160e01b81526004016100de929190611c2e565b6001600160e01b03198216600090815260208281526040808320546001600160a01b0387168452600180860190935290832054600160a01b90910461ffff16929161124791611ca1565b9050808214611333576001600160a01b0385166000908152600184016020526040812080548390811061127c5761127c6119cf565b600091825260208083206008830401546001600160a01b038a168452600188019091526040909220805460079092166004026101000a90920460e01b9250829190859081106112cd576112cd6119cf565b600091825260208083206008830401805463ffffffff60079094166004026101000a938402191660e09590951c929092029390931790556001600160e01b031992909216825284905260409020805461ffff60a01b1916600160a01b61ffff8516021790555b6001600160a01b0385166000908152600184016020526040902080548061135c5761135c611cba565b60008281526020808220600860001990940193840401805463ffffffff600460078716026101000a0219169055919092556001600160e01b0319861682528490526040812080546001600160b01b031916905581900361028e5760028301546000906113ca90600190611ca1565b6001600160a01b038716600090815260018087016020526040909120015490915061ffff1680821461148957600085600201838154811061140d5761140d6119cf565b6000918252602090912001546002870180546001600160a01b03909216925082918490811061143e5761143e6119cf565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815260018781019092526040902001805461ffff191661ffff83161790555b8460020180548061149c5761149c611cba565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b03891682526001878101909152604090912001805461ffff1916905550505050505050565b80356001600160e01b03198116811461150657600080fd5b919050565b60006020828403121561151d57600080fd5b611526826114ee565b9392505050565b6001600160a01b038116811461023957600080fd5b60006020828403121561155457600080fd5b81356115268161152d565b80356115068161152d565b60008083601f84011261157c57600080fd5b50813567ffffffffffffffff81111561159457600080fd5b6020830191508360208285010111156115ac57600080fd5b9250929050565b6000806000806000606086880312156115cb57600080fd5b853567ffffffffffffffff808211156115e357600080fd5b818801915088601f8301126115f757600080fd5b81358181111561160657600080fd5b8960208260051b850101111561161b57600080fd5b602083019750809650506116316020890161155f565b9450604088013591508082111561164757600080fd5b506116548882890161156a565b969995985093965092949392505050565b801515811461023957600080fd5b6000806040838503121561168657600080fd5b61168f836114ee565b9150602083013561169f81611665565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff811182821017156116e3576116e36116aa565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715611712576117126116aa565b604052919050565b600082601f83011261172b57600080fd5b813567ffffffffffffffff811115611745576117456116aa565b611758601f8201601f19166020016116e9565b81815284602083860101111561176d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156117a357600080fd5b86356117ae8161152d565b955060208701356117be8161152d565b9450604087013567ffffffffffffffff808211156117db57600080fd5b6117e78a838b0161171a565b955060608901359150808211156117fd57600080fd5b6118098a838b0161171a565b945060808901359150808216821461182057600080fd5b50915060a08701356118318161152d565b809150509295509295509295565b600067ffffffffffffffff821115611859576118596116aa565b5060051b60200190565b60006118766118718461183f565b6116e9565b83815260208082019190600586811b86013681111561189457600080fd5b865b8181101561198c57803567ffffffffffffffff808211156118b75760008081fd5b818a019150606082360312156118cd5760008081fd5b6118d56116c0565b82356118e08161152d565b815282870135600381106118f45760008081fd5b818801526040838101358381111561190c5760008081fd5b939093019236601f85011261192357600092508283fd5b833592506119336118718461183f565b83815292871b840188019288810190368511156119505760008081fd5b948901945b8486101561197557611966866114ee565b82529489019490890190611955565b918301919091525088525050948301948301611896565b5092979650505050505050565b6000602082840312156119ab57600080fd5b5051919050565b6000602082840312156119c457600080fd5b815161152681611665565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611a2357611a236119fb565b5060010190565b60005b83811015611a45578181015183820152602001611a2d565b50506000910152565b60008151808452611a66816020860160208601611a2a565b601f01601f19169290920160200192915050565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b84811015611b4a57898403607f19018652815180516001600160a01b03168552838101518986019060038110611ae957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b80831015611b355783516001600160e01b0319168252928601926001929092019190860190611b0b565b50978501979550505090820190600101611aa3565b50506001600160a01b038a16908801528681036040880152611b6c8189611a4e565b9a9950505050505050505050565b600060208284031215611b8c57600080fd5b81516115268161152d565b6020808252602b908201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660408201526a1858d95d081d1bc818dd5d60aa1b606082015260800190565b6020808252602c908201527f4c69624469616d6f6e644375743a204164642066616365742063616e2774206260408201526b65206164647265737328302960a01b606082015260800190565b6001600160a01b039290921682526001600160e01b031916602082015260400190565b600061ffff808316818103611c6857611c686119fb565b6001019392505050565b60008251611c84818460208701611a2a565b9190910192915050565b6020815260006115266020830184611a4e565b81810381811115611cb457611cb46119fb565b92915050565b634e487b7160e01b600052603160045260246000fdfec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a204e657720666163657420686173206e6f20636f6465a264697066735822122061949b18f6f37521360e5faa7c6a902adf83acbbb22fd9eb434375c31637950a64736f6c63430008120033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.