Overview
BERA Balance
BERA Value
$0.00More Info
Private Name Tags
ContractCreator
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 Source Code Verified (Exact Match)
Contract Name:
CliqueDistributorManager
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import "solady/utils/MerkleProofLib.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "solady/utils/FixedPointMathLib.sol"; import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; import {Initializable} from "solady/utils/Initializable.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; import {EIP712} from "solady/utils/EIP712.sol"; import {Distributor} from "./sub/Distributor.sol"; import {ECDSA} from "solady/utils/ECDSA.sol"; import {VestedDistributor} from "./sub/VestedDistributor.sol"; contract CliqueDistributorManager is Initializable, OwnableRoles, UUPSUpgradeable, EIP712 { using SafeERC20 for IERC20; using FixedPointMathLib for uint256; error DeadlineReached(); event DistributorCreated(address indexed _token, address indexed distributor, bytes signature); uint256 public constant ADMIN = _ROLE_0; uint256 public constant AIDROP_MANAGER = _ROLE_1; function initialize() external initializer { _initializeOwner(msg.sender); } function createDistributor( address _token, address _vault, address _signer, uint256 _fee, uint256 _deadline, bytes calldata _signature ) external returns (address) { if (block.timestamp > _deadline) { revert DeadlineReached(); } bytes32 digest = _hashTypedData( keccak256( abi.encode( keccak256("NewDistributor(address token,address vault,address signer,uint256 fee,uint256 deadline)"), _token, _vault, _signer, _fee, _deadline ) ) ); address recovered = ECDSA.recover(digest, _signature); if (rolesOf(recovered) & AIDROP_MANAGER == 0) { revert Unauthorized(); } Distributor _distributor = new Distributor(_signer, _token, msg.sender, _vault); emit DistributorCreated(_token, address(_distributor), _signature); return address(_distributor); } function createVestedDistributor( address _token, address _vault, address _signer, address _lock, uint256 _fee, uint256 _deadline, bytes calldata _signature ) external returns (address) { if (block.timestamp > _deadline) { revert DeadlineReached(); } bytes32 digest = _hashTypedData( keccak256( abi.encode( keccak256( "NewVestedDistributor(address token,address vault,address signer,address lock,uint256 fee,uint256 deadline)" ), _token, _vault, _signer, _lock, _fee, _deadline ) ) ); address recovered = ECDSA.recover(digest, _signature); if (rolesOf(recovered) & AIDROP_MANAGER == 0) { revert Unauthorized(); } VestedDistributor _distributor = new VestedDistributor(_signer, _token, msg.sender, _vault, _lock); emit DistributorCreated(_token, address(_distributor), _signature); return address(_distributor); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Airdrop Management */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Set the fee for the distributor /// @param _distributor address of the distributor /// @param _fee fee in percentage /// @param _deadline deadline of the transaction /// @param _signature signature of the transaction function setFee(address _distributor, uint256 _fee, uint256 _deadline, bytes calldata _signature) external { if (rolesOf(msg.sender) & AIDROP_MANAGER == 0) { if (block.timestamp > _deadline) { revert DeadlineReached(); } bytes32 digest = _hashTypedData( keccak256(abi.encode(keccak256("SetFee(address distributor, uint256 fee)"), _distributor, _fee)) ); address recovered = ECDSA.recover(digest, _signature); if (rolesOf(recovered) & AIDROP_MANAGER == 0) { revert Unauthorized(); } } // Distributor _distributorContract = Distributor(_distributor); // _distributorContract.setFee(_fee); } /// @notice Withdraw the fee from the distributor /// @param _distributor address of the distributor /// @param _recipient address of the recipient /// @param _deadline deadline of the transaction /// @param _signature signature of the transaction function withdrawFee(address _distributor, address _recipient, uint256 _deadline, bytes calldata _signature) external { if (rolesOf(msg.sender) & AIDROP_MANAGER == 0) { if (block.timestamp > _deadline) { revert DeadlineReached(); } bytes32 digest = _hashTypedData( keccak256( abi.encode( keccak256("WithdrawFee(address distributor, address recipient)"), _distributor, _recipient ) ) ); address recovered = ECDSA.recover(digest, _signature); if (rolesOf(recovered) & AIDROP_MANAGER == 0) { revert Unauthorized(); } } Distributor _distributorContract = Distributor(_distributor); _distributorContract.withdrawFee(_recipient); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* Upgrade & Metadata */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _authorizeUpgrade(address newImplementation) internal override onlyOwnerOrRoles(ADMIN) {} function _domainNameAndVersionMayChange() internal pure override returns (bool result) { return true; } function _domainNameAndVersion() internal view virtual override returns (string memory name, string memory version) { return ("CliqueDistributorManager", "1"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. * * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client" * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. * * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being * set here. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements. */ function _callOptionalReturn(IERC20 token, bytes memory data) private { uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) // bubble errors if iszero(success) { let ptr := mload(0x40) returndatacopy(ptr, 0, returndatasize()) revert(ptr, returndatasize()) } returnSize := returndatasize() returnValue := mload(0) } if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { bool success; uint256 returnSize; uint256 returnValue; assembly ("memory-safe") { success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20) returnSize := returndatasize() returnValue := mload(0) } return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) library FixedPointMathLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The operation failed, as the output exceeds the maximum value of uint256. error ExpOverflow(); /// @dev The operation failed, as the output exceeds the maximum value of uint256. error FactorialOverflow(); /// @dev The operation failed, due to an overflow. error RPowOverflow(); /// @dev The mantissa is too big to fit. error MantissaOverflow(); /// @dev The operation failed, due to an multiplication overflow. error MulWadFailed(); /// @dev The operation failed, due to an multiplication overflow. error SMulWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error DivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error SDivWadFailed(); /// @dev The operation failed, either due to a multiplication overflow, or a division by a zero. error MulDivFailed(); /// @dev The division failed, as the denominator is zero. error DivFailed(); /// @dev The full precision multiply-divide operation failed, either due /// to the result being larger than 256 bits, or a division by a zero. error FullMulDivFailed(); /// @dev The output is undefined, as the input is less-than-or-equal to zero. error LnWadUndefined(); /// @dev The input outside the acceptable domain. error OutOfDomain(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The scalar of ETH and most ERC20s. uint256 internal constant WAD = 1e18; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIMPLIFIED FIXED POINT OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `(x * y) / WAD` rounded down. function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if gt(x, div(not(0), y)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down. function sMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`. if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) { mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks. function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, y), WAD) } } /// @dev Equivalent to `(x * y) / WAD` rounded up. function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(y == 0 || x <= type(uint256).max / y)`. if iszero(eq(div(z, y), x)) { if y { mstore(0x00, 0xbac65e5b) // `MulWadFailed()`. revert(0x1c, 0x04) } } z := add(iszero(iszero(mod(z, WAD))), div(z, WAD)) } } /// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks. function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD)) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down. function sDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, WAD) // Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`. if iszero(mul(y, eq(sdiv(z, WAD), x))) { mstore(0x00, 0x5c43740d) // `SDivWadFailed()`. revert(0x1c, 0x04) } z := sdiv(z, y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks. function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(mul(x, WAD), y) } } /// @dev Equivalent to `(x * WAD) / y` rounded up. function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`. if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) { mstore(0x00, 0x7c5f487d) // `DivWadFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks. function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y)) } } /// @dev Equivalent to `x` to the power of `y`. /// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`. /// Note: This function is an approximation. function powWad(int256 x, int256 y) internal pure returns (int256) { // Using `ln(x)` means `x` must be greater than 0. return expWad((lnWad(x) * y) / int256(WAD)); } /// @dev Returns `exp(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function expWad(int256 x) internal pure returns (int256 r) { unchecked { // When the result is less than 0.5 we return zero. // This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`. if (x <= -41446531673892822313) return r; /// @solidity memory-safe-assembly assembly { // When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as // an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`. if iszero(slt(x, 135305999368893231589)) { mstore(0x00, 0xa37bfec9) // `ExpOverflow()`. revert(0x1c, 0x04) } } // `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96` // for more intermediate precision and a binary basis. This base conversion // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. x = (x << 78) / 5 ** 18; // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers // of two such that exp(x) = exp(x') * 2**k, where k is an integer. // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96; x = x - k * 54916777467707473351141471128; // `k` is in the range `[-61, 195]`. // Evaluate using a (6, 7)-term rational approximation. // `p` is made monic, we'll multiply by a scale factor later. int256 y = x + 1346386616545796478920950773328; y = ((y * x) >> 96) + 57155421227552351082224309758442; int256 p = y + x - 94201549194550492254356042504812; p = ((p * y) >> 96) + 28719021644029726153956944680412240; p = p * x + (4385272521454847904659076985693276 << 96); // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. int256 q = x - 2855989394907223263936484059900; q = ((q * x) >> 96) + 50020603652535783019961831881945; q = ((q * x) >> 96) - 533845033583426703283633433725380; q = ((q * x) >> 96) + 3604857256930695427073651918091429; q = ((q * x) >> 96) - 14423608567350463180887372962807573; q = ((q * x) >> 96) + 26449188498355588339934803723976023; /// @solidity memory-safe-assembly assembly { // Div in assembly because solidity adds a zero check despite the unchecked. // The q polynomial won't have zeros in the domain as all its roots are complex. // No scaling is necessary because p is already `2**96` too large. r := sdiv(p, q) } // r should be in the range `(0.09, 0.25) * 2**96`. // We now need to multiply r by: // - The scale factor `s ≈ 6.031367120`. // - The `2**k` factor from the range reduction. // - The `1e18 / 2**96` factor for base conversion. // We do this all at once, with an intermediate result in `2**213` // basis, so the final right shift is always by a positive amount. r = int256( (uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k) ); } } /// @dev Returns `ln(x)`, denominated in `WAD`. /// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln /// Note: This function is an approximation. Monotonically increasing. function lnWad(int256 x) internal pure returns (int256 r) { /// @solidity memory-safe-assembly assembly { // We want to convert `x` from `10**18` fixed point to `2**96` fixed point. // We do this by multiplying by `2**96 / 10**18`. But since // `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here // and add `ln(2**96 / 10**18)` at the end. // Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`. r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // We place the check here for more optimal stack operations. if iszero(sgt(x, 0)) { mstore(0x00, 0x1615e638) // `LnWadUndefined()`. revert(0x1c, 0x04) } // forgefmt: disable-next-item r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)) // Reduce range of x to (1, 2) * 2**96 // ln(2^k * x) = k * ln(2) + ln(x) x := shr(159, shl(r, x)) // Evaluate using a (8, 8)-term rational approximation. // `p` is made monic, we will multiply by a scale factor later. // forgefmt: disable-next-item let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir. sar(96, mul(add(43456485725739037958740375743393, sar(96, mul(add(24828157081833163892658089445524, sar(96, mul(add(3273285459638523848632254066296, x), x))), x))), x)), 11111509109440967052023855526967) p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857) p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526) p := sub(mul(p, x), shl(96, 795164235651350426258249787498)) // We leave `p` in `2**192` basis so we don't need to scale it back up for the division. // `q` is monic by convention. let q := add(5573035233440673466300451813936, x) q := add(71694874799317883764090561454958, sar(96, mul(x, q))) q := add(283447036172924575727196451306956, sar(96, mul(x, q))) q := add(401686690394027663651624208769553, sar(96, mul(x, q))) q := add(204048457590392012362485061816622, sar(96, mul(x, q))) q := add(31853899698501571402653359427138, sar(96, mul(x, q))) q := add(909429971244387300277376558375, sar(96, mul(x, q))) // `p / q` is in the range `(0, 0.125) * 2**96`. // Finalization, we need to: // - Multiply by the scale factor `s = 5.549…`. // - Add `ln(2**96 / 10**18)`. // - Add `k * ln(2)`. // - Multiply by `10**18 / 2**96 = 5**18 >> 78`. // The q polynomial is known not to have zeros in the domain. // No scaling required because p is already `2**96` too large. p := sdiv(p, q) // Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`. p := mul(1677202110996718588342820967067443963516166, p) // Add `ln(2) * k * 5**18 * 2**192`. // forgefmt: disable-next-item p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p) // Add `ln(2**96 / 10**18) * 5**18 * 2**192`. p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p) // Base conversion: mul `2**18 / 2**192`. r := sar(174, p) } } /// @dev Returns `W_0(x)`, denominated in `WAD`. /// See: https://en.wikipedia.org/wiki/Lambert_W_function /// a.k.a. Product log function. This is an approximation of the principal branch. /// Note: This function is an approximation. Monotonically increasing. function lambertW0Wad(int256 x) internal pure returns (int256 w) { // forgefmt: disable-next-item unchecked { if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`. (int256 wad, int256 p) = (int256(WAD), x); uint256 c; // Whether we need to avoid catastrophic cancellation. uint256 i = 4; // Number of iterations. if (w <= 0x1ffffffffffff) { if (-0x4000000000000 <= w) { i = 1; // Inputs near zero only take one step to converge. } else if (w <= -0x3ffffffffffffff) { i = 32; // Inputs near `-1/e` take very long to converge. } } else if (uint256(w >> 63) == uint256(0)) { /// @solidity memory-safe-assembly assembly { // Inline log2 for more performance, since the range is small. let v := shr(49, w) let l := shl(3, lt(0xff, v)) l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)), 49) w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13)) c := gt(l, 60) i := add(2, add(gt(l, 53), c)) } } else { int256 ll = lnWad(w = lnWad(w)); /// @solidity memory-safe-assembly assembly { // `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`. w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll)) i := add(3, iszero(shr(68, x))) c := iszero(shr(143, x)) } if (c == uint256(0)) { do { // If `x` is big, use Newton's so that intermediate values won't overflow. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := mul(w, div(e, wad)) w := sub(w, sdiv(sub(t, x), div(add(e, t), wad))) } if (p <= w) break; p = w; } while (--i != uint256(0)); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } return w; } } do { // Otherwise, use Halley's for faster convergence. int256 e = expWad(w); /// @solidity memory-safe-assembly assembly { let t := add(w, wad) let s := sub(mul(w, e), mul(x, wad)) w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t))))) } if (p <= w) break; p = w; } while (--i != c); /// @solidity memory-safe-assembly assembly { w := sub(w, sgt(w, 2)) } // For certain ranges of `x`, we'll use the quadratic-rate recursive formula of // R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation. if (c == uint256(0)) return w; int256 t = w | 1; /// @solidity memory-safe-assembly assembly { x := sdiv(mul(x, wad), t) } x = (t * (wad + lnWad(x))); /// @solidity memory-safe-assembly assembly { w := sdiv(x, add(wad, t)) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* GENERAL NUMBER UTILITIES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `a * b == x * y`, with full precision. function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0)))) } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // 512-bit multiply `[p1 p0] = x * y`. // Compute the product mod `2**256` and mod `2**256 - 1` // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that `product = p1 * 2**256 + p0`. // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. for {} 1 {} { // If overflows. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. /*------------------- 512 by 256 division --------------------*/ // Make division exact by subtracting the remainder from `[p1 p0]`. let r := mulmod(x, y, d) // Compute remainder using mulmod. let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`. // Make sure `z` is less than `2**256`. Also prevents `d == 0`. // Placing the check here seems to give more optimal stack operations. if iszero(gt(d, p1)) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } d := div(d, t) // Divide `d` by `t`, which is a power of two. // Invert `d mod 2**256` // Now that `d` is an odd number, it has an inverse // modulo `2**256` such that `d * inv = 1 mod 2**256`. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, `d * inv = 1 mod 2**4`. let inv := xor(2, mul(3, d)) // Now use 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. inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64 inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128 z := mul( // Divide [p1 p0] by the factors of two. // Shift in bits from `p1` into `p0`. For this we need // to flip `t` such that it is `2**256 / t`. or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256 ) break } z := div(z, d) break } } } /// @dev Calculates `floor(x * y / d)` with full precision. /// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits. /// Performs the full 512 bit calculation regardless. function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) let t := and(d, sub(0, d)) let r := mulmod(x, y, d) d := div(d, t) let inv := xor(2, mul(3, d)) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) inv := mul(inv, sub(2, mul(d, inv))) z := mul( or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)), mul(sub(2, mul(d, inv)), inv) ) } } /// @dev Calculates `floor(x * y / d)` with full precision, rounded up. /// Throws if result overflows a uint256 or when `d` is zero. /// Credit to Uniswap-v3-core under MIT license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { z = fullMulDiv(x, y, d); /// @solidity memory-safe-assembly assembly { if mulmod(x, y, d) { z := add(z, 1) if iszero(z) { mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } } } } /// @dev Calculates `floor(x * y / 2 ** n)` with full precision. /// Throws if result overflows a uint256. /// Credit to Philogy under MIT license: /// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Temporarily use `z` as `p0` to save gas. z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`. for {} 1 {} { if iszero(or(iszero(x), eq(div(z, x), y))) { let k := and(n, 0xff) // `n`, cleaned. let mm := mulmod(x, y, not(0)) let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`. // | p1 | z | // Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 | // Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 | // Check that final `z` doesn't overflow by checking that p1_0 = 0. if iszero(shr(k, p1)) { z := add(shl(sub(256, k), p1), shr(k, z)) break } mstore(0x00, 0xae47f702) // `FullMulDivFailed()`. revert(0x1c, 0x04) } z := shr(and(n, 0xff), z) break } } } /// @dev Returns `floor(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := div(z, d) } } /// @dev Returns `ceil(x * y / d)`. /// Reverts if `x * y` overflows, or `d` is zero. function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(x, y) // Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`. if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) { mstore(0x00, 0xad251c27) // `MulDivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(z, d))), div(z, d)) } } /// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`. function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) { /// @solidity memory-safe-assembly assembly { let g := n let r := mod(a, n) for { let y := 1 } 1 {} { let q := div(g, r) let t := g g := r r := sub(t, mul(r, q)) let u := x x := y y := sub(u, mul(y, q)) if iszero(r) { break } } x := mul(eq(g, 1), add(x, mul(slt(x, 0), n))) } } /// @dev Returns `ceil(x / d)`. /// Reverts if `d` is zero. function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { if iszero(d) { mstore(0x00, 0x65244e4e) // `DivFailed()`. revert(0x1c, 0x04) } z := add(iszero(iszero(mod(x, d))), div(x, d)) } } /// @dev Returns `max(0, x - y)`. Alias for `saturatingSub`. function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `max(0, x - y)`. function saturatingSub(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(gt(x, y), sub(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x + y)`. function saturatingAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(0, lt(add(x, y), x)), add(x, y)) } } /// @dev Returns `min(2 ** 256 - 1, x * y)`. function saturatingMul(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(sub(or(iszero(x), eq(div(mul(x, y), x), y)), 1), mul(x, y)) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `condition ? x : y`, without branching. function ternary(bool condition, address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), iszero(condition))) } } /// @dev Returns `x != 0 ? x : y`, without branching. function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != bytes32(0) ? x : y`, without branching. function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(x))) } } /// @dev Returns `x != address(0) ? x : y`, without branching. function coalesce(address x, address y) internal pure returns (address z) { /// @solidity memory-safe-assembly assembly { z := or(x, mul(y, iszero(shl(96, x)))) } } /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`. if x { z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x` let half := shr(1, b) // Divide `b` by 2. // Divide `y` by 2 every iteration. for { y := shr(1, y) } y { y := shr(1, y) } { let xx := mul(x, x) // Store x squared. let xxRound := add(xx, half) // Round to the nearest number. // Revert if `xx + half` overflowed, or if `x ** 2` overflows. if or(lt(xxRound, xx), shr(128, x)) { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } x := div(xxRound, b) // Set `x` to scaled `xxRound`. // If `y` is odd: if and(y, 1) { let zx := mul(z, x) // Compute `z * x`. let zxRound := add(zx, half) // Round to the nearest number. // If `z * x` overflowed or `zx + half` overflowed: if or(xor(div(zx, x), z), lt(zxRound, zx)) { // Revert if `x` is non-zero. if x { mstore(0x00, 0x49f7642b) // `RPowOverflow()`. revert(0x1c, 0x04) } } z := div(zxRound, b) // Return properly scaled `zxRound`. } } } } } /// @dev Returns the square root of `x`, rounded down. function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // Let `y = x / 2**r`. We check `y >= 2**(k + 8)` // but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`. let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffffff, shr(r, x)))) z := shl(shr(1, r), z) // Goal was to get `z*z*y` within a small factor of `x`. More iterations could // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`. // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small. // That's not possible if `x < 256` but we can just verify those cases exhaustively. // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`. // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`. // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps. // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)` // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`, // with largest error when `s = 1` and when `s = 256` or `1/256`. // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`. // Then we can estimate `sqrt(y)` using // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`. // There is no overflow risk here since `y < 2**136` after the first branch above. z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If `x+1` is a perfect square, the Babylonian method cycles between // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division z := sub(z, lt(div(x, z), z)) } } /// @dev Returns the cube root of `x`, rounded down. /// Credit to bout3fiddy and pcaversaccio under AGPLv3 license: /// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // Makeshift lookup table to nudge the approximate log2 result. z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3))) // Newton-Raphson's. z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) z := div(add(add(div(x, mul(z, z)), z), z), 3) // Round down. z := sub(z, lt(div(x, mul(z, z)), z)) } } /// @dev Returns the square root of `x`, denominated in `WAD`, rounded down. function sqrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18); z = (1 + sqrt(x)) * 10 ** 9; z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1; } /// @solidity memory-safe-assembly assembly { z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down. } } /// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down. /// Formally verified by xuwinnie: /// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf function cbrtWad(uint256 x) internal pure returns (uint256 z) { unchecked { if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36); z = (1 + cbrt(x)) * 10 ** 12; z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3; } /// @solidity memory-safe-assembly assembly { let p := x for {} 1 {} { if iszero(shr(229, p)) { if iszero(shr(199, p)) { p := mul(p, 100000000000000000) // 10 ** 17. break } p := mul(p, 100000000) // 10 ** 8. break } if iszero(shr(249, p)) { p := mul(p, 100) } break } let t := mulmod(mul(z, z), z, p) z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down. } } /// @dev Returns the factorial of `x`. function factorial(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := 1 if iszero(lt(x, 58)) { mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`. revert(0x1c, 0x04) } for {} x { x := sub(x, 1) } { z := mul(z, x) } } } /// @dev Returns the log2 of `x`. /// Equivalent to computing the index of the most significant bit (MSB) of `x`. /// Returns 0 if `x` is zero. function log2(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)), 0x0706060506020504060203020504030106050205030304010505030400000000)) } } /// @dev Returns the log2 of `x`, rounded up. /// Returns 0 if `x` is zero. function log2Up(uint256 x) internal pure returns (uint256 r) { r = log2(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(r, 1), x)) } } /// @dev Returns the log10 of `x`. /// Returns 0 if `x` is zero. function log10(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { if iszero(lt(x, 100000000000000000000000000000000000000)) { x := div(x, 100000000000000000000000000000000000000) r := 38 } if iszero(lt(x, 100000000000000000000)) { x := div(x, 100000000000000000000) r := add(r, 20) } if iszero(lt(x, 10000000000)) { x := div(x, 10000000000) r := add(r, 10) } if iszero(lt(x, 100000)) { x := div(x, 100000) r := add(r, 5) } r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999))))) } } /// @dev Returns the log10 of `x`, rounded up. /// Returns 0 if `x` is zero. function log10Up(uint256 x) internal pure returns (uint256 r) { r = log10(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(exp(10, r), x)) } } /// @dev Returns the log256 of `x`. /// Returns 0 if `x` is zero. function log256(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(shr(3, r), lt(0xff, shr(r, x))) } } /// @dev Returns the log256 of `x`, rounded up. /// Returns 0 if `x` is zero. function log256Up(uint256 x) internal pure returns (uint256 r) { r = log256(x); /// @solidity memory-safe-assembly assembly { r := add(r, lt(shl(shl(3, r), 1), x)) } } /// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`. /// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent). function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) { /// @solidity memory-safe-assembly assembly { mantissa := x if mantissa { if iszero(mod(mantissa, 1000000000000000000000000000000000)) { mantissa := div(mantissa, 1000000000000000000000000000000000) exponent := 33 } if iszero(mod(mantissa, 10000000000000000000)) { mantissa := div(mantissa, 10000000000000000000) exponent := add(exponent, 19) } if iszero(mod(mantissa, 1000000000000)) { mantissa := div(mantissa, 1000000000000) exponent := add(exponent, 12) } if iszero(mod(mantissa, 1000000)) { mantissa := div(mantissa, 1000000) exponent := add(exponent, 6) } if iszero(mod(mantissa, 10000)) { mantissa := div(mantissa, 10000) exponent := add(exponent, 4) } if iszero(mod(mantissa, 100)) { mantissa := div(mantissa, 100) exponent := add(exponent, 2) } if iszero(mod(mantissa, 10)) { mantissa := div(mantissa, 10) exponent := add(exponent, 1) } } } } /// @dev Convenience function for packing `x` into a smaller number using `sci`. /// The `mantissa` will be in bits [7..255] (the upper 249 bits). /// The `exponent` will be in bits [0..6] (the lower 7 bits). /// Use `SafeCastLib` to safely ensure that the `packed` number is small /// enough to fit in the desired unsigned integer type: /// ``` /// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether)); /// ``` function packSci(uint256 x) internal pure returns (uint256 packed) { (x, packed) = sci(x); // Reuse for `mantissa` and `exponent`. /// @solidity memory-safe-assembly assembly { if shr(249, x) { mstore(0x00, 0xce30380c) // `MantissaOverflow()`. revert(0x1c, 0x04) } packed := or(shl(7, x), packed) } } /// @dev Convenience function for unpacking a packed number from `packSci`. function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) { unchecked { unpacked = (packed >> 7) * 10 ** (packed & 0x7f); } } /// @dev Returns the average of `x` and `y`. Rounds towards zero. function avg(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = (x & y) + ((x ^ y) >> 1); } } /// @dev Returns the average of `x` and `y`. Rounds towards negative infinity. function avg(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = (x >> 1) + (y >> 1) + (x & y & 1); } } /// @dev Returns the absolute value of `x`. function abs(int256 x) internal pure returns (uint256 z) { unchecked { z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255); } } /// @dev Returns the absolute distance between `x` and `y`. function dist(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y)) } } /// @dev Returns the absolute distance between `x` and `y`. function dist(int256 x, int256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y)) } } /// @dev Returns the minimum of `x` and `y`. function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @dev Returns the minimum of `x` and `y`. function min(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), slt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } /// @dev Returns the maximum of `x` and `y`. function max(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, y), sgt(y, x))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(uint256 x, uint256 minValue, uint256 maxValue) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), gt(minValue, x))) z := xor(z, mul(xor(z, maxValue), lt(maxValue, z))) } } /// @dev Returns `x`, bounded to `minValue` and `maxValue`. function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := xor(x, mul(xor(x, minValue), sgt(minValue, x))) z := xor(z, mul(xor(z, maxValue), slt(maxValue, z))) } } /// @dev Returns greatest common divisor of `x` and `y`. function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { for { z := x } y {} { let t := y y := mod(z, y) z := t } } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`, /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end) internal pure returns (uint256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; unchecked { if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin); return a - fullMulDiv(a - b, t - begin, end - begin); } } /// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`. /// with `t` clamped between `begin` and `end` (inclusive). /// Agnostic to the order of (`a`, `b`) and (`end`, `begin`). /// If `begins == end`, returns `t <= begin ? a : b`. function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end) internal pure returns (int256) { if (begin > end) (t, begin, end) = (~t, ~begin, ~end); if (t <= begin) return a; if (t >= end) return b; // forgefmt: disable-next-item unchecked { if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a), uint256(t - begin), uint256(end - begin))); return int256(uint256(a) - fullMulDiv(uint256(a - b), uint256(t - begin), uint256(end - begin))); } } /// @dev Returns if `x` is an even number. Some people may need this. function isEven(uint256 x) internal pure returns (bool) { return x & uint256(1) == uint256(0); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RAW NUMBER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `x + y`, without checking for overflow. function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x + y; } } /// @dev Returns `x + y`, without checking for overflow. function rawAdd(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x + y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x - y; } } /// @dev Returns `x - y`, without checking for underflow. function rawSub(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x - y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) { unchecked { z = x * y; } } /// @dev Returns `x * y`, without checking for overflow. function rawMul(int256 x, int256 y) internal pure returns (int256 z) { unchecked { z = x * y; } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := div(x, y) } } /// @dev Returns `x / y`, returning 0 if `y` is zero. function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := sdiv(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mod(x, y) } } /// @dev Returns `x % y`, returning 0 if `y` is zero. function rawSMod(int256 x, int256 y) internal pure returns (int256 z) { /// @solidity memory-safe-assembly assembly { z := smod(x, y) } } /// @dev Returns `(x + y) % d`, return 0 if `d` if zero. function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := addmod(x, y, d) } } /// @dev Returns `(x * y) % d`, return 0 if `d` if zero. function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { z := mulmod(x, y, d) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {CallContextChecker} from "./CallContextChecker.sol"; /// @notice UUPS proxy mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol) /// @author Modified from OpenZeppelin /// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol) /// /// @dev Note: /// - This implementation is intended to be used with ERC1967 proxies. /// See: `LibClone.deployERC1967` and related functions. /// - This implementation is NOT compatible with legacy OpenZeppelin proxies /// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`. abstract contract UUPSUpgradeable is CallContextChecker { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The upgrade failed. error UpgradeFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when the proxy's implementation is upgraded. event Upgraded(address indexed implementation); /// @dev `keccak256(bytes("Upgraded(address)"))`. uint256 private constant _UPGRADED_EVENT_SIGNATURE = 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ERC-1967 storage slot for the implementation in the proxy. /// `uint256(keccak256("eip1967.proxy.implementation")) - 1`. bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UUPS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to check if `msg.sender` is authorized /// to upgrade the proxy to `newImplementation`, reverting if not. /// ``` /// function _authorizeUpgrade(address) internal override onlyOwner {} /// ``` function _authorizeUpgrade(address newImplementation) internal virtual; /// @dev Returns the storage slot used by the implementation, /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822). /// /// Note: The `notDelegated` modifier prevents accidental upgrades to /// an implementation that is a proxy contract. function proxiableUUID() public view virtual notDelegated returns (bytes32) { // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967. return _ERC1967_IMPLEMENTATION_SLOT; } /// @dev Upgrades the proxy's implementation to `newImplementation`. /// Emits a {Upgraded} event. /// /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`. function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); /// @solidity memory-safe-assembly assembly { newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits. mstore(0x00, returndatasize()) mstore(0x01, 0x52d1902d) // `proxiableUUID()`. let s := _ERC1967_IMPLEMENTATION_SLOT // Check if `newImplementation` implements `proxiableUUID` correctly. if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) { mstore(0x01, 0x55299b49) // `UpgradeFailed()`. revert(0x1d, 0x04) } // Emit the {Upgraded} event. log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation) sstore(s, newImplementation) // Updates the implementation. // Perform a delegatecall to `newImplementation` if `data` is non-empty. if data.length { // Forwards the `data` to `newImplementation` via delegatecall. let m := mload(0x40) calldatacopy(m, data.offset, data.length) if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Initializable mixin for the upgradeable contracts. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol) abstract contract Initializable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The contract is already initialized. error InvalidInitialization(); /// @dev The contract is not initializing. error NotInitializing(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Triggered when the contract has been initialized. event Initialized(uint64 version); /// @dev `keccak256(bytes("Initialized(uint64)"))`. bytes32 private constant _INTIALIZED_EVENT_SIGNATURE = 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default initializable slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_INITIALIZABLE_SLOT")))))`. /// /// Bits Layout: /// - [0] `initializing` /// - [1..64] `initializedVersion` bytes32 private constant _INITIALIZABLE_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ constructor() { // Construction time check to ensure that `_initializableSlot()` is not // overridden to zero. Will be optimized away if there is no revert. require(_initializableSlot() != bytes32(0)); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return a non-zero custom storage slot if required. function _initializableSlot() internal pure virtual returns (bytes32) { return _INITIALIZABLE_SLOT; } /// @dev Guards an initializer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `initializer`. /// /// This is similar to `reinitializer(1)`, except that in the context of a constructor, /// an `initializer` guarded function can be invoked multiple times. /// This can be useful during testing and is not expected to be used in production. /// /// Emits an {Initialized} event. modifier initializer() virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) // Set `initializing` to 1, `initializedVersion` to 1. sstore(s, 3) // If `!(initializing == 0 && initializedVersion == 0)`. if i { // If `!(address(this).code.length == 0 && initializedVersion == 1)`. if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`. } } _; /// @solidity memory-safe-assembly assembly { if s { // Set `initializing` to 0, `initializedVersion` to 1. sstore(s, 2) // Emit the {Initialized} event. mstore(0x20, 1) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Guards an reinitialzer function so that it can be invoked at most once. /// /// You can guard a function with `onlyInitializing` such that it can be called /// through a function guarded with `reinitializer`. /// /// Emits an {Initialized} event. modifier reinitializer(uint64 version) virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { // Clean upper bits, and shift left by 1 to make space for the initializing bit. version := shl(1, and(version, 0xffffffffffffffff)) let i := sload(s) // If `initializing == 1 || initializedVersion >= version`. if iszero(lt(and(i, 1), lt(i, version))) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } // Set `initializing` to 1, `initializedVersion` to `version`. sstore(s, or(1, version)) } _; /// @solidity memory-safe-assembly assembly { // Set `initializing` to 0, `initializedVersion` to `version`. sstore(s, version) // Emit the {Initialized} event. mstore(0x20, shr(1, version)) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } /// @dev Guards a function such that it can only be called in the scope /// of a function guarded with `initializer` or `reinitializer`. modifier onlyInitializing() virtual { _checkInitializing(); _; } /// @dev Reverts if the contract is not initializing. function _checkInitializing() internal view virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { if iszero(and(1, sload(s))) { mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`. revert(0x1c, 0x04) } } } /// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`. /// /// Calling this in the constructor will prevent the contract from being initialized /// or reinitialized. 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 called. function _disableInitializers() internal virtual { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { let i := sload(s) if and(i, 1) { mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`. revert(0x1c, 0x04) } let uint64max := 0xffffffffffffffff if iszero(eq(shr(1, i), uint64max)) { // Set `initializing` to 0, `initializedVersion` to `2**64 - 1`. sstore(s, shl(1, uint64max)) // Emit the {Initialized} event. mstore(0x20, uint64max) log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE) } } } /// @dev Returns the highest version that has been initialized. function _getInitializedVersion() internal view virtual returns (uint64 version) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { version := shr(1, sload(s)) } } /// @dev Returns whether the contract is currently initializing. function _isInitializing() internal view virtual returns (bool result) { bytes32 s = _initializableSlot(); /// @solidity memory-safe-assembly assembly { result := and(1, sload(s)) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {Ownable} from "./Ownable.sol"; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Overwrite the roles directly without authorization guard. function _setRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Store the new value. sstore(keccak256(0x0c, 0x20), roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Updates the roles directly without authorization guard. /// If `on` is true, each set bit of `roles` will be turned on, /// otherwise, each set bit of `roles` will be turned off. function _updateRoles(address user, uint256 roles, bool on) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let current := sload(roleSlot) // Compute the updated roles if `on` is true. let updated := or(current, roles) // Compute the updated roles if `on` is false. // Use `and` to compute the intersection of `current` and `roles`, // `xor` it with `current` to flip the bits in the intersection. if iszero(on) { updated := xor(current, and(current, roles)) } // Then, store the new value. sstore(roleSlot, updated) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) } } /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, true); } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, false); } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles != 0; } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles == roles; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Contract for EIP-712 typed structured data hashing and signing. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol) /// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol) /// /// @dev Note, this implementation: /// - Uses `address(this)` for the `verifyingContract` field. /// - Does NOT use the optional EIP-712 salt. /// - Does NOT use any EIP-712 extensions. /// This is for simplicity and to save gas. /// If you need to customize, please fork / modify accordingly. abstract contract EIP712 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev `keccak256("EIP712Domain(string name,string version,address verifyingContract)")`. /// This is only used in `_hashTypedDataSansChainId`. bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID = 0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766; uint256 private immutable _cachedThis; uint256 private immutable _cachedChainId; bytes32 private immutable _cachedNameHash; bytes32 private immutable _cachedVersionHash; bytes32 private immutable _cachedDomainSeparator; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Cache the hashes for cheaper runtime gas costs. /// In the case of upgradeable contracts (i.e. proxies), /// or if the chain id changes due to a hard fork, /// the domain separator will be seamlessly calculated on-the-fly. constructor() { _cachedThis = uint256(uint160(address(this))); _cachedChainId = block.chainid; string memory name; string memory version; if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion(); bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name)); bytes32 versionHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version)); _cachedNameHash = nameHash; _cachedVersionHash = versionHash; bytes32 separator; if (!_domainNameAndVersionMayChange()) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } _cachedDomainSeparator = separator; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTIONS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to return the domain name and version. /// ``` /// function _domainNameAndVersion() /// internal /// pure /// virtual /// returns (string memory name, string memory version) /// { /// name = "Solady"; /// version = "1"; /// } /// ``` /// /// Note: If the returned result may change after the contract has been deployed, /// you must override `_domainNameAndVersionMayChange()` to return true. function _domainNameAndVersion() internal view virtual returns (string memory name, string memory version); /// @dev Returns if `_domainNameAndVersion()` may change /// after the contract has been deployed (i.e. after the constructor). /// Default: false. function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _domainSeparator() internal view virtual returns (bytes32 separator) { if (_domainNameAndVersionMayChange()) { separator = _buildDomainSeparator(); } else { separator = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator(); } } /// @dev Returns the hash of the fully encoded EIP-712 message for this domain, /// given `structHash`, as defined in /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. /// /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message: /// ``` /// bytes32 digest = _hashTypedData(keccak256(abi.encode( /// keccak256("Mail(address to,string contents)"), /// mailTo, /// keccak256(bytes(mailContents)) /// ))); /// address signer = ECDSA.recover(digest, signature); /// ``` function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) { // We will use `digest` to store the domain separator to save a bit of gas. if (_domainNameAndVersionMayChange()) { digest = _buildDomainSeparator(); } else { digest = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator(); } /// @solidity memory-safe-assembly assembly { // Compute the digest. mstore(0x00, 0x1901000000000000) // Store "\x19\x01". mstore(0x1a, digest) // Store the domain separator. mstore(0x3a, structHash) // Store the struct hash. digest := keccak256(0x18, 0x42) // Restore the part of the free memory slot that was overwritten. mstore(0x3a, 0) } } /// @dev Variant of `_hashTypedData` that excludes the chain ID. /// We expect that most contracts will use `_hashTypedData` as the main hash, /// and `_hashTypedDataSansChainId` only occasionally for cross-chain workflows. /// Thus this is optimized for smaller bytecode size over runtime gas. function _hashTypedDataSansChainId(bytes32 structHash) internal view virtual returns (bytes32 digest) { (string memory name, string memory version) = _domainNameAndVersion(); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(0x00, _DOMAIN_TYPEHASH_SANS_CHAIN_ID) mstore(0x20, keccak256(add(name, 0x20), mload(name))) mstore(0x40, keccak256(add(version, 0x20), mload(version))) mstore(0x60, address()) // Compute the digest. mstore(0x20, keccak256(0x00, 0x80)) // Store the domain separator. mstore(0x00, 0x1901) // Store "\x19\x01". mstore(0x40, structHash) // Store the struct hash. digest := keccak256(0x1e, 0x42) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-5267 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev See: https://eips.ethereum.org/EIPS/eip-5267 function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { fields = hex"0f"; // `0b01111`. (name, version) = _domainNameAndVersion(); chainId = block.chainid; verifyingContract = address(this); salt = salt; // `bytes32(0)`. extensions = extensions; // `new uint256[](0)`. } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _buildDomainSeparator() private view returns (bytes32 separator) { // We will use `separator` to store the name hash to save a bit of gas. bytes32 versionHash; if (_domainNameAndVersionMayChange()) { (string memory name, string memory version) = _domainNameAndVersion(); separator = keccak256(bytes(name)); versionHash = keccak256(bytes(version)); } else { separator = _cachedNameHash; versionHash = _cachedVersionHash; } /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), separator) // Name hash. mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } /// @dev Returns if the cached domain separator has been invalidated. function _cachedDomainSeparatorInvalidated() private view returns (bool result) { uint256 cachedChainId = _cachedChainId; uint256 cachedThis = _cachedThis; /// @solidity memory-safe-assembly assembly { result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis))) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import "solady/utils/MerkleProofLib.sol"; import "solady/utils/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; import {BaseDistributor} from "./BaseDistributor.sol"; // ____ _ _ // / ___| (_) __ _ _ _ ___ // | | | | |/ _` | | | |/ _ \ // | |___| | | (_| | |_| | __/ // \____|_|_|\__, |\__,_|\___| _ _ __ __ ____ // | _ \(_)___| |_|_ __(_) |__ _ _| |_ ___ _ __ / | | \/ |/ ___| // | | | | / __| __| '__| | '_ \| | | | __/ _ \| '__| | |_____| |\/| | | // | |_| | \__ \ |_| | | | |_) | |_| | || (_) | | | |_____| | | | |___ // |____/|_|___/\__|_| |_|_.__/ \__,_|\__\___/|_| |_| |_| |_|\____| /// @title Distributor1MC /// @notice Clique Airdrop contract (Mekle + ECDSA), allows for multiple claims /// @author Clique (@Clique2046) /// @author Eillo (@0xEillo) contract Distributor is BaseDistributor { using SafeERC20 for IERC20; error InvalidMerkleRoot(); constructor(address _signer, address _token, address _projectAdmin, address _vault) BaseDistributor(_signer, _token, _projectAdmin, _vault) {} function _execute(address _vault, address _recipient, address _token, bytes32 _configurator, uint256 _amount) internal override { if (_configurator != bytes32(uint256(1))) { revert InvalidMerkleRoot(); } IERC20 token = IERC20(_token); token.safeTransferFrom(_vault, _recipient, _amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized ECDSA wrapper. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) /// /// @dev Note: /// - The recovery functions use the ecrecover precompile (0x1). /// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure. /// This is for more safety by default. /// Use the `tryRecover` variants if you need to get the zero address back /// upon recovery failure instead. /// - As of Solady version 0.0.134, all `bytes signature` variants accept both /// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// This is for calldata efficiency on smart accounts prevalent on L2s. /// /// WARNING! Do NOT directly use signatures as unique identifiers: /// - The recovery operations do NOT check if a signature is non-malleable. /// - Use a nonce in the digest to prevent replay attacks on the same contract. /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts. /// EIP-712 also enables readable signing of typed data for better user safety. /// - If you need a unique hash from a signature, please use the `canonicalHash` functions. library ECDSA { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The order of the secp256k1 elliptic curve. uint256 internal constant N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141; /// @dev `N/2 + 1`. Used for checking the malleability of the signature. uint256 private constant _HALF_N_PLUS_1 = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The signature is invalid. error InvalidSignature(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RECOVERY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { let m := mload(0x40) } 1 { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } { switch mload(signature) case 64 { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. } default { continue } mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if returndatasize() { break } } } } /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function recoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { let m := mload(0x40) } 1 { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } { switch signature.length case 64 { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. } default { continue } mstore(0x00, hash) result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if returndatasize() { break } } } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) result := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* TRY-RECOVER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // WARNING! // These functions will NOT revert upon recovery failure. // Instead, they will return the zero address upon recovery failure. // It is critical that the returned address is NEVER compared against // a zero address (e.g. an uninitialized address variable). /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function tryRecover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { let m := mload(0x40) } 1 {} { switch mload(signature) case 64 { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. } default { break } mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20)) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function tryRecoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { for { let m := mload(0x40) } 1 {} { switch signature.length case 64 { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. } default { break } mstore(0x00, hash) pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20)) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20)) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) pop(staticcall(gas(), 1, 0x00, 0x80, 0x40, 0x20)) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 {} { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CANONICAL HASH FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // The following functions returns the hash of the signature in it's canonicalized format, // which is the 65-byte `abi.encodePacked(r, s, uint8(v))`, where `v` is either 27 or 28. // If `s` is greater than `N / 2` then it will be converted to `N - s` // and the `v` value will be flipped. // If the signature has an invalid length, or if `v` is invalid, // a uniquely corrupt hash will be returned. // These functions are useful for "poor-mans-VRF". /// @dev Returns the canonical hash of `signature`. function canonicalHash(bytes memory signature) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let l := mload(signature) for {} 1 {} { mstore(0x00, mload(add(signature, 0x20))) // `r`. let s := mload(add(signature, 0x40)) let v := mload(add(signature, 0x41)) if eq(l, 64) { v := add(shr(255, s), 27) s := shr(1, shl(1, s)) } if iszero(lt(s, _HALF_N_PLUS_1)) { v := xor(v, 7) s := sub(N, s) } mstore(0x21, v) mstore(0x20, s) result := keccak256(0x00, 0x41) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. break } // If the length is neither 64 nor 65, return a uniquely corrupted hash. if iszero(lt(sub(l, 64), 2)) { // `bytes4(keccak256("InvalidSignatureLength"))`. result := xor(keccak256(add(signature, 0x20), l), 0xd62f1ab2) } } } /// @dev Returns the canonical hash of `signature`. function canonicalHashCalldata(bytes calldata signature) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { mstore(0x00, calldataload(signature.offset)) // `r`. let s := calldataload(add(signature.offset, 0x20)) let v := calldataload(add(signature.offset, 0x21)) if eq(signature.length, 64) { v := add(shr(255, s), 27) s := shr(1, shl(1, s)) } if iszero(lt(s, _HALF_N_PLUS_1)) { v := xor(v, 7) s := sub(N, s) } mstore(0x21, v) mstore(0x20, s) result := keccak256(0x00, 0x41) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. break } // If the length is neither 64 nor 65, return a uniquely corrupted hash. if iszero(lt(sub(signature.length, 64), 2)) { calldatacopy(mload(0x40), signature.offset, signature.length) // `bytes4(keccak256("InvalidSignatureLength"))`. result := xor(keccak256(mload(0x40), signature.length), 0xd62f1ab2) } } } /// @dev Returns the canonical hash of `signature`. function canonicalHash(bytes32 r, bytes32 vs) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, r) // `r`. let v := add(shr(255, vs), 27) let s := shr(1, shl(1, vs)) mstore(0x21, v) mstore(0x20, s) result := keccak256(0x00, 0x41) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /// @dev Returns the canonical hash of `signature`. function canonicalHash(uint8 v, bytes32 r, bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, r) // `r`. if iszero(lt(s, _HALF_N_PLUS_1)) { v := xor(v, 7) s := sub(N, s) } mstore(0x21, v) mstore(0x20, s) result := keccak256(0x00, 0x41) mstore(0x21, 0) // Restore the overwritten part of the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import "solady/utils/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; import {StreamConfig, ICliqueLock} from "../ICliqueLock.sol"; import {BaseDistributor} from "./BaseDistributor.sol"; interface IVestingConfigurator { function makeStreamConfig(address _recipient, uint256 _amount) external view returns (StreamConfig memory streamConfig); } /// @title Vested Distributor /// @author Clique (@Clique2046) /// @author Alan (@alannotnerd) contract VestedDistributor is BaseDistributor { using SafeERC20 for IERC20; address public immutable lock; error MismatchedToken(address actual, address expected); constructor(address _signer, address _token, address _projectAdmin, address _vault, address _lock) BaseDistributor(_signer, _token, _projectAdmin, _vault) { lock = _lock; } function _execute(address _vault, address _recipient, address _token, bytes32 _configurator, uint256 _amount) internal override { IERC20 token = IERC20(_token); address configurator = address(uint160(uint256(_configurator))); StreamConfig memory _streamConfig = IVestingConfigurator(configurator).makeStreamConfig(_recipient, _amount); if (_streamConfig.token != _token) revert MismatchedToken(_streamConfig.token, _token); token.safeTransferFrom(_vault, address(this), _streamConfig.amount); token.approve(lock, _streamConfig.amount); ICliqueLock(lock).createStream(_streamConfig); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Call context checker mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/CallContextChecker.sol) contract CallContextChecker { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The call is from an unauthorized call context. error UnauthorizedCallContext(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev For checking if the context is a delegate call. /// /// Note: To enable use cases with an immutable default implementation in the bytecode, /// (see: ERC6551Proxy), we don't require that the proxy address must match the /// value stored in the implementation slot, which may not be initialized. uint256 private immutable __self = uint256(uint160(address(this))); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CALL CONTEXT CHECKS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // A proxy call can be either via a `delegatecall` to an implementation, // or a 7702 call on an authority that points to a delegation. /// @dev Returns whether the current call context is on a EIP7702 authority /// (i.e. externally owned account). function _onEIP7702Authority() internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { extcodecopy(address(), 0x00, 0x00, 0x20) // Note: Checking that it starts with hex"ef01" is the most general and futureproof. // 7702 bytecode is `abi.encodePacked(hex"ef01", uint8(version), address(delegation))`. result := eq(0xef01, shr(240, mload(0x00))) } } /// @dev Returns the implementation of this contract. function _selfImplementation() internal view virtual returns (address) { return address(uint160(__self)); } /// @dev Returns whether the current call context is on the implementation itself. function _onImplementation() internal view virtual returns (bool) { return __self == uint160(address(this)); } /// @dev Requires that the current call context is performed via a EIP7702 authority. function _checkOnlyEIP7702Authority() internal view virtual { if (!_onEIP7702Authority()) _revertUnauthorizedCallContext(); } /// @dev Requires that the current call context is performed via a proxy. function _checkOnlyProxy() internal view virtual { if (_onImplementation()) _revertUnauthorizedCallContext(); } /// @dev Requires that the current call context is NOT performed via a proxy. /// This is the opposite of `checkOnlyProxy`. function _checkNotDelegated() internal view virtual { if (!_onImplementation()) _revertUnauthorizedCallContext(); } /// @dev Requires that the current call context is performed via a EIP7702 authority. modifier onlyEIP7702Authority() virtual { _checkOnlyEIP7702Authority(); _; } /// @dev Requires that the current call context is performed via a proxy. modifier onlyProxy() virtual { _checkOnlyProxy(); _; } /// @dev Requires that the current call context is NOT performed via a proxy. /// This is the opposite of `onlyProxy`. modifier notDelegated() virtual { _checkNotDelegated(); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function _revertUnauthorizedCallContext() private pure { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`. revert(0x1c, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; import "solady/utils/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; import {StreamConfig, ICliqueLock} from "../ICliqueLock.sol"; /// @title Base Distributor /// @author Clique (@Clique2046) /// @author Alan (@alannotnerd) abstract contract BaseDistributor is OwnableRoles { using SafeERC20 for IERC20; // token to be airdroppped address public token; // address signing the claims address public signer; // vault address address public vault; // whether the airdrop is active bool public active = false; mapping(bytes32 => mapping(address => uint256)) public claimed; mapping(bytes32 => bytes32) public merkleConfiguration; // errors error AlreadyClaimed(); error InvalidSignature(); error NotActive(); error ZeroAddress(); error InvalidMerkleProof(bytes32 root); error WithdrawFailed(); error IncorrectFee(); event AirdropClaimed(address indexed account, uint256 amount); event MerkleConfigurationUpdate(bytes32 indexed root, bytes32 indexed configurator); event Withdraw(address indexed to, uint256 amount); event FeeSet(uint256 fee); event VaultSet(address indexed vault); uint256 public constant PROJECT_ADMIN = _ROLE_0; /// @notice Construct a new Claim contract /// @param _signer address that can sign messages /// @param _token address of the token that will be claimed /// @param _projectAdmin address that can set the signer and claim root constructor(address _signer, address _token, address _projectAdmin, address _vault) { if (_token == address(0)) revert ZeroAddress(); signer = _signer; token = _token; vault = _vault; _initializeOwner(msg.sender); _setRoles(_projectAdmin, PROJECT_ADMIN); } /// @notice Modifier to check if the airdrop is active modifier whenActive() { if (!active) revert NotActive(); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ADMIN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Set the signer /// @param _signer address that can sign messages function setSigner(address _signer) external onlyRoles(PROJECT_ADMIN) { signer = _signer; } /// @notice Set the claim root /// @param _claimRoot root of the merkle tree function setClaimRoot(bytes32 _claimRoot, bytes32 _configurator) external onlyRoles(PROJECT_ADMIN) { merkleConfiguration[_claimRoot] = _configurator; emit MerkleConfigurationUpdate(_claimRoot, _configurator); } /// @notice Set the vault /// @param _vault address of the vault function setVault(address _vault) external onlyRoles(PROJECT_ADMIN) { vault = _vault; emit VaultSet(_vault); } /// @notice Toggle the active state function toggleActive() external onlyRoles(PROJECT_ADMIN) { active = !active; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FEE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Withdraw the fee /// @dev Only callable by the owner function withdrawFee(address _recipient) external onlyOwner { uint256 _balance = address(this).balance; if (_balance > 0) { (bool _success,) = payable(_recipient).call{value: _balance}(""); if (!_success) revert WithdrawFailed(); emit Withdraw(_recipient, _balance); } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EXTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Claim airdrop tokens. Checks for both merkle proof // and signature validation /// @param _proof merkle proof of the claim /// @param _signature signature of the claim /// @param _amount amount of tokens to claim /// @param _onBehalfOf address to claim on behalf of function claim(bytes32[] calldata _proof, bytes calldata _signature, uint256 _amount, address _onBehalfOf) external payable whenActive { (bytes32 _root, bytes32 _configurator) = _rootCheck(_proof, _amount, _onBehalfOf); uint256 _claimedBlock = claimed[_root][_onBehalfOf]; if (_claimedBlock != 0) { revert AlreadyClaimed(); } else { claimed[_root][_onBehalfOf] = block.number; } address _signer = signer; // if the signer is not set, skip signature check if (_signer != address(0)) { _signatureCheck(_amount, _onBehalfOf, _signature, _root, _signer); } _execute(vault, _onBehalfOf, token, _configurator, _amount); emit AirdropClaimed(_onBehalfOf, _amount); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Internal function to execute the claim /// @param _vault vault address /// @param _recipient recipient address /// @param _token token address /// @param _configurator configurator address /// @param _amount amount of tokens to claim function _execute(address _vault, address _recipient, address _token, bytes32 _configurator, uint256 _amount) internal virtual; /// @notice Internal function to check the merkle proof /// @param _proof merkle proof of the claim /// @param _amount amount of tokens to claim /// @param _onBehalfOf address to claim on behalf of function _rootCheck(bytes32[] calldata _proof, uint256 _amount, address _onBehalfOf) internal view returns (bytes32 root, bytes32 configurator) { root = recover(_proof, keccak256(abi.encodePacked(_onBehalfOf, _amount))); configurator = merkleConfiguration[root]; if (configurator == bytes32(0)) revert InvalidMerkleProof(root); } /// @notice Internal function to check the signature /// @param _amount amount of tokens to claim /// @param _onBehalfOf address to claim on behalf of /// @param _signature signature of the claim /// @param _root root of the merkle tree /// @param _signer signer to check function _signatureCheck( uint256 _amount, address _onBehalfOf, bytes calldata _signature, bytes32 _root, address _signer ) internal view { if (_signature.length == 0) revert InvalidSignature(); bytes32 messageHash = keccak256(abi.encodePacked(_onBehalfOf, _amount, _root, address(this), block.chainid)); bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(messageHash); address recoveredSigner = ECDSA.recoverCalldata(prefixedHash, _signature); if (recoveredSigner != _signer) revert InvalidSignature(); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function recover(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32 root) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } root := leaf } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; struct StreamConfig { address recipient; address revokeAuthority; address token; uint256 amount; uint256 startTime; uint256 cliffTime; uint256 endTime; uint256 startUnlockPercentage; uint256 cliffUnlockPercentage; uint256 pieceDuration; address verifier; uint256 id; } /** * @dev Stream struct containing all parameters for a token stream * @param recipient Address that will receive the streamed tokens * @param revokeAuthority Address with permission to revoke the stream * @param token Address of the ERC20 token being streamed * @param amount Total amount of tokens in the stream * @param claimedAmount Amount of tokens already claimed * @param startTime Timestamp when the stream begins * @param cliffTime Timestamp when the cliff period ends * @param endTime Timestamp when the stream ends * @param startUnlockPercentage Percentage of tokens unlocked at start (18 decimals) * @param cliffUnlockPercentage Percentage of tokens unlocked at cliff (18 decimals) * @param pieceDuration Duration of each vesting piece (0 for linear vesting) */ struct Stream { address recipient; address revokeAuthority; address token; uint256 amount; uint256 claimedAmount; uint256 startTime; uint256 cliffTime; uint256 endTime; uint256 startUnlockPercentage; uint256 cliffUnlockPercentage; uint256 pieceDuration; } struct Badge { address verifier; uint256 id; } interface IVerifier { function ownerOf(uint256 id) external view returns (address); } interface ICliqueLock { // EXTERNAL FUNCTIONS - STREAM CREATION /** * @notice Creates a stream using standard ERC20 approve * @dev Requires prior approval of token transfer * @param config StreamConfig struct containing the stream parameters * @return streamId Unique identifier of the created stream */ function createStream(StreamConfig calldata config) external returns (uint256 streamId); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @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[ERC 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); }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"DeadlineReached","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"distributor","type":"address"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"DistributorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"ADMIN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AIDROP_MANAGER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"createDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_lock","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"createVestedDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_distributor","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"withdrawFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
610140806040523461005e57306080523060a0524660c0525f60e052610100905f82526101205f81526131b49283610063843960805183818161070401526107d3015260a05183505060c05183505060e0518350505182505051815050f35b5f80fdfe6080604081815260049182361015610015575f80fd5b5f9260e0905f35821c9283630762cf3f14610bdd57508263183a4f6e14610bc45782631c10893f14610b655782631cd64df414610b2c5782632569296214610ae357826329986d3914610ac85782632a0acc6a14610aad5782632de9480714610a7a57826338fa708d1461090b5782634a4ee7b1146108df5782634f1ef28614610797578263514e62fc1461075d57826352d1902d146106ef57826354d1f13d146106a9578263715018a6146106735782638129fc1c146105d157826384b0196e146105335782638da5cb5b14610505578263cfe0237714610402578263f04e283e14610395578263f2fde38b1461033b578263f5f9a8911461015857505063fee81cf414610122575f80fd5b346101545760203660031901126101545760209161013e610d97565b9063389a75e1600c525281600c20549051908152f35b5080fd5b849084346103375760c036600319011261033757610174610d97565b61017c610dad565b93610185610dc3565b608435949067ffffffffffffffff9060a435828111610333576101ab9036908501610dd9565b979095814211610323578798999a889798519060208201927fb0b468160dab1630ef0a2d69168f606bc3bbecdab6341435d57f1c8cf92ce931845260018060a01b03809e81809316809c8601521695866060850152169384608084015260643560a084015260c083015260c08252810181811086821117610310578a525190206102499061023890610ef0565b610243368c8b610e77565b90610f65565b638b78c6d8600c52855260026020600c2054161561030157875193610ec59081860194868610908611176102ee5750916080939185936110a3853982528660208301523389830152606082015203019082f09081156102e357506020957fce10738e35f78b97594969f2c098b909401ff425841c115dbff915f3dda7b32691169485936102da865192839283610ec9565b0390a351908152f35b8451903d90823e3d90fd5b634e487b7160e01b875260419052602486fd5b87516282b42960e81b81528490fd5b604187634e487b7160e01b5f525260245ffd5b875163b08ce5b360e01b81528590fd5b8480fd5b8280fd5b8490602036600319011261015457610351610d97565b9061035a610fed565b8160601b1561038a575060018060a01b0316638b78c6d8198181545f8051602061315f8339815191525f80a35580f35b637448fbae8352601cfd5b84906020366003190112610154576103ab610d97565b906103b4610fed565b63389a75e1600c528183526020600c2090815442116103f7575082905560018060a01b0316638b78c6d8198181545f8051602061315f8339815191525f80a35580f35b636f5e88188452601cfd5b849084346103375760803660031901126103375761041e610d97565b60643567ffffffffffffffff81116103335761043d9036908501610dd9565b90638b78c6d89283600c5233875260026020600c2054161561045d578680f35b60443542116104f5576104cd92916104c561024392875160208101917f2ca08f0c5e197b3141e5c2f954b97ca510e2cd93f13c8da4f670fb807882627c835260018060a01b0316898201526024356060820152606081526104bd81610e2b565b519020610ef0565b923691610e77565b90600c52835260026020600c205416156104e957808080808680f35b516282b42960e81b8152fd5b845163b08ce5b360e01b81528690fd5b50505034610154578160031936011261015457638b78c6d8195490516001600160a01b039091168152602090f35b838583346101545781600319360112610154576105759291610582610556611009565b85919551968796600f60f81b88526020968060208a0152880190610e07565b9186830390870152610e07565b4660608501523060808501528160a085015283810360c085015260206060519182815201926080925b8281106105ba57505050500390f35b8351855286955093810193928101926001016105ab565b84903461015457816003193601126101545763409feecd1980546003825590918161064e575b505033638b78c6d819558033835f8051602061315f8339815191528180a361061d575080f35b6002905560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a180f35b600182811c14303b1015610668575060ff1b1b82806105f7565b63f92ee8a98452601cfd5b84806003193601126106a657610687610fed565b5f638b78c6d8198181545f8051602061315f8339815191528280a35580f35b80fd5b84806003193601126106a65763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b8385346106a657806003193601126106a657307f00000000000000000000000000000000000000000000000000000000000000000361075157602082517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b639f03a026915052601cfd5b5050503461015457806003193601126101545760209161077b610d97565b90638b78c6d8600c525260243582600c20541615159051908152f35b91505081600319360112610337576107ad610d97565b9160243567ffffffffffffffff8111610333576107cd9036908401610dd9565b919093307f0000000000000000000000000000000000000000000000000000000000000000146108d357638b78c6d8195433036108af575b60018060a01b0316923d86526352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90816020600183601d895afa51036108a3575090828480949388967fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8880a255610882578380f35b8190519485378338925af41561089a57818180808380f35b903d90823e3d90fd5b6355299b49600152601dfd5b638b78c6d8600c5233865260016020600c20541661080557836382b429008752601cfd5b83639f03a0268752601cfd5b5050503660031901126106a6576109086108f7610d97565b6108ff610fed565b6024359061105d565b80f35b849084346109da5760803660031901126109da57610927610d97565b91610930610dad565b67ffffffffffffffff906064358281116109da576109519036908501610dd9565b638b78c6d89182600c52335f5260026020600c205416156109de575b5050506001600160a01b0394851694853b156109da5760245f928387519889948593631ac3ddeb60e01b855216888401525af180156109d0576109ae578480f35b909192809450116109bd575052005b604190634e487b7160e01b5f525260245ffd5b83513d5f823e3d90fd5b5f80fd5b6044354211610a6a5790610243610a3f926104c5895160208101907fc55771f2ceabbd14f04a92fbf0fa8ac9e4e27a4cd03793a1a7a7b92d11677eb382528c60018060a01b038091168d83015289166060820152606081526104bd81610e2b565b90600c525f5260026020600c20541615610a5b5786808061096d565b83516282b42960e81b81528390fd5b865163b08ce5b360e01b81528690fd5b83346109da5760203660031901126109da57602090610a97610d97565b638b78c6d8600c525f5281600c20549051908152f35b83346109da575f3660031901126109da576020905160018152f35b83346109da575f3660031901126109da576020905160028152f35b5f3660031901126109da5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b83346109da57806003193601126109da57602090610b48610d97565b60243590638b78c6d8600c525f528083600c205416149051908152f35b836003193601126109da57610b78610d97565b610b80610fed565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b60203660031901126109da57610bdb90353361105d565b005b9084346109da57836003193601126109da57610bf7610d97565b92610c00610dad565b92610c09610dc3565b6001600160a01b03959060643587811691908290036109da5760a43560c4359367ffffffffffffffff948581116109da57610c479036908801610dd9565b999097834211610d8957508a9b8b8a9b9c8b9a9b51938160208601967fdf3d66efb7c7b992b7161de12143a7b1f114efa9fc1c50d3965d66dea088ba72885216809c860152169586606085015216938460808401528660a084015260843560c0840152818301528152610100810181811087821117610d76578a52519020610cd29061023890610ef0565b638b78c6d8600c525f5260026020600c20541615610d67578751946111f79081870195878710908711176109bd57509185939160a09593611f68863983528660208401523389840152606083015260808201520301905ff080156109d0576020957fce10738e35f78b97594969f2c098b909401ff425841c115dbff915f3dda7b32691169485936102da865192839283610ec9565b87516282b42960e81b81528590fd5b604188634e487b7160e01b5f525260245ffd5b63b08ce5b360e01b81528790fd5b600435906001600160a01b03821682036109da57565b602435906001600160a01b03821682036109da57565b604435906001600160a01b03821682036109da57565b9181601f840112156109da5782359167ffffffffffffffff83116109da57602083818601950101116109da57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b6080810190811067ffffffffffffffff821117610e4757604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117610e4757604052565b92919267ffffffffffffffff91828111610e475760405192601f8201601f19908116603f0116840190811184821017610e47576040528294818452818301116109da578281602093845f960137010152565b90918060409360208452816020850152848401375f828201840152601f01601f1916010190565b60a0610efa611009565b90602081519101209060208151910120604051917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835260208301526040820152466060820152306080820152206719010000000000005f52601a52603a526042601820905f603a52565b91909160409260405191815180604014610fcc57604114610f935750505050505b638baa579f5f526004601cfd5b6060808301515f1a6020528583015190525b5f526020809101518452600160805f825afa51925f606052523d610fca575050610f86565b565b508185015160ff81901c601b016020526001600160ff1b0316606052610fa5565b638b78c6d819543303610ffc57565b6382b429005f526004601cfd5b60405161101581610e5b565b601881527f436c697175654469737472696275746f724d616e61676572000000000000000060208201529060405161104c81610e5b565b60018152603160f81b602082015290565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fe60803461013757601f610ec538819003918201601f19168301916001600160401b0383118484101761013b57808492608094604052833981010312610137576100478161014f565b6100536020830161014f565b61006b60606100646040860161014f565b940161014f565b600254926001600160a01b03928316908115610125578360018060a01b031991168160015416176001555f5416175f55169060018060a81b0319161760025533638b78c6d81955335f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c525f5260016020600c20556001600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3604051610d6190816101648239f35b60405163d92e233d60e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101375756fe6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610c5557508063183a4f6e14610c3d5780631ac3ddeb14610b805780631c10893f14610b205780631cd64df414610ae7578063238ac93314610abf5780632569296214610a7657806329c68dc114610a3b5780632de9480714610a095780634a4ee7b1146109df578063514e62fc146109a757806354d1f13d14610963578063584ebf761461049f5780635fc2f0361461044c5780636817031b146103e65780636c19e783146103a3578063715018a61461035f5780638da5cb5b14610333578063dfcae622146102ea578063e7e79a1e146102c0578063f04e283e14610244578063f28a80b614610229578063f2fde38b146101bf578063fbfa77cf14610197578063fc0c546a146101705763fee81cf41461013a575f80fd5b3461016c57602036600319011261016c57610153610c77565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b3461016c575f36600319011261016c575f546040516001600160a01b039091168152602090f35b3461016c575f36600319011261016c576002546040516001600160a01b039091168152602090f35b602036600319011261016c576101d3610c77565b6101db610caf565b8060601b1561021c5760018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b637448fbae5f526004601cfd5b3461016c575f36600319011261016c57602060405160018152f35b602036600319011261016c57610258610c77565b610260610caf565b63389a75e1600c52805f526020600c20805442116102b3575f905560018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b636f5e88185f526004601cfd5b3461016c57602036600319011261016c576004355f526004602052602060405f2054604051908152f35b3461016c57604036600319011261016c576024356001600160a01b0381169081900361016c576004355f52600360205260405f20905f52602052602060405f2054604051908152f35b3461016c575f36600319011261016c57638b78c6d819546040516001600160a01b039091168152602090f35b5f36600319011261016c57610372610caf565b5f638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a355005b3461016c57602036600319011261016c576103bc610c77565b6103c4610ccb565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b3461016c57602036600319011261016c576103ff610c77565b610407610ccb565b600280546001600160a01b0319166001600160a01b039290921691821790557fe7ae49f883c825b05681b3e00e8be6fdea9ed2a8a45e4c6ecb9390fc44cce6155f80a2005b3461016c57604036600319011261016c5760243560043561046b610ccb565b805f5260046020528160405f20557f5f8f4c6efebc2c9c76d8cadfd5f9bd9cf6611483e79417c706c86997840e95735f80a3005b608036600319011261016c5767ffffffffffffffff6004351161016c5736602360043501121561016c5767ffffffffffffffff600435600401351161016c573660246004356004013560051b60043501011161016c5767ffffffffffffffff6024351161016c5736602360243501121561016c5767ffffffffffffffff602435600401351161016c57366024803560040135813501011161016c576064356001600160a01b038116900361016c5760ff60025460a01c1615610951576040516bffffffffffffffffffffffff1960643560601b16602082015260443560348201526034815280606081011067ffffffffffffffff60608301111761077f576060810160405280516020820120906105c560206004356004013560051b0160608301610c8d565b600435600401356060820152608081019182602460043501905b60246004356004013560051b60043501018210610941575050906060810151928361090b575b50508091505f52600460205260405f20549081156108f3575f8181526003602090815260408083206064356001600160a01b031684529091529020541561065857604051630c8d9eab60e31b8152600490fd5b5f8181526003602090815260408083206001600160a01b036064358116855292529091204390556001541690816107a5575b50506002545f546001600160a01b03908116929116905f1901610793576040519060208201906323b872dd60e01b8252602483015260018060a01b0360643516604483015260443560648301526064825260a082019082821067ffffffffffffffff83111761077f576020925f92604052519082855af115610774575f513d61076b5750803b155b6107535760405160443581526064356001600160a01b0316907f650e45f04ef8a0c267b2f78d983913f69ae3a353b2b32de5429307522be0ab5590602090a2005b60249060405190635274afe760e01b82526004820152fd5b60011415610712565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b604051639dd854d360e01b8152600490fd5b60243560040135156108b557604051906bffffffffffffffffffffffff1960643560601b166020830152604435603483015260548201523060601b6074820152466088820152608881528060c081011067ffffffffffffffff60c08301111761077f5760c08101604052805160208201206020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042060243560040135806040146108c75760411461086557505050505b638baa579f5f526004601cfd5b606460243501355f1a6020526040602480350181375b5f5260c06020600160805f825afa51915f606052016040523d6108a057505050610858565b6001600160a01b0316036108b557818061068a565b604051638baa579f60e01b8152600490fd5b5060248035604481013560ff81901c601b016020529101356040526001600160ff1b031660605261087b565b60249060405190630ee30f2b60e21b82526004820152fd5b9260051b01608001905b8251811160051b90815260208351911852602060405f2092019181831061091557915050808280610605565b81358152602091820191016105df565b604051634065aaf160e11b8152600490fd5b5f36600319011261016c5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461016c57604036600319011261016c576109c0610c77565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b604036600319011261016c57610a076109f6610c77565b6109fe610caf565b60243590610ce6565b005b3461016c57602036600319011261016c57610a22610c77565b638b78c6d8600c525f52602080600c2054604051908152f35b3461016c575f36600319011261016c57610a53610ccb565b6002805460ff60a01b19811660a091821c60ff161590911b60ff60a01b16179055005b5f36600319011261016c5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461016c575f36600319011261016c576001546040516001600160a01b039091168152602090f35b3461016c57604036600319011261016c576020610b02610c77565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b604036600319011261016c57610b34610c77565b610b3c610caf565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461016c57602036600319011261016c57610b99610c77565b610ba1610caf565b479081610baa57005b6001600160a01b0316905f80808084865af13d15610c38573d67ffffffffffffffff811161077f5760405190610bea601f8201601f191660200183610c8d565b81525f60203d92013e5b15610c265760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a2005b604051631d42c86760e21b8152600490fd5b610bf4565b602036600319011261016c57610a0760043533610ce6565b3461016c575f36600319011261016c5760209060ff60025460a01c1615158152f35b600435906001600160a01b038216820361016c57565b90601f8019910116810190811067ffffffffffffffff82111761077f57604052565b638b78c6d819543303610cbe57565b6382b429005f526004601cfd5b638b78c6d8600c52335f5260016020600c20541615610cbe57565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea2646970667358221220003db0d199922105d4c550c8ec7433021a7e86b8e1c4451db8a0b39530e6b67764736f6c6343000819003360a03461015b57601f6111f738819003918201601f19168301916001600160401b0383118484101761015f5780849260a09460405283398101031261015b5761004781610173565b61005360208301610173565b9061006060408401610173565b91610079608061007260608701610173565b9501610173565b600254909490926001600160a01b03928316908115610149578360018060a01b031991168160015416176001555f5416175f55169060018060a81b0319161760025533638b78c6d81955335f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c525f5260016020600c20556001600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a360805260405161106f908161018882396080518181816101df01526107c30152f35b60405163d92e233d60e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820361015b5756fe6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610f4f57508063183a4f6e14610f375780631ac3ddeb14610e7a5780631c10893f14610e1a5780631cd64df414610de1578063238ac93314610db95780632569296214610d7057806329c68dc114610d355780632de9480714610d035780634a4ee7b114610cd9578063514e62fc14610ca157806354d1f13d14610c5d578063584ebf76146104ee5780635fc2f0361461049b5780636817031b146104355780636c19e783146103f2578063715018a6146103ae5780638da5cb5b14610382578063dfcae62214610339578063e7e79a1e1461030f578063f04e283e14610293578063f28a80b614610278578063f2fde38b1461020e578063f83d08ba146101ca578063fbfa77cf146101a2578063fc0c546a1461017b5763fee81cf414610145575f80fd5b346101775760203660031901126101775761015e610f71565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b34610177575f366003190112610177575f546040516001600160a01b039091168152602090f35b34610177575f366003190112610177576002546040516001600160a01b039091168152602090f35b34610177575f366003190112610177576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b602036600319011261017757610222610f71565b61022a610fa9565b8060601b1561026b5760018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b637448fbae5f526004601cfd5b34610177575f36600319011261017757602060405160018152f35b6020366003190112610177576102a7610f71565b6102af610fa9565b63389a75e1600c52805f526020600c2080544211610302575f905560018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b636f5e88185f526004601cfd5b34610177576020366003190112610177576004355f526004602052602060405f2054604051908152f35b34610177576040366003190112610177576024356001600160a01b03811690819003610177576004355f52600360205260405f20905f52602052602060405f2054604051908152f35b34610177575f36600319011261017757638b78c6d819546040516001600160a01b039091168152602090f35b5f366003190112610177576103c1610fa9565b5f638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a355005b346101775760203660031901126101775761040b610f71565b610413610fc5565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b346101775760203660031901126101775761044e610f71565b610456610fc5565b600280546001600160a01b0319166001600160a01b039290921691821790557fe7ae49f883c825b05681b3e00e8be6fdea9ed2a8a45e4c6ecb9390fc44cce6155f80a2005b34610177576040366003190112610177576024356004356104ba610fc5565b805f5260046020528160405f20557f5f8f4c6efebc2c9c76d8cadfd5f9bd9cf6611483e79417c706c86997840e95735f80a3005b60803660031901126101775767ffffffffffffffff60043511610177573660236004350112156101775767ffffffffffffffff6004356004013511610177573660246004356004013560051b6004350101116101775767ffffffffffffffff60243511610177573660236024350112156101775767ffffffffffffffff6024356004013511610177573660248035600401358135010111610177576064356001600160a01b03811690036101775760ff60025460a01c1615610c4b576040516bffffffffffffffffffffffff1960643560601b16602082015260443560348201526034815280606081011067ffffffffffffffff6060830111176109905760608101604052805160208201209061061460206004356004013560051b0160608301610f87565b600435600401356060820152608081019182602460043501905b60246004356004013560051b60043501018210610c3b5750509060608101519283610c05575b50508091505f52600460205260405f2054908115610bed575f8181526003602090815260408083206064356001600160a01b03168452909152902054156106a757604051630c8d9eab60e31b8152600490fd5b5f8181526003602090815260408083206001600160a01b03606435811685529252909120439055600154169081610a9f575b50506002545f546040516317f727f360e11b81526001600160a01b036064358116600483015260448035602484015291949281169381169261018092839287928391165afa93841561092c575f946109c1575b50506040830180519092906001600160a01b03168181036109a4575060608401918251906040519160208301916323b872dd60e01b8352602484015230604484015260648301526064825260a082019082821067ffffffffffffffff831117610990576020925f92604052519082855af11561092c575f513d6109875750803b155b61096f57815160405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201929092529091602090829060449082905f905af1801561092c57610937575b50604051632f45cd6f60e01b815284516001600160a01b03908116600483015260208087015182166024840152945181166044830152925160648201526080850151608482015260a085015160a482015260c085015160c482015260e085015160e482015261010085015161010482015261012085015161012482015261014085015183166101448201526101609094015161016485015283916101849183915f91165af1801561092c57610901575b60405160443581526064356001600160a01b0316907f650e45f04ef8a0c267b2f78d983913f69ae3a353b2b32de5429307522be0ab5590602090a2005b602090813d8311610925575b6109178183610f87565b8101031261017757806108c4565b503d61090d565b6040513d5f823e3d90fd5b6020813d602011610967575b8161095060209383610f87565b810103126101775751801515036101775784610814565b3d9150610943565b60249060405190635274afe760e01b82526004820152fd5b600114156107ae565b634e487b7160e01b5f52604160045260245ffd5b60449160405191630fa309cb60e11b835260048301526024820152fd5b908092945081813d8311610a98575b6109da8183610f87565b810103126101775760405191820182811067ffffffffffffffff82111761099057604052610a0781610fe0565b8252610a1560208201610fe0565b6020830152610a2660408201610fe0565b6040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e083015261010080820151908301526101208082015190830152610140610a81818301610fe0565b90830152610160809101519082015291838061072c565b503d6109d0565b6024356004013515610baf57604051906bffffffffffffffffffffffff1960643560601b166020830152604435603483015260548201523060601b6074820152466088820152608881528060c081011067ffffffffffffffff60c0830111176109905760c08101604052805160208201206020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004206024356004013580604014610bc157604114610b5f57505050505b638baa579f5f526004601cfd5b606460243501355f1a6020526040602480350181375b5f5260c06020600160805f825afa51915f606052016040523d610b9a57505050610b52565b6001600160a01b031603610baf5781806106d9565b604051638baa579f60e01b8152600490fd5b5060248035604481013560ff81901c601b016020529101356040526001600160ff1b0316606052610b75565b60249060405190630ee30f2b60e21b82526004820152fd5b9260051b01608001905b8251811160051b90815260208351911852602060405f20920191818310610c0f57915050808280610654565b813581526020918201910161062e565b604051634065aaf160e11b8152600490fd5b5f3660031901126101775763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461017757604036600319011261017757610cba610f71565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b604036600319011261017757610d01610cf0610f71565b610cf8610fa9565b60243590610ff4565b005b3461017757602036600319011261017757610d1c610f71565b638b78c6d8600c525f52602080600c2054604051908152f35b34610177575f36600319011261017757610d4d610fc5565b6002805460ff60a01b19811660a091821c60ff161590911b60ff60a01b16179055005b5f3660031901126101775763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b34610177575f366003190112610177576001546040516001600160a01b039091168152602090f35b34610177576040366003190112610177576020610dfc610f71565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b604036600319011261017757610e2e610f71565b610e36610fa9565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461017757602036600319011261017757610e93610f71565b610e9b610fa9565b479081610ea457005b6001600160a01b0316905f80808084865af13d15610f32573d67ffffffffffffffff81116109905760405190610ee4601f8201601f191660200183610f87565b81525f60203d92013e5b15610f205760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a2005b604051631d42c86760e21b8152600490fd5b610eee565b602036600319011261017757610d0160043533610ff4565b34610177575f3660031901126101775760209060ff60025460a01c1615158152f35b600435906001600160a01b038216820361017757565b90601f8019910116810190811067ffffffffffffffff82111761099057604052565b638b78c6d819543303610fb857565b6382b429005f526004601cfd5b638b78c6d8600c52335f5260016020600c20541615610fb857565b51906001600160a01b038216820361017757565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea26469706673582212207de909fc8255e283482109cd6be67474f14c03f8212dc16e476663cebaee5ebf64736f6c634300081900338be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a2646970667358221220a7fcd6a788aba7ad491fefd2d65347e30e605afb206d663c6075f35d5f42cd4064736f6c63430008190033
Deployed Bytecode
0x6080604081815260049182361015610015575f80fd5b5f9260e0905f35821c9283630762cf3f14610bdd57508263183a4f6e14610bc45782631c10893f14610b655782631cd64df414610b2c5782632569296214610ae357826329986d3914610ac85782632a0acc6a14610aad5782632de9480714610a7a57826338fa708d1461090b5782634a4ee7b1146108df5782634f1ef28614610797578263514e62fc1461075d57826352d1902d146106ef57826354d1f13d146106a9578263715018a6146106735782638129fc1c146105d157826384b0196e146105335782638da5cb5b14610505578263cfe0237714610402578263f04e283e14610395578263f2fde38b1461033b578263f5f9a8911461015857505063fee81cf414610122575f80fd5b346101545760203660031901126101545760209161013e610d97565b9063389a75e1600c525281600c20549051908152f35b5080fd5b849084346103375760c036600319011261033757610174610d97565b61017c610dad565b93610185610dc3565b608435949067ffffffffffffffff9060a435828111610333576101ab9036908501610dd9565b979095814211610323578798999a889798519060208201927fb0b468160dab1630ef0a2d69168f606bc3bbecdab6341435d57f1c8cf92ce931845260018060a01b03809e81809316809c8601521695866060850152169384608084015260643560a084015260c083015260c08252810181811086821117610310578a525190206102499061023890610ef0565b610243368c8b610e77565b90610f65565b638b78c6d8600c52855260026020600c2054161561030157875193610ec59081860194868610908611176102ee5750916080939185936110a3853982528660208301523389830152606082015203019082f09081156102e357506020957fce10738e35f78b97594969f2c098b909401ff425841c115dbff915f3dda7b32691169485936102da865192839283610ec9565b0390a351908152f35b8451903d90823e3d90fd5b634e487b7160e01b875260419052602486fd5b87516282b42960e81b81528490fd5b604187634e487b7160e01b5f525260245ffd5b875163b08ce5b360e01b81528590fd5b8480fd5b8280fd5b8490602036600319011261015457610351610d97565b9061035a610fed565b8160601b1561038a575060018060a01b0316638b78c6d8198181545f8051602061315f8339815191525f80a35580f35b637448fbae8352601cfd5b84906020366003190112610154576103ab610d97565b906103b4610fed565b63389a75e1600c528183526020600c2090815442116103f7575082905560018060a01b0316638b78c6d8198181545f8051602061315f8339815191525f80a35580f35b636f5e88188452601cfd5b849084346103375760803660031901126103375761041e610d97565b60643567ffffffffffffffff81116103335761043d9036908501610dd9565b90638b78c6d89283600c5233875260026020600c2054161561045d578680f35b60443542116104f5576104cd92916104c561024392875160208101917f2ca08f0c5e197b3141e5c2f954b97ca510e2cd93f13c8da4f670fb807882627c835260018060a01b0316898201526024356060820152606081526104bd81610e2b565b519020610ef0565b923691610e77565b90600c52835260026020600c205416156104e957808080808680f35b516282b42960e81b8152fd5b845163b08ce5b360e01b81528690fd5b50505034610154578160031936011261015457638b78c6d8195490516001600160a01b039091168152602090f35b838583346101545781600319360112610154576105759291610582610556611009565b85919551968796600f60f81b88526020968060208a0152880190610e07565b9186830390870152610e07565b4660608501523060808501528160a085015283810360c085015260206060519182815201926080925b8281106105ba57505050500390f35b8351855286955093810193928101926001016105ab565b84903461015457816003193601126101545763409feecd1980546003825590918161064e575b505033638b78c6d819558033835f8051602061315f8339815191528180a361061d575080f35b6002905560016020527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602080a180f35b600182811c14303b1015610668575060ff1b1b82806105f7565b63f92ee8a98452601cfd5b84806003193601126106a657610687610fed565b5f638b78c6d8198181545f8051602061315f8339815191528280a35580f35b80fd5b84806003193601126106a65763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b8385346106a657806003193601126106a657307f00000000000000000000000077e0f495634f416251a72626ab45879e2b94274a0361075157602082517f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8152f35b639f03a026915052601cfd5b5050503461015457806003193601126101545760209161077b610d97565b90638b78c6d8600c525260243582600c20541615159051908152f35b91505081600319360112610337576107ad610d97565b9160243567ffffffffffffffff8111610333576107cd9036908401610dd9565b919093307f00000000000000000000000077e0f495634f416251a72626ab45879e2b94274a146108d357638b78c6d8195433036108af575b60018060a01b0316923d86526352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90816020600183601d895afa51036108a3575090828480949388967fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8880a255610882578380f35b8190519485378338925af41561089a57818180808380f35b903d90823e3d90fd5b6355299b49600152601dfd5b638b78c6d8600c5233865260016020600c20541661080557836382b429008752601cfd5b83639f03a0268752601cfd5b5050503660031901126106a6576109086108f7610d97565b6108ff610fed565b6024359061105d565b80f35b849084346109da5760803660031901126109da57610927610d97565b91610930610dad565b67ffffffffffffffff906064358281116109da576109519036908501610dd9565b638b78c6d89182600c52335f5260026020600c205416156109de575b5050506001600160a01b0394851694853b156109da5760245f928387519889948593631ac3ddeb60e01b855216888401525af180156109d0576109ae578480f35b909192809450116109bd575052005b604190634e487b7160e01b5f525260245ffd5b83513d5f823e3d90fd5b5f80fd5b6044354211610a6a5790610243610a3f926104c5895160208101907fc55771f2ceabbd14f04a92fbf0fa8ac9e4e27a4cd03793a1a7a7b92d11677eb382528c60018060a01b038091168d83015289166060820152606081526104bd81610e2b565b90600c525f5260026020600c20541615610a5b5786808061096d565b83516282b42960e81b81528390fd5b865163b08ce5b360e01b81528690fd5b83346109da5760203660031901126109da57602090610a97610d97565b638b78c6d8600c525f5281600c20549051908152f35b83346109da575f3660031901126109da576020905160018152f35b83346109da575f3660031901126109da576020905160028152f35b5f3660031901126109da5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b83346109da57806003193601126109da57602090610b48610d97565b60243590638b78c6d8600c525f528083600c205416149051908152f35b836003193601126109da57610b78610d97565b610b80610fed565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b60203660031901126109da57610bdb90353361105d565b005b9084346109da57836003193601126109da57610bf7610d97565b92610c00610dad565b92610c09610dc3565b6001600160a01b03959060643587811691908290036109da5760a43560c4359367ffffffffffffffff948581116109da57610c479036908801610dd9565b999097834211610d8957508a9b8b8a9b9c8b9a9b51938160208601967fdf3d66efb7c7b992b7161de12143a7b1f114efa9fc1c50d3965d66dea088ba72885216809c860152169586606085015216938460808401528660a084015260843560c0840152818301528152610100810181811087821117610d76578a52519020610cd29061023890610ef0565b638b78c6d8600c525f5260026020600c20541615610d67578751946111f79081870195878710908711176109bd57509185939160a09593611f68863983528660208401523389840152606083015260808201520301905ff080156109d0576020957fce10738e35f78b97594969f2c098b909401ff425841c115dbff915f3dda7b32691169485936102da865192839283610ec9565b87516282b42960e81b81528590fd5b604188634e487b7160e01b5f525260245ffd5b63b08ce5b360e01b81528790fd5b600435906001600160a01b03821682036109da57565b602435906001600160a01b03821682036109da57565b604435906001600160a01b03821682036109da57565b9181601f840112156109da5782359167ffffffffffffffff83116109da57602083818601950101116109da57565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b6080810190811067ffffffffffffffff821117610e4757604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117610e4757604052565b92919267ffffffffffffffff91828111610e475760405192601f8201601f19908116603f0116840190811184821017610e47576040528294818452818301116109da578281602093845f960137010152565b90918060409360208452816020850152848401375f828201840152601f01601f1916010190565b60a0610efa611009565b90602081519101209060208151910120604051917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835260208301526040820152466060820152306080820152206719010000000000005f52601a52603a526042601820905f603a52565b91909160409260405191815180604014610fcc57604114610f935750505050505b638baa579f5f526004601cfd5b6060808301515f1a6020528583015190525b5f526020809101518452600160805f825afa51925f606052523d610fca575050610f86565b565b508185015160ff81901c601b016020526001600160ff1b0316606052610fa5565b638b78c6d819543303610ffc57565b6382b429005f526004601cfd5b60405161101581610e5b565b601881527f436c697175654469737472696275746f724d616e61676572000000000000000060208201529060405161104c81610e5b565b60018152603160f81b602082015290565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fe60803461013757601f610ec538819003918201601f19168301916001600160401b0383118484101761013b57808492608094604052833981010312610137576100478161014f565b6100536020830161014f565b61006b60606100646040860161014f565b940161014f565b600254926001600160a01b03928316908115610125578360018060a01b031991168160015416176001555f5416175f55169060018060a81b0319161760025533638b78c6d81955335f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c525f5260016020600c20556001600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3604051610d6190816101648239f35b60405163d92e233d60e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101375756fe6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610c5557508063183a4f6e14610c3d5780631ac3ddeb14610b805780631c10893f14610b205780631cd64df414610ae7578063238ac93314610abf5780632569296214610a7657806329c68dc114610a3b5780632de9480714610a095780634a4ee7b1146109df578063514e62fc146109a757806354d1f13d14610963578063584ebf761461049f5780635fc2f0361461044c5780636817031b146103e65780636c19e783146103a3578063715018a61461035f5780638da5cb5b14610333578063dfcae622146102ea578063e7e79a1e146102c0578063f04e283e14610244578063f28a80b614610229578063f2fde38b146101bf578063fbfa77cf14610197578063fc0c546a146101705763fee81cf41461013a575f80fd5b3461016c57602036600319011261016c57610153610c77565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b3461016c575f36600319011261016c575f546040516001600160a01b039091168152602090f35b3461016c575f36600319011261016c576002546040516001600160a01b039091168152602090f35b602036600319011261016c576101d3610c77565b6101db610caf565b8060601b1561021c5760018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b637448fbae5f526004601cfd5b3461016c575f36600319011261016c57602060405160018152f35b602036600319011261016c57610258610c77565b610260610caf565b63389a75e1600c52805f526020600c20805442116102b3575f905560018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b636f5e88185f526004601cfd5b3461016c57602036600319011261016c576004355f526004602052602060405f2054604051908152f35b3461016c57604036600319011261016c576024356001600160a01b0381169081900361016c576004355f52600360205260405f20905f52602052602060405f2054604051908152f35b3461016c575f36600319011261016c57638b78c6d819546040516001600160a01b039091168152602090f35b5f36600319011261016c57610372610caf565b5f638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a355005b3461016c57602036600319011261016c576103bc610c77565b6103c4610ccb565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b3461016c57602036600319011261016c576103ff610c77565b610407610ccb565b600280546001600160a01b0319166001600160a01b039290921691821790557fe7ae49f883c825b05681b3e00e8be6fdea9ed2a8a45e4c6ecb9390fc44cce6155f80a2005b3461016c57604036600319011261016c5760243560043561046b610ccb565b805f5260046020528160405f20557f5f8f4c6efebc2c9c76d8cadfd5f9bd9cf6611483e79417c706c86997840e95735f80a3005b608036600319011261016c5767ffffffffffffffff6004351161016c5736602360043501121561016c5767ffffffffffffffff600435600401351161016c573660246004356004013560051b60043501011161016c5767ffffffffffffffff6024351161016c5736602360243501121561016c5767ffffffffffffffff602435600401351161016c57366024803560040135813501011161016c576064356001600160a01b038116900361016c5760ff60025460a01c1615610951576040516bffffffffffffffffffffffff1960643560601b16602082015260443560348201526034815280606081011067ffffffffffffffff60608301111761077f576060810160405280516020820120906105c560206004356004013560051b0160608301610c8d565b600435600401356060820152608081019182602460043501905b60246004356004013560051b60043501018210610941575050906060810151928361090b575b50508091505f52600460205260405f20549081156108f3575f8181526003602090815260408083206064356001600160a01b031684529091529020541561065857604051630c8d9eab60e31b8152600490fd5b5f8181526003602090815260408083206001600160a01b036064358116855292529091204390556001541690816107a5575b50506002545f546001600160a01b03908116929116905f1901610793576040519060208201906323b872dd60e01b8252602483015260018060a01b0360643516604483015260443560648301526064825260a082019082821067ffffffffffffffff83111761077f576020925f92604052519082855af115610774575f513d61076b5750803b155b6107535760405160443581526064356001600160a01b0316907f650e45f04ef8a0c267b2f78d983913f69ae3a353b2b32de5429307522be0ab5590602090a2005b60249060405190635274afe760e01b82526004820152fd5b60011415610712565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b604051639dd854d360e01b8152600490fd5b60243560040135156108b557604051906bffffffffffffffffffffffff1960643560601b166020830152604435603483015260548201523060601b6074820152466088820152608881528060c081011067ffffffffffffffff60c08301111761077f5760c08101604052805160208201206020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c60042060243560040135806040146108c75760411461086557505050505b638baa579f5f526004601cfd5b606460243501355f1a6020526040602480350181375b5f5260c06020600160805f825afa51915f606052016040523d6108a057505050610858565b6001600160a01b0316036108b557818061068a565b604051638baa579f60e01b8152600490fd5b5060248035604481013560ff81901c601b016020529101356040526001600160ff1b031660605261087b565b60249060405190630ee30f2b60e21b82526004820152fd5b9260051b01608001905b8251811160051b90815260208351911852602060405f2092019181831061091557915050808280610605565b81358152602091820191016105df565b604051634065aaf160e11b8152600490fd5b5f36600319011261016c5763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461016c57604036600319011261016c576109c0610c77565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b604036600319011261016c57610a076109f6610c77565b6109fe610caf565b60243590610ce6565b005b3461016c57602036600319011261016c57610a22610c77565b638b78c6d8600c525f52602080600c2054604051908152f35b3461016c575f36600319011261016c57610a53610ccb565b6002805460ff60a01b19811660a091821c60ff161590911b60ff60a01b16179055005b5f36600319011261016c5763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b3461016c575f36600319011261016c576001546040516001600160a01b039091168152602090f35b3461016c57604036600319011261016c576020610b02610c77565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b604036600319011261016c57610b34610c77565b610b3c610caf565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461016c57602036600319011261016c57610b99610c77565b610ba1610caf565b479081610baa57005b6001600160a01b0316905f80808084865af13d15610c38573d67ffffffffffffffff811161077f5760405190610bea601f8201601f191660200183610c8d565b81525f60203d92013e5b15610c265760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a2005b604051631d42c86760e21b8152600490fd5b610bf4565b602036600319011261016c57610a0760043533610ce6565b3461016c575f36600319011261016c5760209060ff60025460a01c1615158152f35b600435906001600160a01b038216820361016c57565b90601f8019910116810190811067ffffffffffffffff82111761077f57604052565b638b78c6d819543303610cbe57565b6382b429005f526004601cfd5b638b78c6d8600c52335f5260016020600c20541615610cbe57565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea2646970667358221220003db0d199922105d4c550c8ec7433021a7e86b8e1c4451db8a0b39530e6b67764736f6c6343000819003360a03461015b57601f6111f738819003918201601f19168301916001600160401b0383118484101761015f5780849260a09460405283398101031261015b5761004781610173565b61005360208301610173565b9061006060408401610173565b91610079608061007260608701610173565b9501610173565b600254909490926001600160a01b03928316908115610149578360018060a01b031991168160015416176001555f5416175f55169060018060a81b0319161760025533638b78c6d81955335f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3638b78c6d8600c525f5260016020600c20556001600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a360805260405161106f908161018882396080518181816101df01526107c30152f35b60405163d92e233d60e01b8152600490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b038216820361015b5756fe6080806040526004361015610012575f80fd5b5f3560e01c90816302fb0c5e14610f4f57508063183a4f6e14610f375780631ac3ddeb14610e7a5780631c10893f14610e1a5780631cd64df414610de1578063238ac93314610db95780632569296214610d7057806329c68dc114610d355780632de9480714610d035780634a4ee7b114610cd9578063514e62fc14610ca157806354d1f13d14610c5d578063584ebf76146104ee5780635fc2f0361461049b5780636817031b146104355780636c19e783146103f2578063715018a6146103ae5780638da5cb5b14610382578063dfcae62214610339578063e7e79a1e1461030f578063f04e283e14610293578063f28a80b614610278578063f2fde38b1461020e578063f83d08ba146101ca578063fbfa77cf146101a2578063fc0c546a1461017b5763fee81cf414610145575f80fd5b346101775760203660031901126101775761015e610f71565b63389a75e1600c525f52602080600c2054604051908152f35b5f80fd5b34610177575f366003190112610177575f546040516001600160a01b039091168152602090f35b34610177575f366003190112610177576002546040516001600160a01b039091168152602090f35b34610177575f366003190112610177576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b602036600319011261017757610222610f71565b61022a610fa9565b8060601b1561026b5760018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b637448fbae5f526004601cfd5b34610177575f36600319011261017757602060405160018152f35b6020366003190112610177576102a7610f71565b6102af610fa9565b63389a75e1600c52805f526020600c2080544211610302575f905560018060a01b0316638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355005b636f5e88185f526004601cfd5b34610177576020366003190112610177576004355f526004602052602060405f2054604051908152f35b34610177576040366003190112610177576024356001600160a01b03811690819003610177576004355f52600360205260405f20905f52602052602060405f2054604051908152f35b34610177575f36600319011261017757638b78c6d819546040516001600160a01b039091168152602090f35b5f366003190112610177576103c1610fa9565b5f638b78c6d8198181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a355005b346101775760203660031901126101775761040b610f71565b610413610fc5565b600180546001600160a01b0319166001600160a01b0392909216919091179055005b346101775760203660031901126101775761044e610f71565b610456610fc5565b600280546001600160a01b0319166001600160a01b039290921691821790557fe7ae49f883c825b05681b3e00e8be6fdea9ed2a8a45e4c6ecb9390fc44cce6155f80a2005b34610177576040366003190112610177576024356004356104ba610fc5565b805f5260046020528160405f20557f5f8f4c6efebc2c9c76d8cadfd5f9bd9cf6611483e79417c706c86997840e95735f80a3005b60803660031901126101775767ffffffffffffffff60043511610177573660236004350112156101775767ffffffffffffffff6004356004013511610177573660246004356004013560051b6004350101116101775767ffffffffffffffff60243511610177573660236024350112156101775767ffffffffffffffff6024356004013511610177573660248035600401358135010111610177576064356001600160a01b03811690036101775760ff60025460a01c1615610c4b576040516bffffffffffffffffffffffff1960643560601b16602082015260443560348201526034815280606081011067ffffffffffffffff6060830111176109905760608101604052805160208201209061061460206004356004013560051b0160608301610f87565b600435600401356060820152608081019182602460043501905b60246004356004013560051b60043501018210610c3b5750509060608101519283610c05575b50508091505f52600460205260405f2054908115610bed575f8181526003602090815260408083206064356001600160a01b03168452909152902054156106a757604051630c8d9eab60e31b8152600490fd5b5f8181526003602090815260408083206001600160a01b03606435811685529252909120439055600154169081610a9f575b50506002545f546040516317f727f360e11b81526001600160a01b036064358116600483015260448035602484015291949281169381169261018092839287928391165afa93841561092c575f946109c1575b50506040830180519092906001600160a01b03168181036109a4575060608401918251906040519160208301916323b872dd60e01b8352602484015230604484015260648301526064825260a082019082821067ffffffffffffffff831117610990576020925f92604052519082855af11561092c575f513d6109875750803b155b61096f57815160405163095ea7b360e01b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038116600483015260248201929092529091602090829060449082905f905af1801561092c57610937575b50604051632f45cd6f60e01b815284516001600160a01b03908116600483015260208087015182166024840152945181166044830152925160648201526080850151608482015260a085015160a482015260c085015160c482015260e085015160e482015261010085015161010482015261012085015161012482015261014085015183166101448201526101609094015161016485015283916101849183915f91165af1801561092c57610901575b60405160443581526064356001600160a01b0316907f650e45f04ef8a0c267b2f78d983913f69ae3a353b2b32de5429307522be0ab5590602090a2005b602090813d8311610925575b6109178183610f87565b8101031261017757806108c4565b503d61090d565b6040513d5f823e3d90fd5b6020813d602011610967575b8161095060209383610f87565b810103126101775751801515036101775784610814565b3d9150610943565b60249060405190635274afe760e01b82526004820152fd5b600114156107ae565b634e487b7160e01b5f52604160045260245ffd5b60449160405191630fa309cb60e11b835260048301526024820152fd5b908092945081813d8311610a98575b6109da8183610f87565b810103126101775760405191820182811067ffffffffffffffff82111761099057604052610a0781610fe0565b8252610a1560208201610fe0565b6020830152610a2660408201610fe0565b6040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e083015261010080820151908301526101208082015190830152610140610a81818301610fe0565b90830152610160809101519082015291838061072c565b503d6109d0565b6024356004013515610baf57604051906bffffffffffffffffffffffff1960643560601b166020830152604435603483015260548201523060601b6074820152466088820152608881528060c081011067ffffffffffffffff60c0830111176109905760c08101604052805160208201206020527b19457468657265756d205369676e6564204d6573736167653a0a33325f52603c6004206024356004013580604014610bc157604114610b5f57505050505b638baa579f5f526004601cfd5b606460243501355f1a6020526040602480350181375b5f5260c06020600160805f825afa51915f606052016040523d610b9a57505050610b52565b6001600160a01b031603610baf5781806106d9565b604051638baa579f60e01b8152600490fd5b5060248035604481013560ff81901c601b016020529101356040526001600160ff1b0316606052610b75565b60249060405190630ee30f2b60e21b82526004820152fd5b9260051b01608001905b8251811160051b90815260208351911852602060405f20920191818310610c0f57915050808280610654565b813581526020918201910161062e565b604051634065aaf160e11b8152600490fd5b5f3660031901126101775763389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2005b3461017757604036600319011261017757610cba610f71565b638b78c6d8600c525f52602060243581600c2054161515604051908152f35b604036600319011261017757610d01610cf0610f71565b610cf8610fa9565b60243590610ff4565b005b3461017757602036600319011261017757610d1c610f71565b638b78c6d8600c525f52602080600c2054604051908152f35b34610177575f36600319011261017757610d4d610fc5565b6002805460ff60a01b19811660a091821c60ff161590911b60ff60a01b16179055005b5f3660031901126101775763389a75e1600c52335f526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a2005b34610177575f366003190112610177576001546040516001600160a01b039091168152602090f35b34610177576040366003190112610177576020610dfc610f71565b60243590638b78c6d8600c525f528082600c20541614604051908152f35b604036600319011261017757610e2e610f71565b610e36610fa9565b638b78c6d8600c525f526020600c20602435815417809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3005b3461017757602036600319011261017757610e93610f71565b610e9b610fa9565b479081610ea457005b6001600160a01b0316905f80808084865af13d15610f32573d67ffffffffffffffff81116109905760405190610ee4601f8201601f191660200183610f87565b81525f60203d92013e5b15610f205760207f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436491604051908152a2005b604051631d42c86760e21b8152600490fd5b610eee565b602036600319011261017757610d0160043533610ff4565b34610177575f3660031901126101775760209060ff60025460a01c1615158152f35b600435906001600160a01b038216820361017757565b90601f8019910116810190811067ffffffffffffffff82111761099057604052565b638b78c6d819543303610fb857565b6382b429005f526004601cfd5b638b78c6d8600c52335f5260016020600c20541615610fb857565b51906001600160a01b038216820361017757565b638b78c6d8600c525f526020600c2090815490811618809155600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a356fea26469706673582212207de909fc8255e283482109cd6be67474f14c03f8212dc16e476663cebaee5ebf64736f6c634300081900338be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a2646970667358221220a7fcd6a788aba7ad491fefd2d65347e30e605afb206d663c6075f35d5f42cd4064736f6c63430008190033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.