Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ArchetypeLogicBurgers404
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT // ArchetypeLogic v0.8.0 - BURGERS404 // // d8888 888 888 // d88888 888 888 // d88P888 888 888 // d88P 888 888d888 .d8888b 88888b. .d88b. 888888 888 888 88888b. .d88b. // d88P 888 888P" d88P" 888 "88b d8P Y8b 888 888 888 888 "88b d8P Y8b // d88P 888 888 888 888 888 88888888 888 888 888 888 888 88888888 // d8888888888 888 Y88b. 888 888 Y8b. Y88b. Y88b 888 888 d88P Y8b. // d88P 888 888 "Y8888P 888 888 "Y8888 "Y888 "Y88888 88888P" "Y8888 // 888 888 // Y8b d88P 888 // "Y88P" 888 pragma solidity ^0.8.20; import "../ArchetypePayouts.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "solady/src/utils/MerkleProofLib.sol"; import "solady/src/utils/ECDSA.sol"; error InvalidConfig(); error MintNotYetStarted(); error MintEnded(); error WalletUnauthorizedToMint(); error InsufficientEthSent(); error ExcessiveEthSent(); error Erc20BalanceTooLow(); error MaxSupplyExceeded(); error ListMaxSupplyExceeded(); error NumberOfMintsExceeded(); error MintingPaused(); error InvalidReferral(); error InvalidSignature(); error MaxBatchSizeExceeded(); error NotTokenOwner(); error NotPlatform(); error NotOwner(); error NotShareholder(); error NotApprovedToTransfer(); error InvalidAmountOfTokens(); error WrongPassword(); error LockedForever(); error Blacklisted(); error URIQueryForNonexistentToken(); error invalidTokenIdLength(); error burnToRemintDisabled(); // // STRUCTS // struct Auth { bytes32 key; bytes32[] proof; } struct BonusDiscount { uint16 numMints; uint16 numBonusMints; } struct Config { string baseUri; address affiliateSigner; uint32 maxSupply; // in erc20 uint32 maxBatchSize; // in erc20 uint16 affiliateFee; //BPS uint16 affiliateDiscount; // BPS uint16 defaultRoyalty; //BPS uint16 remintPremium; //BPS premium for burning and reminting a new token uint16 erc20Ratio; // number of erc20 (10**18) equal to one nft } struct PayoutConfig { uint16 ownerBps; uint16 platformBps; uint16 partnerBps; uint16 superAffiliateBps; address partner; address superAffiliate; address ownerAltPayout; } struct AdvancedInvite { uint128 price; // in erc20 uint128 reservePrice; // in erc20 uint128 delta; // in erc20 uint32 maxSupply; // in erc20 uint32 limit; // in erc20 uint32 start; uint32 end; uint32 interval; uint32 unitSize; // mint 1 get x address tokenAddress; bool isBlacklist; } struct Invite { uint128 price; uint32 maxSupply; // in erc20 uint32 limit; // in erc20 uint32 start; uint32 end; uint32 unitSize; // mint 1 get x address tokenAddress; bool isBlacklist; } struct ValidationArgs { address owner; address affiliate; uint256 quantity; uint256 curSupply; uint256 listSupply; uint256 pairedSupply; } // UPDATE CONSTANTS BEFORE DEPLOY address constant PLATFORM = 0x86B82972282Dd22348374bC63fd21620F7ED847B; address constant BATCH = 0x6Bc558A6DC48dEfa0e7022713c23D65Ab26e4Fa7; address constant PAYOUTS = 0xaAfdfA4a935d8511bF285af11A0544ce7e4a1199; uint16 constant MAXBPS = 5000; // max fee or discount is 50% uint32 constant UINT32_MAX = 2**32 - 1; uint256 constant ERC20_UNIT = 10 ** 18; library ArchetypeLogicBurgers404 { // // EVENTS // event Invited(bytes32 indexed key, bytes32 indexed cid); event Referral(address indexed affiliate, address token, uint128 wad, uint256 numMints); event Withdrawal(address indexed src, address token, uint128 wad); // calculate price based on affiliate usage and mint discounts function computePrice( AdvancedInvite storage invite, uint16 affiliateDiscount, uint256 numTokens, uint256 listSupply, bool affiliateUsed ) public view returns (uint256) { uint256 price = invite.price; uint256 cost; if (invite.interval > 0 && invite.delta > 0) { // Apply dutch pricing uint256 diff = (((block.timestamp - invite.start) / invite.interval) * invite.delta); if (price > invite.reservePrice) { if (diff > price - invite.reservePrice) { price = invite.reservePrice; } else { price = price - diff; } } else if (price < invite.reservePrice) { if (diff > invite.reservePrice - price) { price = invite.reservePrice; } else { price = price + diff; } } cost = price * numTokens; } else if (invite.interval == 0 && invite.delta > 0) { // Apply linear curve uint256 lastPrice = price + invite.delta * listSupply; cost = lastPrice * numTokens + (invite.delta * numTokens * (numTokens - 1)) / 2; } else { cost = price * numTokens; } if (affiliateUsed) { cost = cost - ((cost * affiliateDiscount) / 10000); } return cost; } function bonusMintsAwarded(uint256 numNfts, uint256 packedDiscount) internal pure returns (uint256) { for (uint8 i = 0; i < 8; i++) { uint32 discount = uint32((packedDiscount >> (32 * i)) & 0xFFFFFFFF); uint16 tierNumMints = uint16(discount >> 16); uint16 tierBonusMints = uint16(discount); if (tierNumMints == 0) { break; // End of valid discounts } if (numNfts >= tierNumMints) { return (numNfts / tierNumMints) * tierBonusMints; } } return 0; } function validateMint( AdvancedInvite storage i, Config storage config, Auth calldata auth, mapping(address => mapping(bytes32 => uint256)) storage minted, bytes calldata signature, ValidationArgs memory args, uint128 cost ) public view { address msgSender = _msgSender(); if (args.affiliate != address(0)) { if ( args.affiliate == PLATFORM || args.affiliate == args.owner || args.affiliate == msgSender ) { revert InvalidReferral(); } validateAffiliate(args.affiliate, signature, config.affiliateSigner); } if (i.limit == 0) { revert MintingPaused(); } if (!i.isBlacklist) { if (!verify(auth, i.tokenAddress, msgSender)) { revert WalletUnauthorizedToMint(); } } else { if (verify(auth, i.tokenAddress, msgSender)) { revert Blacklisted(); } } if (block.timestamp < i.start) { revert MintNotYetStarted(); } if (i.end > i.start && block.timestamp > i.end) { revert MintEnded(); } if (i.limit < i.maxSupply) { uint256 totalAfterMint = minted[msgSender][auth.key] + args.quantity; if (totalAfterMint > i.limit) { revert NumberOfMintsExceeded(); } } if (i.maxSupply < config.maxSupply) { uint256 totalAfterMint = args.listSupply + args.pairedSupply + args.quantity; if (totalAfterMint > i.maxSupply) { revert ListMaxSupplyExceeded(); } } if (args.quantity > config.maxBatchSize) { revert MaxBatchSizeExceeded(); } if ((args.curSupply + args.quantity) > config.maxSupply) { revert MaxSupplyExceeded(); } if (i.tokenAddress != address(0)) { IERC20 erc20Token = IERC20(i.tokenAddress); if (erc20Token.allowance(msgSender, address(this)) < cost) { revert NotApprovedToTransfer(); } if (erc20Token.balanceOf(msgSender) < cost) { revert Erc20BalanceTooLow(); } if (msg.value != 0) { revert ExcessiveEthSent(); } } else { if (msg.value < cost) { revert InsufficientEthSent(); } } } function updateBalances( AdvancedInvite storage i, Config storage config, mapping(address => uint128) storage _ownerBalance, mapping(address => mapping(address => uint128)) storage _affiliateBalance, address affiliate, uint256 quantity, uint128 value ) public { address tokenAddress = i.tokenAddress; uint128 affiliateWad; if (affiliate != address(0)) { affiliateWad = (value * config.affiliateFee) / 10000; _affiliateBalance[affiliate][tokenAddress] += affiliateWad; emit Referral(affiliate, tokenAddress, affiliateWad, quantity); } uint128 balance = _ownerBalance[tokenAddress]; uint128 ownerWad = value - affiliateWad; _ownerBalance[tokenAddress] = balance + ownerWad; if (tokenAddress != address(0)) { IERC20 erc20Token = IERC20(tokenAddress); bool success = erc20Token.transferFrom(_msgSender(), address(this), value); if (!success) { revert TransferFailed(); } } } function withdrawTokensAffiliate( mapping(address => mapping(address => uint128)) storage _affiliateBalance, address[] calldata tokens ) public { address msgSender = _msgSender(); for (uint256 i; i < tokens.length; i++) { address tokenAddress = tokens[i]; uint128 wad = _affiliateBalance[msgSender][tokenAddress]; _affiliateBalance[msgSender][tokenAddress] = 0; if (wad == 0) { revert BalanceEmpty(); } if (tokenAddress == address(0)) { bool success = false; (success, ) = msgSender.call{ value: wad }(""); if (!success) { revert TransferFailed(); } } else { IERC20 erc20Token = IERC20(tokenAddress); bool success = erc20Token.transfer(msgSender, wad); if (!success) { revert TransferFailed(); } } emit Withdrawal(msgSender, tokenAddress, wad); } } function withdrawTokens( PayoutConfig storage payoutConfig, mapping(address => uint128) storage _ownerBalance, address owner, address[] calldata tokens ) public { address msgSender = _msgSender(); for (uint256 i; i < tokens.length; i++) { address tokenAddress = tokens[i]; uint128 wad; if ( msgSender == owner || msgSender == PLATFORM || msgSender == payoutConfig.partner || msgSender == payoutConfig.superAffiliate || msgSender == payoutConfig.ownerAltPayout ) { wad = _ownerBalance[tokenAddress]; _ownerBalance[tokenAddress] = 0; } else { revert NotShareholder(); } if (wad == 0) { revert BalanceEmpty(); } if (payoutConfig.ownerAltPayout == address(0)) { address[] memory recipients = new address[](4); recipients[0] = owner; recipients[1] = PLATFORM; recipients[2] = payoutConfig.partner; recipients[3] = payoutConfig.superAffiliate; uint16[] memory splits = new uint16[](4); splits[0] = payoutConfig.ownerBps; splits[1] = payoutConfig.platformBps; splits[2] = payoutConfig.partnerBps; splits[3] = payoutConfig.superAffiliateBps; if (tokenAddress == address(0)) { ArchetypePayouts(PAYOUTS).updateBalances{ value: wad }( wad, tokenAddress, recipients, splits ); } else { ArchetypePayouts(PAYOUTS).updateBalances(wad, tokenAddress, recipients, splits); } } else { uint256 ownerShare = (uint256(wad) * payoutConfig.ownerBps) / 10000; uint256 remainingShare = wad - ownerShare; if (tokenAddress == address(0)) { (bool success, ) = payable(payoutConfig.ownerAltPayout).call{ value: ownerShare }(""); if (!success) revert TransferFailed(); } else { IERC20(tokenAddress).transfer(payoutConfig.ownerAltPayout, ownerShare); } address[] memory recipients = new address[](3); recipients[0] = PLATFORM; recipients[1] = payoutConfig.partner; recipients[2] = payoutConfig.superAffiliate; uint16[] memory splits = new uint16[](3); uint16 remainingBps = 10000 - payoutConfig.ownerBps; splits[1] = uint16((uint256(payoutConfig.partnerBps) * 10000) / remainingBps); splits[2] = uint16((uint256(payoutConfig.superAffiliateBps) * 10000) / remainingBps); splits[0] = 10000 - splits[1] - splits[2]; if (tokenAddress == address(0)) { ArchetypePayouts(PAYOUTS).updateBalances{ value: remainingShare }( remainingShare, tokenAddress, recipients, splits ); } else { ArchetypePayouts(PAYOUTS).updateBalances( remainingShare, tokenAddress, recipients, splits ); } } emit Withdrawal(msgSender, tokenAddress, wad); } } function validateAffiliate( address affiliate, bytes calldata signature, address affiliateSigner ) public view { bytes32 signedMessagehash = ECDSA.toEthSignedMessageHash( keccak256(abi.encodePacked(affiliate)) ); address signer = ECDSA.recover(signedMessagehash, signature); if (signer != affiliateSigner) { revert InvalidSignature(); } } function verify( Auth calldata auth, address tokenAddress, address account ) public pure returns (bool) { // keys 0-255 and tokenAddress are public if (uint256(auth.key) <= 0xff || auth.key == keccak256(abi.encodePacked(tokenAddress))) { return true; } return MerkleProofLib.verify(auth.proof, auth.key, keccak256(abi.encodePacked(account))); } function _msgSender() internal view returns (address) { return msg.sender == BATCH ? tx.origin : msg.sender; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface 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 amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // ArchetypePayouts v0.7.0 // // d8888 888 888 // d88888 888 888 // d88P888 888 888 // d88P 888 888d888 .d8888b 88888b. .d88b. 888888 888 888 88888b. .d88b. // d88P 888 888P" d88P" 888 "88b d8P Y8b 888 888 888 888 "88b d8P Y8b // d88P 888 888 888 888 888 88888888 888 888 888 888 888 88888888 // d8888888888 888 Y88b. 888 888 Y8b. Y88b. Y88b 888 888 d88P Y8b. // d88P 888 888 "Y8888P 888 888 "Y8888 "Y888 "Y88888 88888P" "Y8888 // 888 888 // Y8b d88P 888 // pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; error InvalidLength(); error InvalidSplitShares(); error TransferFailed(); error BalanceEmpty(); error NotApprovedToWithdraw(); contract ArchetypePayouts { event Withdrawal(address indexed src, address token, uint256 wad); event FundsAdded(address indexed recipient, address token, uint256 amount); mapping(address => mapping(address => uint256)) private _balance; mapping(address => mapping(address => bool)) private _approvals; function updateBalances( uint256 totalAmount, address token, address[] calldata recipients, uint16[] calldata splits ) public payable { if (recipients.length != splits.length) { revert InvalidLength(); } uint256 totalShares = 0; for (uint256 i = 0; i < splits.length; i++) { totalShares += splits[i]; } if (totalShares != 10000) { revert InvalidSplitShares(); } if (token == address(0)) { // ETH payments uint256 totalReceived = msg.value; for (uint256 i = 0; i < recipients.length; i++) { if (splits[i] > 0) { uint256 amountToAdd = (totalReceived * splits[i]) / 10000; _balance[recipients[i]][token] += amountToAdd; emit FundsAdded(recipients[i], token, amountToAdd); } } } else { // ERC20 payments IERC20 paymentToken = IERC20(token); bool success = paymentToken.transferFrom(msg.sender, address(this), totalAmount); if (!success) { revert TransferFailed(); } for (uint256 i = 0; i < recipients.length; i++) { if (splits[i] > 0) { uint256 amountToAdd = (totalAmount * splits[i]) / 10000; _balance[recipients[i]][token] += amountToAdd; emit FundsAdded(recipients[i], token, amountToAdd); } } } } function withdraw() external { address msgSender = msg.sender; _withdraw(msgSender, msgSender, address(0)); } function withdrawTokens(address[] memory tokens) external { address msgSender = msg.sender; for (uint256 i = 0; i < tokens.length; i++) { _withdraw(msgSender, msgSender, tokens[i]); } } function withdrawFrom(address from, address to) public { if (from != msg.sender && !_approvals[from][to]) { revert NotApprovedToWithdraw(); } _withdraw(from, to, address(0)); } function withdrawTokensFrom( address from, address to, address[] memory tokens ) public { if (from != msg.sender && !_approvals[from][to]) { revert NotApprovedToWithdraw(); } for (uint256 i = 0; i < tokens.length; i++) { _withdraw(from, to, tokens[i]); } } function _withdraw( address from, address to, address token ) internal { uint256 wad; wad = _balance[from][token]; _balance[from][token] = 0; if (wad == 0) { revert BalanceEmpty(); } if (token == address(0)) { bool success = false; (success, ) = to.call{ value: wad }(""); if (!success) { revert TransferFailed(); } } else { IERC20 erc20Token = IERC20(token); bool success = erc20Token.transfer(to, wad); if (!success) { revert TransferFailed(); } } emit Withdrawal(from, token, wad); } function approveWithdrawal(address delegate, bool approved) external { _approvals[msg.sender][delegate] = approved; } function isApproved(address from, address delegate) external view returns (bool) { return _approvals[from][delegate]; } function balance(address recipient) external view returns (uint256) { return _balance[recipient][address(0)]; } function balanceToken(address recipient, address token) external view returns (uint256) { return _balance[recipient][token]; } }
// 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 { result := 1 let m := mload(0x40) // Cache the free memory pointer. for {} 1 {} { mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. break } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. break } result := 0 break } result := mload( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `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`. function recoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) for {} 1 {} { if eq(signature.length, 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`. break } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. break } result := 0 break } result := mload( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `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 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(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `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(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `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 { result := 1 let m := mload(0x40) // Cache the free memory pointer. for {} 1 {} { mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. break } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. break } result := 0 break } pop( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) 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`. function tryRecoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) for {} 1 {} { if eq(signature.length, 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`. break } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. break } result := 0 break } pop( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) 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 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(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) 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(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) 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 { let l := signature.length for {} 1 {} { mstore(0x00, calldataload(signature.offset)) // `r`. let s := calldataload(add(signature.offset, 0x20)) let v := calldataload(add(signature.offset, 0x21)) 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)) { calldatacopy(mload(0x40), signature.offset, l) // `bytes4(keccak256("InvalidSignatureLength"))`. result := xor(keccak256(mload(0x40), l), 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.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 } } }
{ "optimizer": { "enabled": true, "runs": 1 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"BalanceEmpty","type":"error"},{"inputs":[],"name":"Blacklisted","type":"error"},{"inputs":[],"name":"Erc20BalanceTooLow","type":"error"},{"inputs":[],"name":"ExcessiveEthSent","type":"error"},{"inputs":[],"name":"InsufficientEthSent","type":"error"},{"inputs":[],"name":"InvalidReferral","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"ListMaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MaxBatchSizeExceeded","type":"error"},{"inputs":[],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[],"name":"MintEnded","type":"error"},{"inputs":[],"name":"MintNotYetStarted","type":"error"},{"inputs":[],"name":"MintingPaused","type":"error"},{"inputs":[],"name":"NotApprovedToTransfer","type":"error"},{"inputs":[],"name":"NotShareholder","type":"error"},{"inputs":[],"name":"NumberOfMintsExceeded","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WalletUnauthorizedToMint","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"key","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"cid","type":"bytes32"}],"name":"Invited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"numMints","type":"uint256"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint128","name":"wad","type":"uint128"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"affiliateSigner","type":"address"}],"name":"validateAffiliate","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"key","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"internalType":"struct Auth","name":"auth","type":"tuple"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
6120bb61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100775760003560e01c8063140fbc851461007c5780632a70e5821461009e57806332cef8f0146100c657806340fe1ac7146100e65780634c1b6fbc146100f9578063704c38fc1461010c5780638e1ab8661461012d575b600080fd5b81801561008857600080fd5b5061009c61009736600461194a565b61014d565b005b6100b16100ac3660046119c9565b61036a565b60405190151581526020015b60405180910390f35b8180156100d257600080fd5b5061009c6100e1366004611a3d565b61042d565b61009c6100f4366004611ae1565b610687565b61009c610107366004611b45565b61075e565b61011f61011a366004611c81565b610cb5565b6040519081526020016100bd565b81801561013957600080fd5b5061009c610148366004611cde565b610efb565b6000610157611805565b905060005b8281101561036357600084848381811061017857610178611d45565b905060200201602081019061018d9190611d5b565b6001600160a01b03848116600090815260208981526040808320938516835292905290812080546001600160801b031981169091559192506001600160801b03909116908190036101f1576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610284576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610255576040519150601f19603f3d011682016040523d82523d6000602084013e61025a565b606091505b5050809150508061027e576040516312171d8360e31b815260040160405180910390fd5b5061031d565b60405163a9059cbb60e01b815282906000906001600160a01b0383169063a9059cbb906102b79089908790600401611d76565b6020604051808303816000875af11580156102d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102fa9190611d98565b90508061031a576040516312171d8360e31b815260040160405180910390fd5b50505b836001600160a01b03166000805160206120668339815191528383604051610346929190611d76565b60405180910390a25050808061035b90611dcb565b91505061015c565b5050505050565b600060ff84351115806103a65750826040516020016103899190611de4565b604051602081830303815290604052805190602001208460000135145b156103b357506001610426565b6104236103c36020860186611dfc565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040518835925061040891508690602001611de4565b6040516020818303038152906040528051906020012061182c565b90505b9392505050565b60028701546001600160a01b03600160401b9091048116906000908516156105495760018801546127109061046d90600160e01b900461ffff1685611e45565b6104779190611e86565b6001600160a01b038087166000908152602089815260408083209387168352929052908120805492935083929091906104ba9084906001600160801b0316611eac565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b20838387604051610540939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906105768386611ed3565b90506105828183611eac565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b0393909316929092179091551561067a578360006001600160a01b0382166323b872dd6105d8611805565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201523060248201526001600160801b038a1660448201526064016020604051808303816000875af1158015610633573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106579190611d98565b905080610677576040516312171d8360e31b815260040160405180910390fd5b50505b5050505050505050505050565b60006106de8560405160200161069d9190611de4565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b905060006107228286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061186e92505050565b9050826001600160a01b0316816001600160a01b03161461075657604051638baa579f60e01b815260040160405180910390fd5b505050505050565b6000610768611805565b60208401519091506001600160a01b0316156108255760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806107c6575082600001516001600160a01b031683602001516001600160a01b0316145b806107e65750806001600160a01b031683602001516001600160a01b0316145b156108045760405163119833d760e11b815260040160405180910390fd5b602083015160018901546108259190879087906001600160a01b0316610687565b6001890154600160a01b900463ffffffff16600003610857576040516375ab03ab60e11b815260040160405180910390fd5b6002890154600160e01b900460ff166108ad57600289015461088b908890600160401b90046001600160a01b03168361036a565b6108a85760405163d838648f60e01b815260040160405180910390fd5b6108ec565b60028901546108ce908890600160401b90046001600160a01b03168361036a565b156108ec576040516309550c7760e01b815260040160405180910390fd5b6001890154600160c01b900463ffffffff1642101561091e57604051630e91d3a160e11b815260040160405180910390fd5b600189015463ffffffff600160c01b82048116600160e01b9092041611801561095757506001890154600160e01b900463ffffffff1642115b156109755760405163124212e560e21b815260040160405180910390fd5b600189015463ffffffff600160801b82048116600160a01b9092041610156109ff576040808401516001600160a01b038316600090815260208981528382208b3583529052918220546109c89190611ef3565b60018b0154909150600160a01b900463ffffffff168111156109fd576040516315fcbc9d60e01b815260040160405180910390fd5b505b600188810154908a0154600160a01b90910463ffffffff908116600160801b909204161015610a8457600083604001518460a001518560800151610a439190611ef3565b610a4d9190611ef3565b60018b0154909150600160801b900463ffffffff16811115610a825760405163103f447360e31b815260040160405180910390fd5b505b60018801546040840151600160c01b90910463ffffffff161015610abb57604051637a7e96df60e01b815260040160405180910390fd5b600188015460408401516060850151600160a01b90920463ffffffff1691610ae39190611ef3565b1115610b0257604051638a164f6360e01b815260040160405180910390fd5b6002890154600160401b90046001600160a01b031615610c80576002890154604051636eb1769f60e11b81526001600160a01b038381166004830152306024830152600160401b909204909116906001600160801b03841690829063dd62ed3e90604401602060405180830381865afa158015610b83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba79190611f0c565b1015610bc6576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0383811660048301526001600160801b03851691908316906370a0823190602401602060405180830381865afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190611f0c565b1015610c5b5760405163046abae760e31b815260040160405180910390fd5b3415610c7a576040516301b2422760e61b815260040160405180910390fd5b50610caa565b816001600160801b0316341015610caa5760405163f244866f60e01b815260040160405180910390fd5b505050505050505050565b845460028601546000916001600160801b031690829063ffffffff1615801590610ceb575060018801546001600160801b031615155b15610e1657600188015460028901546000916001600160801b0381169163ffffffff90811691610d2491600160c01b9091041642611f25565b610d2e9190611f38565b610d389190611f4c565b8954909150600160801b90046001600160801b0316831115610da1578854610d7090600160801b90046001600160801b031684611f25565b811115610d90578854600160801b90046001600160801b03169250610e04565b610d9a8184611f25565b9250610e04565b8854600160801b90046001600160801b0316831015610e04578854610dd7908490600160801b90046001600160801b0316611f25565b811115610df7578854600160801b90046001600160801b03169250610e04565b610e018184611ef3565b92505b610e0e8784611f4c565b915050610ec2565b600288015463ffffffff16158015610e3a575060018801546001600160801b031615155b15610eb5576001880154600090610e5b9087906001600160801b0316611f4c565b610e659084611ef3565b90506002610e74600189611f25565b60018b0154610e8d908a906001600160801b0316611f4c565b610e979190611f4c565b610ea19190611f38565b610eab8883611f4c565b610e0e9190611ef3565b610ebf8683611f4c565b90505b8315610ef057612710610ed961ffff891683611f4c565b610ee39190611f38565b610eed9082611f25565b90505b979650505050505050565b6000610f05611805565b905060005b828110156117fc576000848483818110610f2657610f26611d45565b9050602002016020810190610f3b9190611d5b565b90506000866001600160a01b0316846001600160a01b03161480610f7b57506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80610f99575088546001600160a01b03858116600160401b90920416145b80610fb3575060018901546001600160a01b038581169116145b80610fcd575060028901546001600160a01b038581169116145b1561100957506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b0316611022565b60405163650a61e160e01b815260040160405180910390fd5b806001600160801b031660000361104c576040516321cd723f60e21b815260040160405180910390fd5b60028901546001600160a01b03166113575760408051600480825260a0820190925260009160208201608080368337019050509050878160008151811061109557611095611d45565b60200260200101906001600160a01b031690816001600160a01b0316815250507386b82972282dd22348374bc63fd21620f7ed847b816001815181106110dd576110dd611d45565b6001600160a01b0392831660209182029290920101528a548251600160401b909104909116908290600290811061111657611116611d45565b6001600160a01b03928316602091820292909201015260018b015482519116908290600390811061114957611149611d45565b6001600160a01b039290921660209283029190910182015260408051600480825260a08201909252600092909190820160808036833750508c54825192935061ffff169183915060009061119f5761119f611d45565b61ffff92831660209182029290920101528b5482516201000090910490911690829060019081106111d2576111d2611d45565b61ffff92831660209182029290920101528b548251600160201b909104909116908290600290811061120657611206611d45565b61ffff92831660209182029290920101528b548251600160301b909104909116908290600390811061123a5761123a611d45565b61ffff909216602092830291909101909101526001600160a01b0384166112dd576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906001600160801b038616906112a6908790899088908890600401611fdb565b6000604051808303818588803b1580156112bf57600080fd5b505af11580156112d3573d6000803e3d6000fd5b5050505050611350565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061131d908690889087908790600401611fdb565b600060405180830381600087803b15801561133757600080fd5b505af115801561134b573d6000803e3d6000fd5b505050505b50506117b6565b8854600090612710906113779061ffff166001600160801b038516611f4c565b6113819190611f38565b90506000611398826001600160801b038516611f25565b90506001600160a01b0384166114245760028b01546040516000916001600160a01b03169084908381818185875af1925050503d80600081146113f7576040519150601f19603f3d011682016040523d82523d6000602084013e6113fc565b606091505b505090508061141e576040516312171d8360e31b815260040160405180910390fd5b5061149f565b60028b015460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018490529085169063a9059cbb906044016020604051808303816000875af1158015611479573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149d9190611d98565b505b60408051600380825260808201909252600091602082016060803683370190505090507386b82972282dd22348374bc63fd21620f7ed847b816000815181106114ea576114ea611d45565b6001600160a01b0392831660209182029290920101528c548251600160401b909104909116908290600190811061152357611523611d45565b6001600160a01b03928316602091820292909201015260018d015482519116908290600290811061155657611556611d45565b6001600160a01b039290921660209283029190910182015260408051600380825260808201909252600092909190820160608036833750508e549192506000916115a7915061ffff16612710612020565b8e5490915061ffff808316916115c891600160201b90910416612710611f4c565b6115d29190611f38565b826001815181106115e5576115e5611d45565b61ffff92831660209182029290920101528e548282169161161091600160301b900416612710611f4c565b61161a9190611f38565b8260028151811061162d5761162d611d45565b602002602001019061ffff16908161ffff16815250508160028151811061165657611656611d45565b60200260200101518260018151811061167157611671611d45565b60200260200101516127106116869190612020565b6116909190612020565b826000815181106116a3576116a3611d45565b61ffff909216602092830291909101909101526001600160a01b03871661173d576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9086906117069082908c908990899060040161203b565b6000604051808303818588803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b50505050506117b0565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061177d9087908b908890889060040161203b565b600060405180830381600087803b15801561179757600080fd5b505af11580156117ab573d6000803e3d6000fd5b505050505b50505050505b836001600160a01b031660008051602061206683398151915283836040516117df929190611d76565b60405180910390a2505080806117f490611dcb565b915050610f0a565b50505050505050565b600033736bc558a6dc48defa0e7022713c23d65ab26e4fa71461182757503390565b503290565b60008351156118675760208401845160051b81015b8151841160051b9384528151602094851852604060002093909101908082106118415750505b5014919050565b60405160019083600052602083015160405260408351036118aa57604083015160ff81901c601b016020526001600160ff1b03166060526118d0565b60418351036118cb57606083015160001a60205260408301516060526118d0565b600091505b6020600160806000855afa5191503d6118f157638baa579f6000526004601cfd5b600060605260405292915050565b60008083601f84011261191157600080fd5b5081356001600160401b0381111561192857600080fd5b6020830191508360208260051b850101111561194357600080fd5b9250929050565b60008060006040848603121561195f57600080fd5b8335925060208401356001600160401b0381111561197c57600080fd5b611988868287016118ff565b9497909650939450505050565b6000604082840312156119a757600080fd5b50919050565b80356001600160a01b03811681146119c457600080fd5b919050565b6000806000606084860312156119de57600080fd5b83356001600160401b038111156119f457600080fd5b611a0086828701611995565b935050611a0f602085016119ad565b9150611a1d604085016119ad565b90509250925092565b80356001600160801b03811681146119c457600080fd5b600080600080600080600060e0888a031215611a5857600080fd5b87359650602088013595506040880135945060608801359350611a7d608089016119ad565b925060a08801359150611a9260c08901611a26565b905092959891949750929550565b60008083601f840112611ab257600080fd5b5081356001600160401b03811115611ac957600080fd5b60208301915083602082850101111561194357600080fd5b60008060008060608587031215611af757600080fd5b611b00856119ad565b935060208501356001600160401b03811115611b1b57600080fd5b611b2787828801611aa0565b9094509250611b3a9050604086016119ad565b905092959194509250565b600080600080600080600080888a03610180811215611b6357600080fd5b8935985060208a0135975060408a01356001600160401b0380821115611b8857600080fd5b611b948d838e01611995565b985060608c0135975060808c0135915080821115611bb157600080fd5b611bbd8d838e01611aa0565b909750955085915060c0609f1984011215611bd757600080fd5b604051925060c0830191508282108183111715611c0457634e487b7160e01b600052604160045260246000fd5b50604052611c1460a08b016119ad565b8152611c2260c08b016119ad565b602082015260e08a013560408201526101008a013560608201526101208a013560808201526101408a013560a08201529150611c616101608a01611a26565b90509295985092959890939650565b8015158114611c7e57600080fd5b50565b600080600080600060a08688031215611c9957600080fd5b85359450602086013561ffff81168114611cb257600080fd5b935060408601359250606086013591506080860135611cd081611c70565b809150509295509295909350565b600080600080600060808688031215611cf657600080fd5b8535945060208601359350611d0d604087016119ad565b925060608601356001600160401b03811115611d2857600080fd5b611d34888289016118ff565b969995985093965092949392505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611d6d57600080fd5b610426826119ad565b6001600160a01b039290921682526001600160801b0316602082015260400190565b600060208284031215611daa57600080fd5b815161042681611c70565b634e487b7160e01b600052601160045260246000fd5b600060018201611ddd57611ddd611db5565b5060010190565b60609190911b6001600160601b031916815260140190565b6000808335601e19843603018112611e1357600080fd5b8301803591506001600160401b03821115611e2d57600080fd5b6020019150600581901b360382131561194357600080fd5b6001600160801b03818116838216028082169190828114611e6857611e68611db5565b505092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160801b0383811680611ea057611ea0611e70565b92169190910492915050565b6001600160801b03818116838216019080821115611ecc57611ecc611db5565b5092915050565b6001600160801b03828116828216039080821115611ecc57611ecc611db5565b80820180821115611f0657611f06611db5565b92915050565b600060208284031215611f1e57600080fd5b5051919050565b81810381811115611f0657611f06611db5565b600082611f4757611f47611e70565b500490565b8082028115828204841417611f0657611f06611db5565b600081518084526020808501945080840160005b83811015611f9c5781516001600160a01b031687529582019590820190600101611f77565b509495945050505050565b600081518084526020808501945080840160005b83811015611f9c57815161ffff1687529582019590820190600101611fbb565b6001600160801b03851681526001600160a01b038416602082015260806040820181905260009061200e90830185611f63565b8281036060840152610ef08185611fa7565b61ffff828116828216039080821115611ecc57611ecc611db5565b8481526001600160a01b038416602082015260806040820181905260009061200e90830185611f6356fe02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f49a2646970667358221220ad23ff0540a7c461be1f7a0cbf6bd66283221db6cf4da22e1bc24d37984945f964736f6c63430008140033
Deployed Bytecode
0x73d4e182124131fe5f3bde4cdef00975fb97f5b3d830146080604052600436106100775760003560e01c8063140fbc851461007c5780632a70e5821461009e57806332cef8f0146100c657806340fe1ac7146100e65780634c1b6fbc146100f9578063704c38fc1461010c5780638e1ab8661461012d575b600080fd5b81801561008857600080fd5b5061009c61009736600461194a565b61014d565b005b6100b16100ac3660046119c9565b61036a565b60405190151581526020015b60405180910390f35b8180156100d257600080fd5b5061009c6100e1366004611a3d565b61042d565b61009c6100f4366004611ae1565b610687565b61009c610107366004611b45565b61075e565b61011f61011a366004611c81565b610cb5565b6040519081526020016100bd565b81801561013957600080fd5b5061009c610148366004611cde565b610efb565b6000610157611805565b905060005b8281101561036357600084848381811061017857610178611d45565b905060200201602081019061018d9190611d5b565b6001600160a01b03848116600090815260208981526040808320938516835292905290812080546001600160801b031981169091559192506001600160801b03909116908190036101f1576040516321cd723f60e21b815260040160405180910390fd5b6001600160a01b038216610284576000846001600160a01b0316826001600160801b031660405160006040518083038185875af1925050503d8060008114610255576040519150601f19603f3d011682016040523d82523d6000602084013e61025a565b606091505b5050809150508061027e576040516312171d8360e31b815260040160405180910390fd5b5061031d565b60405163a9059cbb60e01b815282906000906001600160a01b0383169063a9059cbb906102b79089908790600401611d76565b6020604051808303816000875af11580156102d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102fa9190611d98565b90508061031a576040516312171d8360e31b815260040160405180910390fd5b50505b836001600160a01b03166000805160206120668339815191528383604051610346929190611d76565b60405180910390a25050808061035b90611dcb565b91505061015c565b5050505050565b600060ff84351115806103a65750826040516020016103899190611de4565b604051602081830303815290604052805190602001208460000135145b156103b357506001610426565b6104236103c36020860186611dfc565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040518835925061040891508690602001611de4565b6040516020818303038152906040528051906020012061182c565b90505b9392505050565b60028701546001600160a01b03600160401b9091048116906000908516156105495760018801546127109061046d90600160e01b900461ffff1685611e45565b6104779190611e86565b6001600160a01b038087166000908152602089815260408083209387168352929052908120805492935083929091906104ba9084906001600160801b0316611eac565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550846001600160a01b03167f8abfbe92bb62ff992ef6347c68d007f25a6e5aea2ad2f05e89f3486947cc0b20838387604051610540939291906001600160a01b039390931683526001600160801b03919091166020830152604082015260600190565b60405180910390a25b6001600160a01b0382166000908152602088905260408120546001600160801b0316906105768386611ed3565b90506105828183611eac565b6001600160a01b038516600081815260208c90526040902080546001600160801b0319166001600160801b0393909316929092179091551561067a578360006001600160a01b0382166323b872dd6105d8611805565b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201523060248201526001600160801b038a1660448201526064016020604051808303816000875af1158015610633573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106579190611d98565b905080610677576040516312171d8360e31b815260040160405180910390fd5b50505b5050505050505050505050565b60006106de8560405160200161069d9190611de4565b604051602081830303815290604052805190602001206020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b905060006107228286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061186e92505050565b9050826001600160a01b0316816001600160a01b03161461075657604051638baa579f60e01b815260040160405180910390fd5b505050505050565b6000610768611805565b60208401519091506001600160a01b0316156108255760208301516001600160a01b03167386b82972282dd22348374bc63fd21620f7ed847b14806107c6575082600001516001600160a01b031683602001516001600160a01b0316145b806107e65750806001600160a01b031683602001516001600160a01b0316145b156108045760405163119833d760e11b815260040160405180910390fd5b602083015160018901546108259190879087906001600160a01b0316610687565b6001890154600160a01b900463ffffffff16600003610857576040516375ab03ab60e11b815260040160405180910390fd5b6002890154600160e01b900460ff166108ad57600289015461088b908890600160401b90046001600160a01b03168361036a565b6108a85760405163d838648f60e01b815260040160405180910390fd5b6108ec565b60028901546108ce908890600160401b90046001600160a01b03168361036a565b156108ec576040516309550c7760e01b815260040160405180910390fd5b6001890154600160c01b900463ffffffff1642101561091e57604051630e91d3a160e11b815260040160405180910390fd5b600189015463ffffffff600160c01b82048116600160e01b9092041611801561095757506001890154600160e01b900463ffffffff1642115b156109755760405163124212e560e21b815260040160405180910390fd5b600189015463ffffffff600160801b82048116600160a01b9092041610156109ff576040808401516001600160a01b038316600090815260208981528382208b3583529052918220546109c89190611ef3565b60018b0154909150600160a01b900463ffffffff168111156109fd576040516315fcbc9d60e01b815260040160405180910390fd5b505b600188810154908a0154600160a01b90910463ffffffff908116600160801b909204161015610a8457600083604001518460a001518560800151610a439190611ef3565b610a4d9190611ef3565b60018b0154909150600160801b900463ffffffff16811115610a825760405163103f447360e31b815260040160405180910390fd5b505b60018801546040840151600160c01b90910463ffffffff161015610abb57604051637a7e96df60e01b815260040160405180910390fd5b600188015460408401516060850151600160a01b90920463ffffffff1691610ae39190611ef3565b1115610b0257604051638a164f6360e01b815260040160405180910390fd5b6002890154600160401b90046001600160a01b031615610c80576002890154604051636eb1769f60e11b81526001600160a01b038381166004830152306024830152600160401b909204909116906001600160801b03841690829063dd62ed3e90604401602060405180830381865afa158015610b83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba79190611f0c565b1015610bc6576040516302df483560e21b815260040160405180910390fd5b6040516370a0823160e01b81526001600160a01b0383811660048301526001600160801b03851691908316906370a0823190602401602060405180830381865afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190611f0c565b1015610c5b5760405163046abae760e31b815260040160405180910390fd5b3415610c7a576040516301b2422760e61b815260040160405180910390fd5b50610caa565b816001600160801b0316341015610caa5760405163f244866f60e01b815260040160405180910390fd5b505050505050505050565b845460028601546000916001600160801b031690829063ffffffff1615801590610ceb575060018801546001600160801b031615155b15610e1657600188015460028901546000916001600160801b0381169163ffffffff90811691610d2491600160c01b9091041642611f25565b610d2e9190611f38565b610d389190611f4c565b8954909150600160801b90046001600160801b0316831115610da1578854610d7090600160801b90046001600160801b031684611f25565b811115610d90578854600160801b90046001600160801b03169250610e04565b610d9a8184611f25565b9250610e04565b8854600160801b90046001600160801b0316831015610e04578854610dd7908490600160801b90046001600160801b0316611f25565b811115610df7578854600160801b90046001600160801b03169250610e04565b610e018184611ef3565b92505b610e0e8784611f4c565b915050610ec2565b600288015463ffffffff16158015610e3a575060018801546001600160801b031615155b15610eb5576001880154600090610e5b9087906001600160801b0316611f4c565b610e659084611ef3565b90506002610e74600189611f25565b60018b0154610e8d908a906001600160801b0316611f4c565b610e979190611f4c565b610ea19190611f38565b610eab8883611f4c565b610e0e9190611ef3565b610ebf8683611f4c565b90505b8315610ef057612710610ed961ffff891683611f4c565b610ee39190611f38565b610eed9082611f25565b90505b979650505050505050565b6000610f05611805565b905060005b828110156117fc576000848483818110610f2657610f26611d45565b9050602002016020810190610f3b9190611d5b565b90506000866001600160a01b0316846001600160a01b03161480610f7b57506001600160a01b0384167386b82972282dd22348374bc63fd21620f7ed847b145b80610f99575088546001600160a01b03858116600160401b90920416145b80610fb3575060018901546001600160a01b038581169116145b80610fcd575060028901546001600160a01b038581169116145b1561100957506001600160a01b038116600090815260208890526040902080546001600160801b031981169091556001600160801b0316611022565b60405163650a61e160e01b815260040160405180910390fd5b806001600160801b031660000361104c576040516321cd723f60e21b815260040160405180910390fd5b60028901546001600160a01b03166113575760408051600480825260a0820190925260009160208201608080368337019050509050878160008151811061109557611095611d45565b60200260200101906001600160a01b031690816001600160a01b0316815250507386b82972282dd22348374bc63fd21620f7ed847b816001815181106110dd576110dd611d45565b6001600160a01b0392831660209182029290920101528a548251600160401b909104909116908290600290811061111657611116611d45565b6001600160a01b03928316602091820292909201015260018b015482519116908290600390811061114957611149611d45565b6001600160a01b039290921660209283029190910182015260408051600480825260a08201909252600092909190820160808036833750508c54825192935061ffff169183915060009061119f5761119f611d45565b61ffff92831660209182029290920101528b5482516201000090910490911690829060019081106111d2576111d2611d45565b61ffff92831660209182029290920101528b548251600160201b909104909116908290600290811061120657611206611d45565b61ffff92831660209182029290920101528b548251600160301b909104909116908290600390811061123a5761123a611d45565b61ffff909216602092830291909101909101526001600160a01b0384166112dd576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e906001600160801b038616906112a6908790899088908890600401611fdb565b6000604051808303818588803b1580156112bf57600080fd5b505af11580156112d3573d6000803e3d6000fd5b5050505050611350565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061131d908690889087908790600401611fdb565b600060405180830381600087803b15801561133757600080fd5b505af115801561134b573d6000803e3d6000fd5b505050505b50506117b6565b8854600090612710906113779061ffff166001600160801b038516611f4c565b6113819190611f38565b90506000611398826001600160801b038516611f25565b90506001600160a01b0384166114245760028b01546040516000916001600160a01b03169084908381818185875af1925050503d80600081146113f7576040519150601f19603f3d011682016040523d82523d6000602084013e6113fc565b606091505b505090508061141e576040516312171d8360e31b815260040160405180910390fd5b5061149f565b60028b015460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018490529085169063a9059cbb906044016020604051808303816000875af1158015611479573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149d9190611d98565b505b60408051600380825260808201909252600091602082016060803683370190505090507386b82972282dd22348374bc63fd21620f7ed847b816000815181106114ea576114ea611d45565b6001600160a01b0392831660209182029290920101528c548251600160401b909104909116908290600190811061152357611523611d45565b6001600160a01b03928316602091820292909201015260018d015482519116908290600290811061155657611556611d45565b6001600160a01b039290921660209283029190910182015260408051600380825260808201909252600092909190820160608036833750508e549192506000916115a7915061ffff16612710612020565b8e5490915061ffff808316916115c891600160201b90910416612710611f4c565b6115d29190611f38565b826001815181106115e5576115e5611d45565b61ffff92831660209182029290920101528e548282169161161091600160301b900416612710611f4c565b61161a9190611f38565b8260028151811061162d5761162d611d45565b602002602001019061ffff16908161ffff16815250508160028151811061165657611656611d45565b60200260200101518260018151811061167157611671611d45565b60200260200101516127106116869190612020565b6116909190612020565b826000815181106116a3576116a3611d45565b61ffff909216602092830291909101909101526001600160a01b03871661173d576040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9086906117069082908c908990899060040161203b565b6000604051808303818588803b15801561171f57600080fd5b505af1158015611733573d6000803e3d6000fd5b50505050506117b0565b6040516001627d6bf960e11b0319815273aafdfa4a935d8511bf285af11a0544ce7e4a11999063ff05280e9061177d9087908b908890889060040161203b565b600060405180830381600087803b15801561179757600080fd5b505af11580156117ab573d6000803e3d6000fd5b505050505b50505050505b836001600160a01b031660008051602061206683398151915283836040516117df929190611d76565b60405180910390a2505080806117f490611dcb565b915050610f0a565b50505050505050565b600033736bc558a6dc48defa0e7022713c23d65ab26e4fa71461182757503390565b503290565b60008351156118675760208401845160051b81015b8151841160051b9384528151602094851852604060002093909101908082106118415750505b5014919050565b60405160019083600052602083015160405260408351036118aa57604083015160ff81901c601b016020526001600160ff1b03166060526118d0565b60418351036118cb57606083015160001a60205260408301516060526118d0565b600091505b6020600160806000855afa5191503d6118f157638baa579f6000526004601cfd5b600060605260405292915050565b60008083601f84011261191157600080fd5b5081356001600160401b0381111561192857600080fd5b6020830191508360208260051b850101111561194357600080fd5b9250929050565b60008060006040848603121561195f57600080fd5b8335925060208401356001600160401b0381111561197c57600080fd5b611988868287016118ff565b9497909650939450505050565b6000604082840312156119a757600080fd5b50919050565b80356001600160a01b03811681146119c457600080fd5b919050565b6000806000606084860312156119de57600080fd5b83356001600160401b038111156119f457600080fd5b611a0086828701611995565b935050611a0f602085016119ad565b9150611a1d604085016119ad565b90509250925092565b80356001600160801b03811681146119c457600080fd5b600080600080600080600060e0888a031215611a5857600080fd5b87359650602088013595506040880135945060608801359350611a7d608089016119ad565b925060a08801359150611a9260c08901611a26565b905092959891949750929550565b60008083601f840112611ab257600080fd5b5081356001600160401b03811115611ac957600080fd5b60208301915083602082850101111561194357600080fd5b60008060008060608587031215611af757600080fd5b611b00856119ad565b935060208501356001600160401b03811115611b1b57600080fd5b611b2787828801611aa0565b9094509250611b3a9050604086016119ad565b905092959194509250565b600080600080600080600080888a03610180811215611b6357600080fd5b8935985060208a0135975060408a01356001600160401b0380821115611b8857600080fd5b611b948d838e01611995565b985060608c0135975060808c0135915080821115611bb157600080fd5b611bbd8d838e01611aa0565b909750955085915060c0609f1984011215611bd757600080fd5b604051925060c0830191508282108183111715611c0457634e487b7160e01b600052604160045260246000fd5b50604052611c1460a08b016119ad565b8152611c2260c08b016119ad565b602082015260e08a013560408201526101008a013560608201526101208a013560808201526101408a013560a08201529150611c616101608a01611a26565b90509295985092959890939650565b8015158114611c7e57600080fd5b50565b600080600080600060a08688031215611c9957600080fd5b85359450602086013561ffff81168114611cb257600080fd5b935060408601359250606086013591506080860135611cd081611c70565b809150509295509295909350565b600080600080600060808688031215611cf657600080fd5b8535945060208601359350611d0d604087016119ad565b925060608601356001600160401b03811115611d2857600080fd5b611d34888289016118ff565b969995985093965092949392505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611d6d57600080fd5b610426826119ad565b6001600160a01b039290921682526001600160801b0316602082015260400190565b600060208284031215611daa57600080fd5b815161042681611c70565b634e487b7160e01b600052601160045260246000fd5b600060018201611ddd57611ddd611db5565b5060010190565b60609190911b6001600160601b031916815260140190565b6000808335601e19843603018112611e1357600080fd5b8301803591506001600160401b03821115611e2d57600080fd5b6020019150600581901b360382131561194357600080fd5b6001600160801b03818116838216028082169190828114611e6857611e68611db5565b505092915050565b634e487b7160e01b600052601260045260246000fd5b60006001600160801b0383811680611ea057611ea0611e70565b92169190910492915050565b6001600160801b03818116838216019080821115611ecc57611ecc611db5565b5092915050565b6001600160801b03828116828216039080821115611ecc57611ecc611db5565b80820180821115611f0657611f06611db5565b92915050565b600060208284031215611f1e57600080fd5b5051919050565b81810381811115611f0657611f06611db5565b600082611f4757611f47611e70565b500490565b8082028115828204841417611f0657611f06611db5565b600081518084526020808501945080840160005b83811015611f9c5781516001600160a01b031687529582019590820190600101611f77565b509495945050505050565b600081518084526020808501945080840160005b83811015611f9c57815161ffff1687529582019590820190600101611fbb565b6001600160801b03851681526001600160a01b038416602082015260806040820181905260009061200e90830185611f63565b8281036060840152610ef08185611fa7565b61ffff828116828216039080821115611ecc57611ecc611db5565b8481526001600160a01b038416602082015260806040820181905260009061200e90830185611f6356fe02128911bc7070fd6c100b116c2dd9a3bb6bf132d5259a65ca8d0c86ccd78f49a2646970667358221220ad23ff0540a7c461be1f7a0cbf6bd66283221db6cf4da22e1bc24d37984945f964736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.