ETH Price: $3,268.98 (-4.29%)
 

Overview

Max Total Supply

1,000,000,000 LUM

Holders

1

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
0 LUM

Value
$0.00
0x4698f06568ac4cb283d7891bf06d30ae8cd46b29
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
BeliefToken

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion, BSL 1.1 license
File 1 of 4 : BeliefToken.sol
// SPDX-License-Identifier: BUSL-1.1
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/higherrrrrrrfun/status/1861142877138755683
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/GIGANIGGAY
Website: https://giganigga.com
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/JINGK0NT0D/status/1861538765837414768
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/BGMTheBull
Telegram: https://t.me/BGMTheBull
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/wolfpackaix
Telegram: https://t.me/wolfpackaitg
Website: https://www.wolfpackai.app/landing
Created at https://beliefs.social
*/
/*
X: https://x.com/brian_armstrong/status/1861564814595600744
Website: https://x.com/brian_armstrong/status/1861564814595600744
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
Website: https://gandalf.com/
Created at https://beliefs.social
*/
/*
X: https://x.com/pepecoineth
Created at https://beliefs.social
*/
/*
Created at https://beliefs.social
*/
/*
X: https://x.com/launchtokenbot/status/1858918358080700744
Created at https://beliefs.social
*/

pragma solidity ^0.8.25;

import {ERC20} from "solady/src/tokens/ERC20.sol";
import {MerkleProofLib} from "solady/src/utils/MerkleProofLib.sol";
import {Token} from "./libraries/Token.sol";

interface ProtocolModerators {
    function isAirdropController(address) external view returns (bool);

    function isClaimableRewardsController(address) external view returns (bool);

    function isTokenExists(address token) external view returns (bool);
}

/// @title BeliefToken
/// @dev Owner of this token is the protocol itself.
/// It is used as vault for tokens for airdrops and rewards (if creator has enabled them).
contract BeliefToken is ERC20 {
    uint256 public constant MAX_SUPPLY = 1_000_000_000 * 1e18;

    string private _name;
    string private _symbol;
    address public immutable creator;
    address public immutable protocol;

    error BeliefToken_Unauthorized();
    error BeliefToken_AirdropNotEligible();
    error BeliefToken_MaxSupplyOverflow();
    error BeliefToken_AlreadyClaimed();
    error BeliefToken_AirdropWaveNotEnabled();

    event BeliefToken_ClaimReward(address indexed recipient, uint256 amount);
    event BeliefToken_EnableAirdropWave(string waveId, bytes32 merkleRoot);
    event BeliefToken_ClaimAirdropWave(string waveId, uint256 amount, bytes32[] merkleProof);

    mapping(string waveId => mapping(address holder => bool claimed)) public claimedAirdropWaveStatusOf;
    mapping(string waveId => Token.AirdropWave) public airdropWaves;

    mapping(string userId => bool claimed) public claimedRewardStatusOf;
    bytes32 public rewardsMerkleRoot;

    constructor(
        string memory name_,
        string memory symbol_,
        address creator_,
        address protocol_,
        Token.AirdropWave[] memory airdropWaves_,
        bytes32 rewardsMerkleRoot_,
        uint256 amountToDistributeClaimableRewards
    ) {
        _name = name_;

        // Ensure that the token is created by the protocol
        if (!ProtocolModerators(protocol_).isTokenExists(address(this))) {
            revert BeliefToken_Unauthorized();
        }

        protocol = protocol_;
        _symbol = symbol_;
        creator = creator_;
        {
            uint256 amountToDistributeAirdropToken;
            for (uint256 i = 0; i < airdropWaves_.length; i++) {
                airdropWaves[airdropWaves_[i].id] = airdropWaves_[i];
                amountToDistributeAirdropToken += airdropWaves_[i].amount;
            }
            rewardsMerkleRoot = rewardsMerkleRoot_;

            // mint most of the tokens to the protocol for trading and liquidity
            _mint(protocol_, MAX_SUPPLY - amountToDistributeAirdropToken - amountToDistributeClaimableRewards);

            // mint for airdrop and rewards to the token itself
            _mint(address(this), amountToDistributeClaimableRewards + amountToDistributeAirdropToken);
        }
    }

    function name() public view override returns (string memory) {
        return _name;
    }

    function symbol() public view override returns (string memory) {
        return _symbol;
    }

    function burn(uint256 amount) external {
        _burn(msg.sender, amount);
    }

    function claimReward(address recipient, uint256 amount) external {
        if (!ProtocolModerators(protocol).isClaimableRewardsController(msg.sender)) {
            revert BeliefToken_Unauthorized();
        }

        _transfer(address(this), recipient, amount);
        emit BeliefToken_ClaimReward(recipient, amount);
    }

    function enableAirdropWave(string memory waveId, bytes32 merkleRoot) external {
        if (!ProtocolModerators(protocol).isAirdropController(msg.sender)) {
            revert BeliefToken_Unauthorized();
        }
        airdropWaves[waveId].merkleRoot = merkleRoot;

        emit BeliefToken_EnableAirdropWave(waveId, merkleRoot);
    }

    function claimAirdropWave(string memory waveId, uint256 amount, bytes32[] calldata merkleProof) external {
        if (claimedAirdropWaveStatusOf[waveId][msg.sender]) {
            revert BeliefToken_AlreadyClaimed();
        }
        if (airdropWaves[waveId].merkleRoot == bytes32(0)) {
            revert BeliefToken_AirdropWaveNotEnabled();
        }

        claimedAirdropWaveStatusOf[waveId][msg.sender] = true;

        if (
            !MerkleProofLib.verifyCalldata(
                merkleProof, airdropWaves[waveId].merkleRoot, keccak256(abi.encodePacked(msg.sender, amount))
            )
        ) revert BeliefToken_AirdropNotEligible();

        _transfer(address(this), msg.sender, amount);
        emit BeliefToken_ClaimAirdropWave(waveId, amount, merkleProof);
    }

    function _beforeTokenTransfer(address from, address to, uint256) internal override {
        address _protocol = protocol;
        // automatically approve if the recipient is the protocol
        if (to == _protocol && allowance(from, _protocol) == 0) {
            _approve(from, _protocol, type(uint256).max);
        }
    }
}

File 2 of 4 : ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC20 + EIP-2612 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
///
/// @dev Note:
/// - The ERC20 standard allows minting and transferring to and from the zero address,
///   minting and transferring zero tokens, as well as self-approvals.
///   For performance, this implementation WILL NOT revert for such actions.
///   Please add any checks with overrides if desired.
/// - The `permit` function uses the ecrecover precompile (0x1).
///
/// If you are overriding:
/// - NEVER violate the ERC20 invariant:
///   the total sum of all balances must be equal to `totalSupply()`.
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC20 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The total supply has overflowed.
    error TotalSupplyOverflow();

    /// @dev The allowance has overflowed.
    error AllowanceOverflow();

    /// @dev The allowance has underflowed.
    error AllowanceUnderflow();

    /// @dev Insufficient balance.
    error InsufficientBalance();

    /// @dev Insufficient allowance.
    error InsufficientAllowance();

    /// @dev The permit is invalid.
    error InvalidPermit();

    /// @dev The permit has expired.
    error PermitExpired();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 amount);

    /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The storage slot for the total supply.
    uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;

    /// @dev The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x0c, _BALANCE_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x20)
    /// ```
    uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;

    /// @dev The allowance slot of (`owner`, `spender`) is given by:
    /// ```
    ///     mstore(0x20, spender)
    ///     mstore(0x0c, _ALLOWANCE_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let allowanceSlot := keccak256(0x0c, 0x34)
    /// ```
    uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;

    /// @dev The nonce slot of `owner` is given by:
    /// ```
    ///     mstore(0x0c, _NONCES_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let nonceSlot := keccak256(0x0c, 0x20)
    /// ```
    uint256 private constant _NONCES_SLOT_SEED = 0x38377508;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
    uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;

    /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
    bytes32 private constant _DOMAIN_TYPEHASH =
        0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;

    /// @dev `keccak256("1")`.
    bytes32 private constant _VERSION_HASH =
        0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;

    /// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
    bytes32 private constant _PERMIT_TYPEHASH =
        0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ERC20 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the name of the token.
    function name() public view virtual returns (string memory);

    /// @dev Returns the symbol of the token.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the decimals places of the token.
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           ERC20                            */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the amount of tokens in existence.
    function totalSupply() public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_TOTAL_SUPPLY_SLOT)
        }
    }

    /// @dev Returns the amount of tokens owned by `owner`.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
    function allowance(address owner, address spender)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x34))
        }
    }

    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    ///
    /// Emits a {Approval} event.
    function approve(address spender, uint256 amount) public virtual returns (bool) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the allowance slot and store the amount.
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x34), amount)
            // Emit the {Approval} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
        }
        return true;
    }

    /// @dev Transfer `amount` tokens from the caller to `to`.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    ///
    /// Emits a {Transfer} event.
    function transfer(address to, uint256 amount) public virtual returns (bool) {
        _beforeTokenTransfer(msg.sender, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, caller())
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(msg.sender, to, amount);
        return true;
    }

    /// @dev Transfers `amount` tokens from `from` to `to`.
    ///
    /// Note: Does not update the allowance if it is the maximum uint256 value.
    ///
    /// Requirements:
    /// - `from` must at least have `amount`.
    /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
        _beforeTokenTransfer(from, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let from_ := shl(96, from)
            // Compute the allowance slot and load its value.
            mstore(0x20, caller())
            mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
            let allowanceSlot := keccak256(0x0c, 0x34)
            let allowance_ := sload(allowanceSlot)
            // If the allowance is not the maximum uint256 value.
            if add(allowance_, 1) {
                // Revert if the amount to be transferred exceeds the allowance.
                if gt(amount, allowance_) {
                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated allowance.
                sstore(allowanceSlot, sub(allowance_, amount))
            }
            // Compute the balance slot and load its value.
            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(from, to, amount);
        return true;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          EIP-2612                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev For more performance, override to return the constant value
    /// of `keccak256(bytes(name()))` if `name()` will never change.
    function _constantNameHash() internal view virtual returns (bytes32 result) {}

    /// @dev Returns the current nonce for `owner`.
    /// This value is used to compute the signature for EIP-2612 permit.
    function nonces(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the nonce slot and load its value.
            mstore(0x0c, _NONCES_SLOT_SEED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
    /// authorized by a signed approval by `owner`.
    ///
    /// Emits a {Approval} event.
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        bytes32 nameHash = _constantNameHash();
        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the block timestamp is greater than `deadline`.
            if gt(timestamp(), deadline) {
                mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
                revert(0x1c, 0x04)
            }
            let m := mload(0x40) // Grab the free memory pointer.
            // Clean the upper 96 bits.
            owner := shr(96, shl(96, owner))
            spender := shr(96, shl(96, spender))
            // Compute the nonce slot and load its value.
            mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
            mstore(0x00, owner)
            let nonceSlot := keccak256(0x0c, 0x20)
            let nonceValue := sload(nonceSlot)
            // Prepare the domain separator.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), nameHash)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            mstore(0x2e, keccak256(m, 0xa0))
            // Prepare the struct hash.
            mstore(m, _PERMIT_TYPEHASH)
            mstore(add(m, 0x20), owner)
            mstore(add(m, 0x40), spender)
            mstore(add(m, 0x60), value)
            mstore(add(m, 0x80), nonceValue)
            mstore(add(m, 0xa0), deadline)
            mstore(0x4e, keccak256(m, 0xc0))
            // Prepare the ecrecover calldata.
            mstore(0x00, keccak256(0x2c, 0x42))
            mstore(0x20, and(0xff, v))
            mstore(0x40, r)
            mstore(0x60, s)
            let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
            // If the ecrecover fails, the returndatasize will be 0x00,
            // `owner` will be checked if it equals the hash at 0x00,
            // which evaluates to false (i.e. 0), and we will revert.
            // If the ecrecover succeeds, the returndatasize will be 0x20,
            // `owner` will be compared against the returned address at 0x20.
            if iszero(eq(mload(returndatasize()), owner)) {
                mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
                revert(0x1c, 0x04)
            }
            // Increment and store the updated nonce.
            sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
            // Compute the allowance slot and store the value.
            // The `owner` is already at slot 0x20.
            mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
            sstore(keccak256(0x2c, 0x34), value)
            // Emit the {Approval} event.
            log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
    function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
        bytes32 nameHash = _constantNameHash();
        //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
        if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Grab the free memory pointer.
            mstore(m, _DOMAIN_TYPEHASH)
            mstore(add(m, 0x20), nameHash)
            mstore(add(m, 0x40), _VERSION_HASH)
            mstore(add(m, 0x60), chainid())
            mstore(add(m, 0x80), address())
            result := keccak256(m, 0xa0)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Mints `amount` tokens to `to`, increasing the total supply.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 amount) internal virtual {
        _beforeTokenTransfer(address(0), to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
            let totalSupplyAfter := add(totalSupplyBefore, amount)
            // Revert if the total supply overflows.
            if lt(totalSupplyAfter, totalSupplyBefore) {
                mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
                revert(0x1c, 0x04)
            }
            // Store the updated total supply.
            sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(address(0), to, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Burns `amount` tokens from `from`, reducing the total supply.
    ///
    /// Emits a {Transfer} event.
    function _burn(address from, uint256 amount) internal virtual {
        _beforeTokenTransfer(from, address(0), amount);
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the balance slot and load its value.
            mstore(0x0c, _BALANCE_SLOT_SEED)
            mstore(0x00, from)
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Subtract and store the updated total supply.
            sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
            // Emit the {Transfer} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
        }
        _afterTokenTransfer(from, address(0), amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL TRANSFER FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Moves `amount` of tokens from `from` to `to`.
    function _transfer(address from, address to, uint256 amount) internal virtual {
        _beforeTokenTransfer(from, to, amount);
        /// @solidity memory-safe-assembly
        assembly {
            let from_ := shl(96, from)
            // Compute the balance slot and load its value.
            mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
            let fromBalanceSlot := keccak256(0x0c, 0x20)
            let fromBalance := sload(fromBalanceSlot)
            // Revert if insufficient balance.
            if gt(amount, fromBalance) {
                mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                revert(0x1c, 0x04)
            }
            // Subtract and store the updated balance.
            sstore(fromBalanceSlot, sub(fromBalance, amount))
            // Compute the balance slot of `to`.
            mstore(0x00, to)
            let toBalanceSlot := keccak256(0x0c, 0x20)
            // Add and store the updated balance of `to`.
            // Will not overflow because the sum of all user balances
            // cannot exceed the maximum uint256 value.
            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
            // Emit the {Transfer} event.
            mstore(0x20, amount)
            log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
        }
        _afterTokenTransfer(from, to, amount);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL ALLOWANCE FUNCTIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the allowance slot and load its value.
            mstore(0x20, spender)
            mstore(0x0c, _ALLOWANCE_SLOT_SEED)
            mstore(0x00, owner)
            let allowanceSlot := keccak256(0x0c, 0x34)
            let allowance_ := sload(allowanceSlot)
            // If the allowance is not the maximum uint256 value.
            if add(allowance_, 1) {
                // Revert if the amount to be transferred exceeds the allowance.
                if gt(amount, allowance_) {
                    mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated allowance.
                sstore(allowanceSlot, sub(allowance_, amount))
            }
        }
    }

    /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
    ///
    /// Emits a {Approval} event.
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let owner_ := shl(96, owner)
            // Compute the allowance slot and store the amount.
            mstore(0x20, spender)
            mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
            sstore(keccak256(0x0c, 0x34), amount)
            // Emit the {Approval} event.
            mstore(0x00, amount)
            log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HOOKS TO OVERRIDE                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Hook that is called before any transfer of tokens.
    /// This includes minting and burning.
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /// @dev Hook that is called after any transfer of tokens.
    /// This includes minting and burning.
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}

File 3 of 4 : MerkleProofLib.sol
// 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
        }
    }
}

File 4 of 4 : Token.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.25;

/// @title Token
/// @dev A library of structures to represent a token and its state
library Token {
    enum TargetDex {
        UniswapV2, // 0 value, cause it's the default value
        UniswapV4
    }

    struct MintableData {
        string id;
        uint256 amount;
    }

    struct ClaimableReward {
        string id;
        uint256 amount;
        bool minted;
    }
    /// @dev Represents the parameters for creating a token

    struct CreationParameters {
        uint256 initialVirtualReserveEth; // The initial virtual reserve of ETH
        uint256 initialVirtualReserveToken; // The initial virtual reserve of the token
        uint256 amountToAddLiquidityEth; // The amount of ETH to add as liquidity
        uint256 amountToAddLiquidityToken; // The amount of the token to add as liquidity
        uint256 realReserveToken;
        MintableData[] airdropWaves;
        uint256 ____UNUSED_SLOT;
    }

    /// @dev Represents the parameters for creating a token with a rewards merkle root
    /// and the amount to distribute as claimable rewards
    struct CreationParametersV1Upgrade {
        bytes32 rewardsMerkleRoot;
        uint256 amountToDistributeClaimableRewards;
    }

    /// @dev Represents the parameters for creating tokens with restriction on max total
    /// buy per address and antisnipe configuration
    struct CreationParametersV2Upgrade {
        bool enableSniping;
        uint256 maxAmountTotalBuyToken;
    }

    /// @dev Represents the parameters for creating tokens to be used in the UniswapV4
    struct CreationParametersV3Upgrade {
        TargetDex targetDex;
        address uniswapV4Hook;
    }

    /// @dev Represents the state of a token
    struct State {
        uint256 virtualReserveEth; // The virtual reserve of ETH
        uint256 virtualReserveToken; // The virtual reserve of the token
        uint256 realReserveEth; // The real reserve of ETH
        uint256 realReserveToken; // The real reserve of the token
        bool locked; // Whether the token is locked
        address poolAddress; // The address of the uniswap V2 pool or the address(1) contract for Uniswap V4
    }

    /// @dev Represents the parameters for token creation added via an upgrades
    struct PostUpgradeCreationParameters {
        CreationParametersV1Upgrade v1;
        CreationParametersV2Upgrade v2;
        CreationParametersV3Upgrade v3;
    }

    /// @dev Represents the data of a token
    struct Data {
        CreationParameters creationParameters; // The creation parameters of the token
        State state; // The state of the token
        PostUpgradeCreationParameters postUpgradeCreationParameters;
    }

    struct AirdropWave {
        string id;
        bytes32 merkleRoot;
        uint256 amount;
    }
}

Settings
{
  "remappings": [
    "forge-std/=node_modules/forge-std/",
    "solady/=node_modules/solady/",
    "@uniswap/v2-periphery/=node_modules/@uniswap/v2-periphery/",
    "@uniswap/v2-core/=node_modules/@uniswap/v2-core/",
    "@uniswap/lib/=node_modules/@uniswap/lib/",
    "@prb/math/=node_modules/@prb/math/",
    "@uniswap/v4-core/=lib/v4-core/",
    "@uniswap/v4-periphery/=lib/v4-periphery/",
    "@uniswap/permit2/=lib/permit2/",
    "@uniswap/universal-router/=node_modules/@uniswap/universal-router/",
    "@ensdomains/=lib/v4-core/node_modules/@ensdomains/",
    "@openzeppelin/=lib/v4-core/lib/openzeppelin-contracts/",
    "@openzeppelin/contracts/=lib/v4-core/lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/v4-core/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/v4-core/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/v4-core/lib/forge-gas-snapshot/src/",
    "hardhat/=lib/v4-core/node_modules/hardhat/",
    "openzeppelin-contracts/=lib/v4-core/lib/openzeppelin-contracts/",
    "permit2/=lib/permit2/",
    "solmate/=lib/v4-core/lib/solmate/",
    "v4-core/=lib/v4-core/src/",
    "v4-periphery/=lib/v4-periphery/"
  ],
  "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

Contract ABI

[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"creator_","type":"address"},{"internalType":"address","name":"protocol_","type":"address"},{"components":[{"internalType":"string","name":"id","type":"string"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Token.AirdropWave[]","name":"airdropWaves_","type":"tuple[]"},{"internalType":"bytes32","name":"rewardsMerkleRoot_","type":"bytes32"},{"internalType":"uint256","name":"amountToDistributeClaimableRewards","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AllowanceOverflow","type":"error"},{"inputs":[],"name":"AllowanceUnderflow","type":"error"},{"inputs":[],"name":"BeliefToken_AirdropNotEligible","type":"error"},{"inputs":[],"name":"BeliefToken_AirdropWaveNotEnabled","type":"error"},{"inputs":[],"name":"BeliefToken_AlreadyClaimed","type":"error"},{"inputs":[],"name":"BeliefToken_MaxSupplyOverflow","type":"error"},{"inputs":[],"name":"BeliefToken_Unauthorized","type":"error"},{"inputs":[],"name":"InsufficientAllowance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidPermit","type":"error"},{"inputs":[],"name":"PermitExpired","type":"error"},{"inputs":[],"name":"TotalSupplyOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"waveId","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"BeliefToken_ClaimAirdropWave","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BeliefToken_ClaimReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"waveId","type":"string"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"BeliefToken_EnableAirdropWave","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"result","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"waveId","type":"string"}],"name":"airdropWaves","outputs":[{"internalType":"string","name":"id","type":"string"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"waveId","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"name":"claimAirdropWave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"waveId","type":"string"},{"internalType":"address","name":"holder","type":"address"}],"name":"claimedAirdropWaveStatusOf","outputs":[{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"userId","type":"string"}],"name":"claimedRewardStatusOf","outputs":[{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"waveId","type":"string"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"enableAirdropWave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocol","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60c080604052346105a757611c07803803809161001c8285610725565b833981019060e0818303126105a75780516001600160401b0381116105a75782610047918301610748565b60208201516001600160401b0381116105a75783610066918401610748565b6100726040840161079d565b61007e6060850161079d565b60808501519092906001600160401b0381116105a75785019580601f880112156105a7578651966001600160401b0388116103af578760051b91604051986100c9602085018b610725565b89526020808a0193830101918183116105a75760208101935b8385106106a357505050505060c060a08601519501519380519060018060401b0382116103af575f5490600182811c92168015610699575b60208310146103915781601f84931161062c575b50602090601f83116001146105c9575f926105be575b50508160011b915f199060031b1c1916175f555b604051634f6a7d2d60e11b81523060048201526020816024816001600160a01b0388165afa9081156105b3575f91610574575b50156105655760a08390528051906001600160401b0382116103af5760015490600182811c9216801561055b575b60208310146103915781601f8493116104ed575b50602090601f8311600114610487575f9261047c575b50508160011b915f199060031b1c1916176001555b6080525f91825b85518410156103c35761021284876107b1565b51602080610220878a6107b1565b5151604051928184925191829101835e8101600381520301902090805180519060018060401b0382116103af578354600181811c911680156103a5575b602082101461039157601f811161034c575b50602090601f83116001146102de5760019593836102cb96946002946040945f926102d3575b50505f19600383901b1c191690881b1784555b602081015187850155015191015560406102c2878a6107b1565b510151906107d9565b9301926101ff565b015190505f80610295565b90601f19831691855f52815f20925f5b81811061033457508460029460409460019a98946102cb9a988c951061031c575b505050811b0184556102a8565b01515f1960f88460031b161c191690555f808061030f565b929360206001819287860151815501950193016102ee565b845f5260205f20601f840160051c81019160208510610387575b601f0160051c01905b81811061037c575061026f565b5f815560010161036f565b9091508190610366565b634e487b7160e01b5f52602260045260245ffd5b90607f169061025d565b634e487b7160e01b5f52604160045260245ffd5b84600555806b033b2e3c9fd0803ce800000003916b033b2e3c9fd0803ce80000008311610468578082016b033b2e3c9fd0803ce800000003928311610468576104126104179361041d956107e6565b6107d9565b306107e6565b60405161132990816108de823960805181610ebd015260a051818181610323015281816105b2015281816107da01528181610bc901528181610d6c01528181610f3e01526111c00152f35b634e487b7160e01b5f52601160045260245ffd5b015190505f806101e3565b60015f9081528281209350601f198516905b8181106104d557509084600195949392106104bd575b505050811b016001556101f8565b01515f1960f88460031b161c191690555f80806104af565b92936020600181928786015181550195019301610499565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610551575b90601f859493920160051c01905b81811061054357506101cd565b5f8155849350600101610536565b9091508190610528565b91607f16916101b9565b631f9831d360e11b5f5260045ffd5b90506020813d6020116105ab575b8161058f60209383610725565b810103126105a7575180151581036105a7575f61018b565b5f80fd5b3d9150610582565b6040513d5f823e3d90fd5b015190505f80610144565b5f8080528281209350601f198516905b81811061061457509084600195949392106105fc575b505050811b015f55610158565b01515f1960f88460031b161c191690555f80806105ef565b929360206001819287860151815501950193016105d9565b5f80529091507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563601f840160051c8101916020851061068f575b90601f859493920160051c01905b818110610681575061012e565b5f8155849350600101610674565b9091508190610666565b91607f169161011a565b84516001600160401b0381116105a75782016060818503601f1901126105a75760405191606083016001600160401b038111848210176103af576040526020820151926001600160401b0384116105a757606083610708886020809881980101610748565b8352604081015185840152015160408201528152019401936100e2565b601f909101601f19168101906001600160401b038211908210176103af57604052565b81601f820112156105a7578051906001600160401b0382116103af576040519261077c601f8401601f191660200185610725565b828452602083830101116105a757815f9260208093018386015e8301015290565b51906001600160a01b03821682036105a757565b80518210156107c55760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b9190820180921161046857565b60a0516001600160a01b039081169082168114806108c1575b610878575b506805345cdf77eb68f44c5482810190811061086b576805345cdf77eb68f44c556387a211a2600c525f526020600c20818154019055602052600c5160601c5f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3565b63e5cfe9575f526004601cfd5b602052637f5e9f20600c525f196034600c20555f195f52602c5160601c5f7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602082a35f610804565b5080602052637f5e9f20600c525f80526034600c2054156107ff56fe60806040526004361015610011575f80fd5b5f3560e01c8063028e248514610eec57806302d05d3f14610ea857806306fdde0314610e8d578063095ea7b314610e35578063174e31c414610d3157806318160ddd14610d0c57806323b872dd14610ba2578063313ce56714610b8757806332cb6b0c14610b615780633644e51514610ad95780633b785468146108bc57806342966c68146107c457806370a08231146107925780637ecebe001461076057806384920bbd146107055780638c674c03146105e15780638ce744261461059d57806390d2f54e1461052657806395d89b411461041a578063a9059cbb14610304578063b5890a13146102e7578063d505accf1461015e5763dd62ed3e14610116575f80fd5b3461015a57604036600319011261015a5760206101526101346110ad565b61013c6110c3565b602052637f5e9f20600c525f526034600c205490565b604051908152f35b5f80fd5b3461015a5760e036600319011261015a576101776110ad565b61017f6110c3565b6084359160643560443560ff8516850361015a5761019b6110d9565b60208151910120908242116102da576040519360018060a01b03169460018060a01b03169565383775081901600e52855f5260c06020600c20958654957f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252602082019586528660408301967fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc688528b6060850198468a528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528688525260a082015220604e526042602c205f5260ff1660205260a43560405260c43560605260208060805f60015afa93853d51036102cd575f805160206112d483398151915294602094019055856303faf4f960a51b176040526034602c2055a3005b63ddafbaef5f526004601cfd5b631a15a3cc5f526004601cfd5b3461015a575f36600319011261015a576020600554604051908152f35b3461015a57604036600319011261015a5761031d6110ad565b602435907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0380831690821614806103f7575b6103bc575b506387a211a2600c52335f526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c335f805160206112b4833981519152602080a3602060405160018152f35b63f4d678b85f526004601cfd5b602052637f5e9f203360601b17600c525f196034600c20555f195f52602c5160601c335f805160206112d483398151915260205fa38261035c565b50610414813390602052637f5e9f20600c525f526034600c205490565b15610357565b3461015a575f36600319011261015a576040515f6001548060011c9060018116801561051c575b602083108114610508578285529081156104e45750600114610486575b6104828361046e81850382610ffd565b604051918291602083526020830190611089565b0390f35b60015f9081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b8082106104ca5750909150810160200161046e61045e565b9192600181602092548385880101520191019092916104b2565b60ff191660208086019190915291151560051b8401909101915061046e905061045e565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610441565b3461015a57604036600319011261015a5760043567ffffffffffffffff811161015a57610557903690600401611033565b6020806105626110c3565b92604051928184925191829101835e810160028152030190209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461015a575f36600319011261015a576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461015a57602036600319011261015a5760043567ffffffffffffffff811161015a57602061061581923690600401611033565b604051928184925191829101835e810160038152030190206040515f9180548060011c906001811680156106fb575b602083108114610508578285529081156106d7575060011461069e575b506106718261068f940383610ffd565b60026001820154910154604051938493606085526060850190611089565b91602084015260408301520390f35b9250805f5260205f205f905b8482106106c1575082016020019250610671610661565b60018160209254838588010152019101906106aa565b60ff191660208086019190915291151560051b840190910193506106719050610661565b91607f1691610644565b3461015a57602036600319011261015a5760043567ffffffffffffffff811161015a5760ff60208061073c81943690600401611033565b604051928184925191829101835e8101600481520301902054166040519015158152f35b3461015a57602036600319011261015a576107796110ad565b6338377508600c525f52602080600c2054604051908152f35b3461015a57602036600319011261015a576107ab6110ad565b6387a211a2600c525f52602080600c2054604051908152f35b3461015a57602036600319011261015a576004357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381161580610899575b61085e575b506387a211a2600c52335f526020600c2080548083116103af578290039055806805345cdf77eb68f44c54036805345cdf77eb68f44c555f525f335f805160206112b4833981519152602083a3005b602052637f5e9f203360601b17600c525f196034600c20555f195f52602c5160601c335f805160206112d483398151915260205fa38161080f565b506108b6813390602052637f5e9f20600c525f526034600c205490565b1561080a565b3461015a57606036600319011261015a5760043567ffffffffffffffff811161015a576108ed903690600401611033565b6044359060243567ffffffffffffffff831161015a573660238401121561015a57826004013567ffffffffffffffff811161015a57602484019060248160051b8096010136811161015a57604051855190602081818901938085835e8101600281520301902060018060a01b0333165f5260205260ff60405f205416610aca57600160405160208189518086835e81016003815203019020015415610abb57600183916040516020818a518085835e81016002815203019020828060a01b0333165f5260205260405f208260ff19825416179055602060405180928a518091835e8101600381520301902001549160405160208101903360601b8252876034820152603481526109fe605482610ffd565b51902091610a8f575b5003610a8057610a188333306111bc565b610a2d60405194606086526060860190611089565b602085019390935283830360408501528083526001600160fb1b031061015a5783827f26065fb4d131171e2476eb17b938a9e211cf521be70d22c52c83244ce1c54d8a95859360208096013701030190a1005b635b64090160e11b5f5260045ffd5b84915b602083359182811160051b9081521852602060405f20920191818310610a925791505087610a07565b63fb5f54ef60e01b5f5260045ffd5b6306dfe52560e31b5f5260045ffd5b3461015a575f36600319011261015a57602060a0610af56110d9565b828151910120604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b3461015a575f36600319011261015a5760206040516b033b2e3c9fd0803ce80000008152f35b3461015a575f36600319011261015a57602060405160128152f35b3461015a57606036600319011261015a57610bbb6110ad565b610bc36110c3565b604435907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038083169082161480610ce9575b610ca6575b508260601b33602052637f5e9f208117600c526034600c209081549160018301610c82575b506387a211a2915017600c526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f805160206112b4833981519152602080a3602060405160018152f35b828511610c9957846387a211a29303905585610c27565b6313be252b5f526004601cfd5b602052637f5e9f208360601b17600c525f196034600c20555f195f52602c5160601c60018060a01b0384165f805160206112d483398151915260205fa383610c02565b50610d06818590602052637f5e9f20600c525f526034600c205490565b15610bfd565b3461015a575f36600319011261015a5760206805345cdf77eb68f44c54604051908152f35b3461015a57604036600319011261015a57610d4a6110ad565b6040516302abd8c960e11b8152336004820152602480359291906020908290817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610e2a575f91610dfb575b5015610dec57602081610dd9847fa7e0801466cad990c2143c2c40a4924862c5503ee26b103582962c5e61e69a1494306111bc565b6040519384526001600160a01b031692a2005b631f9831d360e11b5f5260045ffd5b610e1d915060203d602011610e23575b610e158183610ffd565b8101906111a4565b83610da4565b503d610e0b565b6040513d5f823e3d90fd5b3461015a57604036600319011261015a57610e4e6110ad565b60243590602052637f5e9f20600c52335f52806034600c20555f52602c5160601c335f805160206112d483398151915260205fa3602060405160018152f35b3461015a575f36600319011261015a5761048261046e6110d9565b3461015a575f36600319011261015a576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461015a57604036600319011261015a5760043567ffffffffffffffff811161015a57610f1d903690600401611033565b604051630bda7b5560e21b81523360048201526024803591906020908290817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610e2a575f91610fde575b5015610dec577f08f9536f4dbd4a3a46a8531d13a42875526412cad47ce602b0b77d30667b861f9181610fd3926001604051602081865180838901835e810160038152030190200155604051928392604084526040840190611089565b9060208301520390a1005b610ff7915060203d602011610e2357610e158183610ffd565b83610f76565b90601f8019910116810190811067ffffffffffffffff82111761101f57604052565b634e487b7160e01b5f52604160045260245ffd5b81601f8201121561015a5780359067ffffffffffffffff821161101f5760405192611068601f8401601f191660200185610ffd565b8284526020838301011161015a57815f926020809301838601378301015290565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361015a57565b602435906001600160a01b038216820361015a57565b604051905f80548060011c916001821691821561119a575b60208410831461050857838652859290811561117b575060011461111e575b61111c92500383610ffd565b565b505f80805290917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b81831061115f57505090602061111c92820101611110565b6020919350806001915483858901015201910190918492611147565b6020925061111c94915060ff191682840152151560051b820101611110565b92607f16926110f1565b9081602091031261015a5751801515810361015a5790565b91907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b038083169082161480611290575b61124d575b506387a211a28360601b17600c526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f805160206112b4833981519152602080a3565b602052637f5e9f208360601b17600c525f196034600c20555f195f52602c5160601c60018060a01b0384165f805160206112d483398151915260205fa35f6111f9565b506112ad818590602052637f5e9f20600c525f526034600c205490565b156111f456feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a26469706673582212208858e58f6a733aa3c3a3beb1b0993fb86a2f49fe889ceb8cad258447c1345a1e64736f6c634300081a003300000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000fdb2b393e15252ddf665a664216bf0006d6869e80000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086c756d696e6f757300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034c554d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361015610011575f80fd5b5f3560e01c8063028e248514610eec57806302d05d3f14610ea857806306fdde0314610e8d578063095ea7b314610e35578063174e31c414610d3157806318160ddd14610d0c57806323b872dd14610ba2578063313ce56714610b8757806332cb6b0c14610b615780633644e51514610ad95780633b785468146108bc57806342966c68146107c457806370a08231146107925780637ecebe001461076057806384920bbd146107055780638c674c03146105e15780638ce744261461059d57806390d2f54e1461052657806395d89b411461041a578063a9059cbb14610304578063b5890a13146102e7578063d505accf1461015e5763dd62ed3e14610116575f80fd5b3461015a57604036600319011261015a5760206101526101346110ad565b61013c6110c3565b602052637f5e9f20600c525f526034600c205490565b604051908152f35b5f80fd5b3461015a5760e036600319011261015a576101776110ad565b61017f6110c3565b6084359160643560443560ff8516850361015a5761019b6110d9565b60208151910120908242116102da576040519360018060a01b03169460018060a01b03169565383775081901600e52855f5260c06020600c20958654957f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252602082019586528660408301967fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc688528b6060850198468a528c608087019330855260a08820602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9885252528688525260a082015220604e526042602c205f5260ff1660205260a43560405260c43560605260208060805f60015afa93853d51036102cd575f805160206112d483398151915294602094019055856303faf4f960a51b176040526034602c2055a3005b63ddafbaef5f526004601cfd5b631a15a3cc5f526004601cfd5b3461015a575f36600319011261015a576020600554604051908152f35b3461015a57604036600319011261015a5761031d6110ad565b602435907f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b0380831690821614806103f7575b6103bc575b506387a211a2600c52335f526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c335f805160206112b4833981519152602080a3602060405160018152f35b63f4d678b85f526004601cfd5b602052637f5e9f203360601b17600c525f196034600c20555f195f52602c5160601c335f805160206112d483398151915260205fa38261035c565b50610414813390602052637f5e9f20600c525f526034600c205490565b15610357565b3461015a575f36600319011261015a576040515f6001548060011c9060018116801561051c575b602083108114610508578285529081156104e45750600114610486575b6104828361046e81850382610ffd565b604051918291602083526020830190611089565b0390f35b60015f9081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6939250905b8082106104ca5750909150810160200161046e61045e565b9192600181602092548385880101520191019092916104b2565b60ff191660208086019190915291151560051b8401909101915061046e905061045e565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610441565b3461015a57604036600319011261015a5760043567ffffffffffffffff811161015a57610557903690600401611033565b6020806105626110c3565b92604051928184925191829101835e810160028152030190209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461015a575f36600319011261015a576040517f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b03168152602090f35b3461015a57602036600319011261015a5760043567ffffffffffffffff811161015a57602061061581923690600401611033565b604051928184925191829101835e810160038152030190206040515f9180548060011c906001811680156106fb575b602083108114610508578285529081156106d7575060011461069e575b506106718261068f940383610ffd565b60026001820154910154604051938493606085526060850190611089565b91602084015260408301520390f35b9250805f5260205f205f905b8482106106c1575082016020019250610671610661565b60018160209254838588010152019101906106aa565b60ff191660208086019190915291151560051b840190910193506106719050610661565b91607f1691610644565b3461015a57602036600319011261015a5760043567ffffffffffffffff811161015a5760ff60208061073c81943690600401611033565b604051928184925191829101835e8101600481520301902054166040519015158152f35b3461015a57602036600319011261015a576107796110ad565b6338377508600c525f52602080600c2054604051908152f35b3461015a57602036600319011261015a576107ab6110ad565b6387a211a2600c525f52602080600c2054604051908152f35b3461015a57602036600319011261015a576004357f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b0381161580610899575b61085e575b506387a211a2600c52335f526020600c2080548083116103af578290039055806805345cdf77eb68f44c54036805345cdf77eb68f44c555f525f335f805160206112b4833981519152602083a3005b602052637f5e9f203360601b17600c525f196034600c20555f195f52602c5160601c335f805160206112d483398151915260205fa38161080f565b506108b6813390602052637f5e9f20600c525f526034600c205490565b1561080a565b3461015a57606036600319011261015a5760043567ffffffffffffffff811161015a576108ed903690600401611033565b6044359060243567ffffffffffffffff831161015a573660238401121561015a57826004013567ffffffffffffffff811161015a57602484019060248160051b8096010136811161015a57604051855190602081818901938085835e8101600281520301902060018060a01b0333165f5260205260ff60405f205416610aca57600160405160208189518086835e81016003815203019020015415610abb57600183916040516020818a518085835e81016002815203019020828060a01b0333165f5260205260405f208260ff19825416179055602060405180928a518091835e8101600381520301902001549160405160208101903360601b8252876034820152603481526109fe605482610ffd565b51902091610a8f575b5003610a8057610a188333306111bc565b610a2d60405194606086526060860190611089565b602085019390935283830360408501528083526001600160fb1b031061015a5783827f26065fb4d131171e2476eb17b938a9e211cf521be70d22c52c83244ce1c54d8a95859360208096013701030190a1005b635b64090160e11b5f5260045ffd5b84915b602083359182811160051b9081521852602060405f20920191818310610a925791505087610a07565b63fb5f54ef60e01b5f5260045ffd5b6306dfe52560e31b5f5260045ffd5b3461015a575f36600319011261015a57602060a0610af56110d9565b828151910120604051907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8252838201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6604082015246606082015230608082015220604051908152f35b3461015a575f36600319011261015a5760206040516b033b2e3c9fd0803ce80000008152f35b3461015a575f36600319011261015a57602060405160128152f35b3461015a57606036600319011261015a57610bbb6110ad565b610bc36110c3565b604435907f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b038083169082161480610ce9575b610ca6575b508260601b33602052637f5e9f208117600c526034600c209081549160018301610c82575b506387a211a2915017600c526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f805160206112b4833981519152602080a3602060405160018152f35b828511610c9957846387a211a29303905585610c27565b6313be252b5f526004601cfd5b602052637f5e9f208360601b17600c525f196034600c20555f195f52602c5160601c60018060a01b0384165f805160206112d483398151915260205fa383610c02565b50610d06818590602052637f5e9f20600c525f526034600c205490565b15610bfd565b3461015a575f36600319011261015a5760206805345cdf77eb68f44c54604051908152f35b3461015a57604036600319011261015a57610d4a6110ad565b6040516302abd8c960e11b8152336004820152602480359291906020908290817f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b03165afa908115610e2a575f91610dfb575b5015610dec57602081610dd9847fa7e0801466cad990c2143c2c40a4924862c5503ee26b103582962c5e61e69a1494306111bc565b6040519384526001600160a01b031692a2005b631f9831d360e11b5f5260045ffd5b610e1d915060203d602011610e23575b610e158183610ffd565b8101906111a4565b83610da4565b503d610e0b565b6040513d5f823e3d90fd5b3461015a57604036600319011261015a57610e4e6110ad565b60243590602052637f5e9f20600c52335f52806034600c20555f52602c5160601c335f805160206112d483398151915260205fa3602060405160018152f35b3461015a575f36600319011261015a5761048261046e6110d9565b3461015a575f36600319011261015a576040517f000000000000000000000000fdb2b393e15252ddf665a664216bf0006d6869e86001600160a01b03168152602090f35b3461015a57604036600319011261015a5760043567ffffffffffffffff811161015a57610f1d903690600401611033565b604051630bda7b5560e21b81523360048201526024803591906020908290817f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b03165afa908115610e2a575f91610fde575b5015610dec577f08f9536f4dbd4a3a46a8531d13a42875526412cad47ce602b0b77d30667b861f9181610fd3926001604051602081865180838901835e810160038152030190200155604051928392604084526040840190611089565b9060208301520390a1005b610ff7915060203d602011610e2357610e158183610ffd565b83610f76565b90601f8019910116810190811067ffffffffffffffff82111761101f57604052565b634e487b7160e01b5f52604160045260245ffd5b81601f8201121561015a5780359067ffffffffffffffff821161101f5760405192611068601f8401601f191660200185610ffd565b8284526020838301011161015a57815f926020809301838601378301015290565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361015a57565b602435906001600160a01b038216820361015a57565b604051905f80548060011c916001821691821561119a575b60208410831461050857838652859290811561117b575060011461111e575b61111c92500383610ffd565b565b505f80805290917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b81831061115f57505090602061111c92820101611110565b6020919350806001915483858901015201910190918492611147565b6020925061111c94915060ff191682840152151560051b820101611110565b92607f16926110f1565b9081602091031261015a5751801515810361015a5790565b91907f0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f46001600160a01b038083169082161480611290575b61124d575b506387a211a28360601b17600c526020600c2080548084116103af5783900390555f526020600c20818154019055602052600c5160601c9060018060a01b03165f805160206112b4833981519152602080a3565b602052637f5e9f208360601b17600c525f196034600c20555f195f52602c5160601c60018060a01b0384165f805160206112d483398151915260205fa35f6111f9565b506112ad818590602052637f5e9f20600c525f526034600c205490565b156111f456feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a26469706673582212208858e58f6a733aa3c3a3beb1b0993fb86a2f49fe889ceb8cad258447c1345a1e64736f6c634300081a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000fdb2b393e15252ddf665a664216bf0006d6869e80000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f400000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086c756d696e6f757300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034c554d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name_ (string): luminous
Arg [1] : symbol_ (string): LUM
Arg [2] : creator_ (address): 0xFdb2B393e15252dDF665a664216bf0006D6869E8
Arg [3] : protocol_ (address): 0x7a306c63a1Ccc180CBf60FA2A92FBB31E16904F4

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 000000000000000000000000fdb2b393e15252ddf665a664216bf0006d6869e8
Arg [3] : 0000000000000000000000007a306c63a1ccc180cbf60fa2a92fbb31e16904f4
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [8] : 6c756d696e6f7573000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [10] : 4c554d0000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000


[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.