ETH Price: $3,017.75 (-3.07%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
348046392025-08-28 16:30:2581 days ago1756398625
Juicebox: Tokens V4
 Contract Creation0 ETH
346206602025-08-24 10:17:4785 days ago1756030667
Juicebox: Tokens V4
 Contract Creation0 ETH
342677972025-08-16 6:15:4193 days ago1755324941
Juicebox: Tokens V4
 Contract Creation0 ETH
341526222025-08-13 14:16:3196 days ago1755094591
Juicebox: Tokens V4
 Contract Creation0 ETH
339945142025-08-09 22:26:15100 days ago1754778375
Juicebox: Tokens V4
 Contract Creation0 ETH
339923372025-08-09 21:13:41100 days ago1754774021
Juicebox: Tokens V4
 Contract Creation0 ETH
339534402025-08-08 23:37:07101 days ago1754696227
Juicebox: Tokens V4
 Contract Creation0 ETH
338192302025-08-05 21:03:27104 days ago1754427807
Juicebox: Tokens V4
 Contract Creation0 ETH
338185002025-08-05 20:39:07104 days ago1754426347
Juicebox: Tokens V4
 Contract Creation0 ETH
338144262025-08-05 18:23:19104 days ago1754418199
Juicebox: Tokens V4
 Contract Creation0 ETH
335536572025-07-30 17:31:01110 days ago1753896661
Juicebox: Tokens V4
 Contract Creation0 ETH
335509042025-07-30 15:59:15110 days ago1753891155
Juicebox: Tokens V4
 Contract Creation0 ETH
335220202025-07-29 23:56:27111 days ago1753833387
Juicebox: Tokens V4
 Contract Creation0 ETH
335213422025-07-29 23:33:51111 days ago1753832031
Juicebox: Tokens V4
 Contract Creation0 ETH
333489322025-07-25 23:46:51115 days ago1753487211
Juicebox: Tokens V4
 Contract Creation0 ETH
333408512025-07-25 19:17:29115 days ago1753471049
Juicebox: Tokens V4
 Contract Creation0 ETH
333007602025-07-24 21:01:07116 days ago1753390867
Juicebox: Tokens V4
 Contract Creation0 ETH
333006022025-07-24 20:55:51116 days ago1753390551
Juicebox: Tokens V4
 Contract Creation0 ETH
332964142025-07-24 18:36:15116 days ago1753382175
Juicebox: Tokens V4
 Contract Creation0 ETH
332580382025-07-23 21:17:03117 days ago1753305423
Juicebox: Tokens V4
 Contract Creation0 ETH
332483672025-07-23 15:54:41117 days ago1753286081
Juicebox: Tokens V4
 Contract Creation0 ETH
329158702025-07-15 23:11:27125 days ago1752621087
Juicebox: Tokens V4
 Contract Creation0 ETH
328718082025-07-14 22:42:43126 days ago1752532963
Juicebox: Tokens V4
 Contract Creation0 ETH
326740872025-07-10 8:52:01130 days ago1752137521
Juicebox: Tokens V4
 Contract Creation0 ETH
326600162025-07-10 1:02:59131 days ago1752109379
Juicebox: Tokens V4
 Contract Creation0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
JBTokens

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";

import {JBControlled} from "./abstract/JBControlled.sol";
import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
import {IJBToken} from "./interfaces/IJBToken.sol";
import {IJBTokens} from "./interfaces/IJBTokens.sol";

/// @notice Manages minting, burning, and balances of projects' tokens and token credits.
/// @dev Token balances can either be ERC-20s or token credits. This contract manages these two representations and
/// allows credit -> ERC-20 claiming.
/// @dev The total supply of a project's tokens and the balance of each account are calculated in this contract.
/// @dev An ERC-20 contract must be set by a project's owner for ERC-20 claiming to become available. Projects can bring
/// their own IJBToken if they prefer.
contract JBTokens is JBControlled, IJBTokens {
    //*********************************************************************//
    // --------------------------- custom errors ------------------------- //
    //*********************************************************************//

    error JBTokens_EmptyName();
    error JBTokens_EmptySymbol();
    error JBTokens_EmptyToken();
    error JBTokens_InsufficientCredits(uint256 count, uint256 creditBalance);
    error JBTokens_InsufficientTokensToBurn(uint256 count, uint256 tokenBalance);
    error JBTokens_OverflowAlert(uint256 value, uint256 limit);
    error JBTokens_ProjectAlreadyHasToken(IJBToken token);
    error JBTokens_TokenAlreadyBeingUsed(uint256 projectId);
    error JBTokens_TokenCantBeAdded(uint256 projectId);
    error JBTokens_TokenNotFound();
    error JBTokens_TokensMustHave18Decimals(uint256 decimals);

    //*********************************************************************//
    // --------------- public immutable stored properties ---------------- //
    //*********************************************************************//

    /// @notice A reference to the token implementation that'll be cloned as projects deploy their own tokens.
    IJBToken public immutable TOKEN;

    //*********************************************************************//
    // --------------------- public stored properties -------------------- //
    //*********************************************************************//

    /// @notice Each holder's credit balance for each project.
    /// @custom:param holder The credit holder.
    /// @custom:param projectId The ID of the project to which the credits belong.
    mapping(address holder => mapping(uint256 projectId => uint256)) public override creditBalanceOf;

    /// @notice Each token's project.
    /// @custom:param token The address of the token associated with the project.
    // slither-disable-next-line unused-return
    mapping(IJBToken token => uint256) public override projectIdOf;

    /// @notice Each project's attached token contract.
    /// @custom:param projectId The ID of the project the token belongs to.
    mapping(uint256 projectId => IJBToken) public override tokenOf;

    /// @notice The total supply of credits for each project.
    /// @custom:param projectId The ID of the project to which the credits belong.
    mapping(uint256 projectId => uint256) public override totalCreditSupplyOf;

    //*********************************************************************//
    // -------------------------- constructor ---------------------------- //
    //*********************************************************************//

    /// @param directory A contract storing directories of terminals and controllers for each project.
    /// @param token The implementation of the token contract that project can deploy.
    constructor(IJBDirectory directory, IJBToken token) JBControlled(directory) {
        TOKEN = token;
    }

    //*********************************************************************//
    // ------------------------- external views -------------------------- //
    //*********************************************************************//

    /// @notice The total balance a holder has for a specified project, including both tokens and token credits.
    /// @param holder The holder to get a balance for.
    /// @param projectId The project to get the `_holder`s balance for.
    /// @return balance The combined token and token credit balance of the `_holder
    function totalBalanceOf(address holder, uint256 projectId) external view override returns (uint256 balance) {
        // Get a reference to the holder's credits for the project.
        balance = creditBalanceOf[holder][projectId];

        // Get a reference to the project's current token.
        IJBToken token = tokenOf[projectId];

        // If the project has a current token, add the holder's balance to the total.
        if (token != IJBToken(address(0))) {
            balance += token.balanceOf(holder);
        }
    }

    //*********************************************************************//
    // --------------------------- public views -------------------------- //
    //*********************************************************************//

    /// @notice The total supply for a specific project, including both tokens and token credits.
    /// @param projectId The ID of the project to get the total supply of.
    /// @return totalSupply The total supply of the project's tokens and token credits.
    function totalSupplyOf(uint256 projectId) public view override returns (uint256 totalSupply) {
        // Get a reference to the total supply of the project's credits
        totalSupply = totalCreditSupplyOf[projectId];

        // Get a reference to the project's current token.
        IJBToken token = tokenOf[projectId];

        // If the project has a current token, add its total supply to the total.
        if (token != IJBToken(address(0))) {
            totalSupply += token.totalSupply();
        }
    }

    //*********************************************************************//
    // ---------------------- external transactions ---------------------- //
    //*********************************************************************//

    /// @notice Burns (destroys) credits or tokens.
    /// @dev Credits are burned first, then tokens are burned.
    /// @dev Only a project's current controller can burn its tokens.
    /// @param holder The address that owns the tokens which are being burned.
    /// @param projectId The ID of the project to the burned tokens belong to.
    /// @param count The number of tokens to burn.
    function burnFrom(address holder, uint256 projectId, uint256 count) external override onlyControllerOf(projectId) {
        // Get a reference to the project's current token.
        IJBToken token = tokenOf[projectId];

        // Get a reference to the amount of credits the holder has.
        uint256 creditBalance = creditBalanceOf[holder][projectId];

        // Get a reference to the amount of the project's current token the holder has in their wallet.
        uint256 tokenBalance = token == IJBToken(address(0)) ? 0 : token.balanceOf(holder);

        // There must be enough tokens to burn across the holder's combined token and credit balance.
        if (count > tokenBalance + creditBalance) {
            revert JBTokens_InsufficientTokensToBurn(count, tokenBalance + creditBalance);
        }

        // The amount of tokens to burn.
        uint256 tokensToBurn;

        // Get a reference to how many tokens should be burned
        if (tokenBalance != 0) {
            // Burn credits before tokens.
            unchecked {
                tokensToBurn = creditBalance < count ? count - creditBalance : 0;
            }
        }

        // The amount of credits to burn.
        uint256 creditsToBurn;
        unchecked {
            creditsToBurn = count - tokensToBurn;
        }

        // Subtract the burned credits from the credit balance and credit supply.
        if (creditsToBurn > 0) {
            creditBalanceOf[holder][projectId] = creditBalanceOf[holder][projectId] - creditsToBurn;
            totalCreditSupplyOf[projectId] = totalCreditSupplyOf[projectId] - creditsToBurn;
        }

        emit Burn({
            holder: holder,
            projectId: projectId,
            count: count,
            creditBalance: creditBalance,
            tokenBalance: tokenBalance,
            caller: msg.sender
        });

        // Burn the tokens.
        if (tokensToBurn > 0) token.burn(holder, tokensToBurn);
    }

    /// @notice Redeem credits to claim tokens into a holder's wallet.
    /// @dev Only a project's controller can claim that project's tokens.
    /// @param holder The owner of the credits being redeemed.
    /// @param projectId The ID of the project whose tokens are being claimed.
    /// @param count The number of tokens to claim.
    /// @param beneficiary The account into which the claimed tokens will go.
    function claimTokensFor(
        address holder,
        uint256 projectId,
        uint256 count,
        address beneficiary
    )
        external
        override
        onlyControllerOf(projectId)
    {
        // Get a reference to the project's current token.
        IJBToken token = tokenOf[projectId];

        // The project must have a token contract attached.
        if (token == IJBToken(address(0))) revert JBTokens_TokenNotFound();

        // Get a reference to the amount of credits the holder has.
        uint256 creditBalance = creditBalanceOf[holder][projectId];

        // There must be enough credits to claim.
        if (count > creditBalance) revert JBTokens_InsufficientCredits(count, creditBalance);

        unchecked {
            // Subtract the claim amount from the holder's credit balance.
            creditBalanceOf[holder][projectId] = creditBalance - count;

            // Subtract the claim amount from the project's total credit supply.
            totalCreditSupplyOf[projectId] -= count;
        }

        emit ClaimTokens({
            holder: holder,
            projectId: projectId,
            creditBalance: creditBalance,
            count: count,
            beneficiary: beneficiary,
            caller: msg.sender
        });

        // Mint the equivalent amount of the project's token for the holder.
        token.mint(beneficiary, count);
    }

    /// @notice Deploys an ERC-20 token for a project. It will be used when claiming tokens.
    /// @dev Deploys a project's ERC-20 token contract.
    /// @dev Only a project's controller can deploy its token.
    /// @param projectId The ID of the project to deploy an ERC-20 token for.
    /// @param name The ERC-20's name.
    /// @param symbol The ERC-20's symbol.
    /// @param salt The salt used for ERC-1167 clone deployment. Pass a non-zero salt for deterministic deployment based
    /// on `msg.sender` and the `TOKEN` implementation address.
    /// @return token The address of the token that was deployed.
    function deployERC20For(
        uint256 projectId,
        string calldata name,
        string calldata symbol,
        bytes32 salt
    )
        external
        override
        onlyControllerOf(projectId)
        returns (IJBToken token)
    {
        // There must be a name.
        if (bytes(name).length == 0) revert JBTokens_EmptyName();

        // There must be a symbol.
        if (bytes(symbol).length == 0) revert JBTokens_EmptySymbol();

        // The project shouldn't already have a token.
        if (tokenOf[projectId] != IJBToken(address(0))) revert JBTokens_ProjectAlreadyHasToken(tokenOf[projectId]);

        token = salt == bytes32(0)
            ? IJBToken(Clones.clone(address(TOKEN)))
            : IJBToken(Clones.cloneDeterministic(address(TOKEN), keccak256(abi.encode(msg.sender, salt))));

        // Store the token contract.
        tokenOf[projectId] = token;

        // Store the project for the token.
        projectIdOf[token] = projectId;

        emit DeployERC20({
            projectId: projectId,
            token: token,
            name: name,
            symbol: symbol,
            salt: salt,
            caller: msg.sender
        });

        // Initialize the token.
        token.initialize({name: name, symbol: symbol, owner: address(this)});
    }

    /// @notice Mint (create) new tokens or credits.
    /// @dev Only a project's current controller can mint its tokens.
    /// @param holder The address receiving the new tokens.
    /// @param projectId The ID of the project to which the tokens belong.
    /// @param count The number of tokens to mint.
    /// @return token The address of the token that was minted, if the project has a token.
    function mintFor(
        address holder,
        uint256 projectId,
        uint256 count
    )
        external
        override
        onlyControllerOf(projectId)
        returns (IJBToken token)
    {
        // Get a reference to the project's current token.
        token = tokenOf[projectId];

        // Save a reference to whether there a token exists.
        bool tokensWereClaimed = token != IJBToken(address(0));

        if (tokensWereClaimed) {
            // If tokens should be claimed, mint tokens into the holder's wallet.
            // slither-disable-next-line reentrancy-events
            token.mint(holder, count);
        } else {
            // Otherwise, add the tokens to their credits and the credit supply.
            creditBalanceOf[holder][projectId] += count;
            totalCreditSupplyOf[projectId] += count;
        }

        // The total supply can't exceed the maximum value storable in a uint208.
        if (totalSupplyOf(projectId) > type(uint208).max) {
            revert JBTokens_OverflowAlert(totalSupplyOf(projectId), type(uint208).max);
        }

        emit Mint({
            holder: holder,
            projectId: projectId,
            count: count,
            tokensWereClaimed: tokensWereClaimed,
            caller: msg.sender
        });
    }

    /// @notice Set a project's token if not already set.
    /// @dev Only a project's controller can set its token.
    /// @param projectId The ID of the project to set the token of.
    /// @param token The new token's address.
    function setTokenFor(uint256 projectId, IJBToken token) external override onlyControllerOf(projectId) {
        // Can't set to the zero address.
        if (token == IJBToken(address(0))) revert JBTokens_EmptyToken();

        // Can't set a token if the project is already associated with another token.
        if (tokenOf[projectId] != IJBToken(address(0))) revert JBTokens_ProjectAlreadyHasToken(tokenOf[projectId]);

        // Can't set a token if it's already associated with another project.
        if (projectIdOf[token] != 0) revert JBTokens_TokenAlreadyBeingUsed(projectIdOf[token]);

        // Can't change to a token that doesn't use 18 decimals.
        if (token.decimals() != 18) revert JBTokens_TokensMustHave18Decimals(token.decimals());

        // Make sure the token can be added to the project its being added to.
        if (!token.canBeAddedTo(projectId)) revert JBTokens_TokenCantBeAdded(projectId);

        // Store the new token.
        tokenOf[projectId] = token;

        // Store the project for the token.
        projectIdOf[token] = projectId;

        emit SetToken({projectId: projectId, token: token, caller: msg.sender});
    }

    /// @notice Allows a holder to transfer credits to another account.
    /// @dev Only a project's controller can transfer credits for that project.
    /// @param holder The address to transfer credits from.
    /// @param projectId The ID of the project whose credits are being transferred.
    /// @param recipient The recipient of the credits.
    /// @param count The number of token credits to transfer.
    function transferCreditsFrom(
        address holder,
        uint256 projectId,
        address recipient,
        uint256 count
    )
        external
        override
        onlyControllerOf(projectId)
    {
        // Get a reference to the holder's unclaimed project token balance.
        uint256 creditBalance = creditBalanceOf[holder][projectId];

        // The holder must have enough unclaimed tokens to transfer.
        if (count > creditBalance) revert JBTokens_InsufficientCredits(count, creditBalance);

        // Subtract from the holder's unclaimed token balance.
        unchecked {
            creditBalanceOf[holder][projectId] = creditBalance - count;
        }

        // Add the unclaimed project tokens to the recipient's balance.
        creditBalanceOf[recipient][projectId] += count;

        emit TransferCredits({
            holder: holder,
            projectId: projectId,
            recipient: recipient,
            count: count,
            caller: msg.sender
        });
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    error CloneArgumentsTooLong();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        return clone(implementation, 0);
    }

    /**
     * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
     * to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function clone(address implementation, uint256 value) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(value, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple times will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        return cloneDeterministic(implementation, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
     * a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministic(
        address implementation,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(value, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create opcode, which should never revert.
     */
    function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
        return cloneWithImmutableArgs(implementation, args, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
     * parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneWithImmutableArgs(
        address implementation,
        bytes memory args,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        assembly ("memory-safe") {
            instance := create(value, add(bytecode, 0x20), mload(bytecode))
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
     * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
     * at the same address.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
     * but with a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.deploy(value, salt, bytecode);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.computeAddress(salt, keccak256(bytecode), deployer);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
    }

    /**
     * @dev Get the immutable args attached to a clone.
     *
     * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
     *   function will return an empty array.
     * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
     *   `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
     *   creation.
     * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
     *   function should only be used to check addresses that are known to be clones.
     */
    function fetchCloneArgs(address instance) internal view returns (bytes memory) {
        bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
        assembly ("memory-safe") {
            extcodecopy(instance, add(result, 32), 45, mload(result))
        }
        return result;
    }

    /**
     * @dev Helper that prepares the initcode of the proxy with immutable args.
     *
     * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
     * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
     * abi.encodePacked is more expensive but also more portable and easier to review.
     *
     * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
     * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
     */
    function _cloneCodeWithImmutableArgs(
        address implementation,
        bytes memory args
    ) private pure returns (bytes memory) {
        if (args.length > 24531) revert CloneArgumentsTooLong();
        return
            abi.encodePacked(
                hex"61",
                uint16(args.length + 45),
                hex"3d81600a3d39f3363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3",
                args
            );
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}

File 5 of 18 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 7 of 18 : JBControlled.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IJBControlled} from "./../interfaces/IJBControlled.sol";
import {IJBDirectory} from "./../interfaces/IJBDirectory.sol";

/// @notice Provides a modifier for contracts with functionality that can only be accessed by a project's controller.
abstract contract JBControlled is IJBControlled {
    //*********************************************************************//
    // --------------------------- custom errors -------------------------- //
    //*********************************************************************//

    error JBControlled_ControllerUnauthorized(address controller);

    //*********************************************************************//
    // ---------------------------- modifiers ---------------------------- //
    //*********************************************************************//

    /// @notice Only allows the controller of the specified project to proceed.
    /// @param projectId The ID of the project.
    modifier onlyControllerOf(uint256 projectId) {
        _onlyControllerOf(projectId);
        _;
    }

    //*********************************************************************//
    // ---------------- public immutable stored properties --------------- //
    //*********************************************************************//

    /// @notice The directory of terminals and controllers for projects.
    IJBDirectory public immutable override DIRECTORY;

    //*********************************************************************//
    // -------------------------- constructor ---------------------------- //
    //*********************************************************************//

    /// @param directory A contract storing directories of terminals and controllers for each project.
    constructor(IJBDirectory directory) {
        DIRECTORY = directory;
    }

    /// @notice Only allows the controller of the specified project to proceed.
    function _onlyControllerOf(uint256 projectId) internal view {
        if (address(DIRECTORY.controllerOf(projectId)) != msg.sender) {
            revert JBControlled_ControllerUnauthorized(address(DIRECTORY.controllerOf(projectId)));
        }
    }
}

File 8 of 18 : IJBControlled.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IJBDirectory} from "./IJBDirectory.sol";

interface IJBControlled {
    function DIRECTORY() external view returns (IJBDirectory);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IJBProjects} from "./IJBProjects.sol";
import {IJBTerminal} from "./IJBTerminal.sol";

interface IJBDirectory {
    event AddTerminal(uint256 indexed projectId, IJBTerminal indexed terminal, address caller);
    event SetController(uint256 indexed projectId, IERC165 indexed controller, address caller);
    event SetIsAllowedToSetFirstController(address indexed addr, bool indexed isAllowed, address caller);
    event SetPrimaryTerminal(
        uint256 indexed projectId, address indexed token, IJBTerminal indexed terminal, address caller
    );
    event SetTerminals(uint256 indexed projectId, IJBTerminal[] terminals, address caller);

    function PROJECTS() external view returns (IJBProjects);

    function controllerOf(uint256 projectId) external view returns (IERC165);
    function isAllowedToSetFirstController(address account) external view returns (bool);
    function isTerminalOf(uint256 projectId, IJBTerminal terminal) external view returns (bool);
    function primaryTerminalOf(uint256 projectId, address token) external view returns (IJBTerminal);
    function terminalsOf(uint256 projectId) external view returns (IJBTerminal[] memory);

    function setControllerOf(uint256 projectId, IERC165 controller) external;
    function setIsAllowedToSetFirstController(address account, bool flag) external;
    function setPrimaryTerminalOf(uint256 projectId, address token, IJBTerminal terminal) external;
    function setTerminalsOf(uint256 projectId, IJBTerminal[] calldata terminals) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBAfterPayRecordedContext} from "./../structs/JBAfterPayRecordedContext.sol";

/// @notice Hook called after a terminal's `pay(...)` logic completes (if passed by the ruleset's data hook).
interface IJBPayHook is IERC165 {
    /// @notice This function is called by the terminal's `pay(...)` function after the payment has been recorded in the
    /// terminal store.
    /// @dev Critical business logic should be protected by appropriate access control.
    /// @param context The context passed in by the terminal, as a `JBAfterPayRecordedContext` struct.
    function afterPayRecordedWith(JBAfterPayRecordedContext calldata context) external payable;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";

import {IJBTokenUriResolver} from "./IJBTokenUriResolver.sol";

interface IJBProjects is IERC721 {
    event Create(uint256 indexed projectId, address indexed owner, address caller);
    event SetTokenUriResolver(IJBTokenUriResolver indexed resolver, address caller);

    function count() external view returns (uint256);
    function tokenUriResolver() external view returns (IJBTokenUriResolver);

    function createFor(address owner) external returns (uint256 projectId);
    function setTokenUriResolver(IJBTokenUriResolver resolver) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {IJBPayHook} from "./IJBPayHook.sol";
import {JBAccountingContext} from "../structs/JBAccountingContext.sol";
import {JBAfterPayRecordedContext} from "../structs/JBAfterPayRecordedContext.sol";

/// @notice A terminal that accepts payments and can be migrated.
interface IJBTerminal is IERC165 {
    event AddToBalance(
        uint256 indexed projectId, uint256 amount, uint256 returnedFees, string memo, bytes metadata, address caller
    );
    event HookAfterRecordPay(
        IJBPayHook indexed hook, JBAfterPayRecordedContext context, uint256 specificationAmount, address caller
    );

    event MigrateTerminal(
        uint256 indexed projectId, address indexed token, IJBTerminal indexed to, uint256 amount, address caller
    );
    event Pay(
        uint256 indexed rulesetId,
        uint256 indexed rulesetCycleNumber,
        uint256 indexed projectId,
        address payer,
        address beneficiary,
        uint256 amount,
        uint256 newlyIssuedTokenCount,
        string memo,
        bytes metadata,
        address caller
    );
    event SetAccountingContext(uint256 indexed projectId, JBAccountingContext context, address caller);

    function accountingContextForTokenOf(
        uint256 projectId,
        address token
    )
        external
        view
        returns (JBAccountingContext memory);
    function accountingContextsOf(uint256 projectId) external view returns (JBAccountingContext[] memory);
    function currentSurplusOf(
        uint256 projectId,
        JBAccountingContext[] memory accountingContexts,
        uint256 decimals,
        uint256 currency
    )
        external
        view
        returns (uint256);

    function addAccountingContextsFor(uint256 projectId, JBAccountingContext[] calldata accountingContexts) external;
    function addToBalanceOf(
        uint256 projectId,
        address token,
        uint256 amount,
        bool shouldReturnHeldFees,
        string calldata memo,
        bytes calldata metadata
    )
        external
        payable;
    function migrateBalanceOf(uint256 projectId, address token, IJBTerminal to) external returns (uint256 balance);
    function pay(
        uint256 projectId,
        address token,
        uint256 amount,
        address beneficiary,
        uint256 minReturnedTokens,
        string calldata memo,
        bytes calldata metadata
    )
        external
        payable
        returns (uint256 beneficiaryTokenCount);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IJBToken {
    function balanceOf(address account) external view returns (uint256);
    function canBeAddedTo(uint256 projectId) external view returns (bool);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);

    function initialize(string memory name, string memory symbol, address owner) external;
    function burn(address account, uint256 amount) external;
    function mint(address account, uint256 amount) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IJBTokenUriResolver {
    function getUri(uint256 projectId) external view returns (string memory tokenUri);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IJBToken} from "./IJBToken.sol";

interface IJBTokens {
    event DeployERC20(
        uint256 indexed projectId, IJBToken indexed token, string name, string symbol, bytes32 salt, address caller
    );
    event Burn(
        address indexed holder,
        uint256 indexed projectId,
        uint256 count,
        uint256 creditBalance,
        uint256 tokenBalance,
        address caller
    );
    event ClaimTokens(
        address indexed holder,
        uint256 indexed projectId,
        uint256 creditBalance,
        uint256 count,
        address beneficiary,
        address caller
    );
    event Mint(
        address indexed holder, uint256 indexed projectId, uint256 count, bool tokensWereClaimed, address caller
    );
    event SetToken(uint256 indexed projectId, IJBToken indexed token, address caller);
    event TransferCredits(
        address indexed holder, uint256 indexed projectId, address indexed recipient, uint256 count, address caller
    );

    function creditBalanceOf(address holder, uint256 projectId) external view returns (uint256);
    function projectIdOf(IJBToken token) external view returns (uint256);
    function tokenOf(uint256 projectId) external view returns (IJBToken);
    function totalCreditSupplyOf(uint256 projectId) external view returns (uint256);

    function totalBalanceOf(address holder, uint256 projectId) external view returns (uint256 result);
    function totalSupplyOf(uint256 projectId) external view returns (uint256);

    function burnFrom(address holder, uint256 projectId, uint256 count) external;
    function claimTokensFor(address holder, uint256 projectId, uint256 count, address beneficiary) external;
    function deployERC20For(
        uint256 projectId,
        string calldata name,
        string calldata symbol,
        bytes32 salt
    )
        external
        returns (IJBToken token);
    function mintFor(address holder, uint256 projectId, uint256 count) external returns (IJBToken token);
    function setTokenFor(uint256 projectId, IJBToken token) external;
    function transferCreditsFrom(address holder, uint256 projectId, address recipient, uint256 count) external;
}

File 16 of 18 : JBAccountingContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member token The address of the token that accounting is being done with.
/// @custom:member decimals The number of decimals expected in that token's fixed point accounting.
/// @custom:member currency The currency that the token is priced in terms of. By convention, this is
/// `uint32(uint160(tokenAddress))` for tokens, or a constant ID from e.g. `JBCurrencyIds` for other currencies.
struct JBAccountingContext {
    address token;
    uint8 decimals;
    uint32 currency;
}

File 17 of 18 : JBAfterPayRecordedContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {JBTokenAmount} from "./JBTokenAmount.sol";

/// @custom:member payer The address the payment originated from.
/// @custom:member projectId The ID of the project being paid.
/// @custom:member rulesetId The ID of the ruleset the payment is being made during.
/// @custom:member amount The payment's token amount. Includes the token being paid, the value, the number of decimals
/// included, and the currency of the amount.
/// @custom:member forwardedAmount The token amount being forwarded to the pay hook. Includes the token
/// being paid, the value, the number of decimals included, and the currency of the amount.
/// @custom:member weight The current ruleset's weight (used to determine how many tokens should be minted).
/// @custom:member newlyIssuedTokenCount The number of project tokens minted for the beneficiary.
/// @custom:member beneficiary The address which receives any tokens this payment yields.
/// @custom:member hookMetadata Extra data specified by the data hook, which is sent to the pay hook.
/// @custom:member payerMetadata Extra data specified by the payer, which is sent to the pay hook.
struct JBAfterPayRecordedContext {
    address payer;
    uint256 projectId;
    uint256 rulesetId;
    JBTokenAmount amount;
    JBTokenAmount forwardedAmount;
    uint256 weight;
    uint256 newlyIssuedTokenCount;
    address beneficiary;
    bytes hookMetadata;
    bytes payerMetadata;
}

File 18 of 18 : JBTokenAmount.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @custom:member token The token the payment was made in.
/// @custom:member decimals The number of decimals included in the value fixed point number.
/// @custom:member currency The currency. By convention, this is `uint32(uint160(tokenAddress))` for tokens, or a
/// constant ID from e.g. `JBCurrencyIds` for other currencies.
/// @custom:member value The amount of tokens that was paid, as a fixed point number.
struct JBTokenAmount {
    address token;
    uint8 decimals;
    uint32 currency;
    uint256 value;
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "appendCBOR": true,
    "bytecodeHash": "ipfs",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "@sphinx-labs/contracts/=lib/sphinx/packages/contracts/contracts/foundry/",
    "@arbitrum/=node_modules/@arbitrum/",
    "@bananapus/=node_modules/@bananapus/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@offchainlabs/=node_modules/@offchainlabs/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@prb/=node_modules/@prb/",
    "@scroll-tech/=node_modules/@scroll-tech/",
    "@uniswap/=node_modules/@uniswap/",
    "@zksync/=node_modules/@zksync/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "solmate/=node_modules/solmate/",
    "sphinx/=lib/sphinx/packages/contracts/contracts/forge-std/src/"
  ],
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract IJBDirectory","name":"directory","type":"address"},{"internalType":"contract IJBToken","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"controller","type":"address"}],"name":"JBControlled_ControllerUnauthorized","type":"error"},{"inputs":[],"name":"JBTokens_EmptyName","type":"error"},{"inputs":[],"name":"JBTokens_EmptySymbol","type":"error"},{"inputs":[],"name":"JBTokens_EmptyToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"creditBalance","type":"uint256"}],"name":"JBTokens_InsufficientCredits","type":"error"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"uint256","name":"tokenBalance","type":"uint256"}],"name":"JBTokens_InsufficientTokensToBurn","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"JBTokens_OverflowAlert","type":"error"},{"inputs":[{"internalType":"contract IJBToken","name":"token","type":"address"}],"name":"JBTokens_ProjectAlreadyHasToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"JBTokens_TokenAlreadyBeingUsed","type":"error"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"JBTokens_TokenCantBeAdded","type":"error"},{"inputs":[],"name":"JBTokens_TokenNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"decimals","type":"uint256"}],"name":"JBTokens_TokensMustHave18Decimals","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creditBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenBalance","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"creditBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"ClaimTokens","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"contract IJBToken","name":"token","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"DeployERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"bool","name":"tokensWereClaimed","type":"bool"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"contract IJBToken","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"SetToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"indexed":true,"internalType":"uint256","name":"projectId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"TransferCredits","type":"event"},{"inputs":[],"name":"DIRECTORY","outputs":[{"internalType":"contract IJBDirectory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN","outputs":[{"internalType":"contract IJBToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"}],"name":"claimTokensFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"creditBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"deployERC20For","outputs":[{"internalType":"contract IJBToken","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"mintFor","outputs":[{"internalType":"contract IJBToken","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IJBToken","name":"token","type":"address"}],"name":"projectIdOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"contract IJBToken","name":"token","type":"address"}],"name":"setTokenFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"tokenOf","outputs":[{"internalType":"contract IJBToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"totalBalanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"totalCreditSupplyOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId","type":"uint256"}],"name":"totalSupplyOf","outputs":[{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"projectId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"transferCreditsFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c060405234801561001057600080fd5b50604051620016743803806200167483398101604081905261003191610060565b6001600160a01b039182166080521660a05261009a565b6001600160a01b038116811461005d57600080fd5b50565b6000806040838503121561007357600080fd5b825161007e81610048565b602084015190925061008f81610048565b809150509250929050565b60805160a051611598620000dc600039600081816101ad0152818161072101526107690152600081816101e701528181610f3a0152610fc901526115986000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063878003b81161008c578063b1e6d2a111610066578063b1e6d2a11461021c578063c6c116bd1461022f578063ea78803f14610257578063f12b64a51461028057600080fd5b8063878003b8146101cf57806388bc2ef3146101e2578063aab68bdb1461020957600080fd5b806358178191116100c8578063581781911461014a57806366d542161461017557806375b0d9cd1461019557806382bfefc8146101a857600080fd5b80630f85421b146100ef578063124d91e514610122578063303f5dfa14610137575b600080fd5b61010f6100fd3660046111d1565b60016020526000908152604090205481565b6040519081526020015b60405180910390f35b6101356101303660046111ee565b610293565b005b610135610145366004611223565b6104ee565b61015d6101583660046112b6565b610663565b6040516001600160a01b039091168152602001610119565b61010f610183366004611338565b60036020526000908152604090205481565b61010f6101a3366004611338565b610881565b61015d7f000000000000000000000000000000000000000000000000000000000000000081565b61010f6101dd366004611351565b610920565b61015d7f000000000000000000000000000000000000000000000000000000000000000081565b61015d6102173660046111ee565b6109d3565b61013561022a36600461137d565b610b63565b61010f61023d366004611351565b600060208181529281526040808220909352908152205481565b61015d610265366004611338565b6002602052600090815260409020546001600160a01b031681565b61013561028e3660046113c5565b610c5b565b8161029d81610f1a565b6000838152600260209081526040808320546001600160a01b038881168552848452828520888652909352908320549116918215610344576040516370a0823160e01b81526001600160a01b0388811660048301528416906370a0823190602401602060405180830381865afa15801561031b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033f91906113f5565b610347565b60005b90506103538282611424565b85111561038c57846103658383611424565b6040516305dc356160e51b8152600481019290925260248201526044015b60405180910390fd5b600081156103a9578583106103a25760006103a6565b8286035b90505b808603868214610426576001600160a01b0389166000908152602081815260408083208b84529091529020546103e0908290611437565b6001600160a01b038a166000908152602081815260408083208c8452825280832093909355600390522054610416908290611437565b6000898152600360205260409020555b604080518881526020810186905290810184905233606082015288906001600160a01b038b16907fa6a919b3314fbbdb84c4a64d62f381f104d0c1747b789163262d2fcfeec292689060800160405180910390a381156104e357604051632770a7eb60e21b81526001600160a01b038a8116600483015260248201849052861690639dc29fac90604401600060405180830381600087803b1580156104ca57600080fd5b505af11580156104de573d6000803e3d6000fd5b505050505b505050505050505050565b826104f881610f1a565b6000848152600260205260409020546001600160a01b03168061052e576040516335fb0a2760e11b815260040160405180910390fd5b6001600160a01b0386166000908152602081815260408083208884529091529020548085111561057b5760405163914993a160e01b81526004810186905260248101829052604401610383565b6001600160a01b038781166000818152602081815260408083208b845282528083208a87039055600382529182902080548a9003905581518581529081018990529287169083015233606083015287917fde5600808a2321d39207ba773327f7a932a4b0b019107fb5a95618006cd0ff009060800160405180910390a36040516340c10f1960e01b81526001600160a01b038581166004830152602482018790528316906340c10f1990604401600060405180830381600087803b15801561064257600080fd5b505af1158015610656573d6000803e3d6000fd5b5050505050505050505050565b60008661066f81610f1a565b60008690036106915760405163109f035760e21b815260040160405180910390fd5b60008490036106b357604051630d1a676960e31b815260040160405180910390fd5b6000888152600260205260409020546001600160a01b03161561070557600088815260026020526040908190205490516378ed73ed60e11b81526001600160a01b039091166004820152602401610383565b8215610764576040805133602082015290810184905261075f907f00000000000000000000000000000000000000000000000000000000000000009060600160405160208183030381529060405280519060200120611064565b61078d565b61078d7f000000000000000000000000000000000000000000000000000000000000000061107b565b600089815260026020908152604080832080546001600160a01b0319166001600160a01b0386169081179091558084526001909252918290208b905590519193509089907fb4510654a5884cae50948507300dc482833ed1446cef375e064bef00b6b4ba4e90610808908b908b908b908b908b903390611473565b60405180910390a36040516303bf912560e11b81526001600160a01b0383169063077f224a90610844908a908a908a908a9030906004016114be565b600060405180830381600087803b15801561085e57600080fd5b505af1158015610872573d6000803e3d6000fd5b50505050509695505050505050565b6000818152600360209081526040808320546002909252909120546001600160a01b0316801561091a57806001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090d91906113f5565b6109179083611424565b91505b50919050565b6001600160a01b0380831660009081526020818152604080832085845282528083205460029092529091205490911680156109cc576040516370a0823160e01b81526001600160a01b0385811660048301528216906370a0823190602401602060405180830381865afa15801561099b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bf91906113f5565b6109c99083611424565b91505b5092915050565b6000826109df81610f1a565b6000848152600260205260409020546001600160a01b031691508115801590610a69576040516340c10f1960e01b81526001600160a01b038781166004830152602482018690528416906340c10f1990604401600060405180830381600087803b158015610a4c57600080fd5b505af1158015610a60573d6000803e3d6000fd5b50505050610ac3565b6001600160a01b03861660009081526020818152604080832088845290915281208054869290610a9a908490611424565b909155505060008581526003602052604081208054869290610abd908490611424565b90915550505b6001600160d01b03610ad486610881565b1115610b0d57610ae385610881565b60405163a2f5932960e01b815260048101919091526001600160d01b036024820152604401610383565b6040805185815282151560208201523381830152905186916001600160a01b038916917f0153be209252ccc3b70df14d55d2cc93fa5a74e263b163d9a1caf45152fd0e869181900360600190a350509392505050565b82610b6d81610f1a565b6001600160a01b03851660009081526020818152604080832087845290915290205480831115610bba5760405163914993a160e01b81526004810184905260248101829052604401610383565b6001600160a01b0380871660009081526020818152604080832089845282528083208786039055928716825281815282822088835290529081208054859290610c04908490611424565b9091555050604080518481523360208201526001600160a01b03808716928892918a16917f6d86dde1e9f07a2ad1e0f3e611b7bb8343d629126c5ca73f1a5951177d87143f910160405180910390a4505050505050565b81610c6581610f1a565b6001600160a01b038216610c8c57604051637661e72d60e01b815260040160405180910390fd5b6000838152600260205260409020546001600160a01b031615610cde57600083815260026020526040908190205490516378ed73ed60e11b81526001600160a01b039091166004820152602401610383565b6001600160a01b03821660009081526001602052604090205415610d33576001600160a01b0382166000908152600160205260409081902054905163487d5b8b60e11b81526004810191909152602401610383565b816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d959190611500565b60ff16601214610e2057816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ddd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e019190611500565b604051630a51f6ff60e41b815260ff9091166004820152602401610383565b60405163372ff0f960e11b8152600481018490526001600160a01b03831690636e5fe1f290602401602060405180830381865afa158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e899190611523565b610ea9576040516305b5c3d160e31b815260048101849052602401610383565b600083815260026020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260018352928190208690555133815285917f768e177d7f9dac714049e6d43d9ac533cf0c6cc23cddcfe642bfd7a18bee3772910160405180910390a3505050565b604051632eec7b5560e11b81526004810182905233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635dd8f6aa90602401602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa59190611545565b6001600160a01b03161461106157604051632eec7b5560e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015611018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103c9190611545565b604051639a007b3960e01b81526001600160a01b039091166004820152602401610383565b50565b600061107283836000611088565b90505b92915050565b6000611075826000611126565b6000814710156110b45760405163cf47918160e01b815247600482015260248101839052604401610383565b763d602d80600a3d3981f3363d3d373d3d3d363d730000008460601b60e81c176000526e5af43d82803e903d91602b57fd5bf38460781b17602052826037600984f590506001600160a01b03811661111f5760405163b06ebf3d60e01b815260040160405180910390fd5b9392505050565b6000814710156111525760405163cf47918160e01b815247600482015260248101839052604401610383565b763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b176020526037600983f090506001600160a01b0381166110755760405163b06ebf3d60e01b815260040160405180910390fd5b6001600160a01b038116811461106157600080fd5b6000602082840312156111e357600080fd5b813561111f816111bc565b60008060006060848603121561120357600080fd5b833561120e816111bc565b95602085013595506040909401359392505050565b6000806000806080858703121561123957600080fd5b8435611244816111bc565b935060208501359250604085013591506060850135611262816111bc565b939692955090935050565b60008083601f84011261127f57600080fd5b50813567ffffffffffffffff81111561129757600080fd5b6020830191508360208285010111156112af57600080fd5b9250929050565b600080600080600080608087890312156112cf57600080fd5b86359550602087013567ffffffffffffffff808211156112ee57600080fd5b6112fa8a838b0161126d565b9097509550604089013591508082111561131357600080fd5b5061132089828a0161126d565b979a9699509497949695606090950135949350505050565b60006020828403121561134a57600080fd5b5035919050565b6000806040838503121561136457600080fd5b823561136f816111bc565b946020939093013593505050565b6000806000806080858703121561139357600080fd5b843561139e816111bc565b93506020850135925060408501356113b5816111bc565b9396929550929360600135925050565b600080604083850312156113d857600080fd5b8235915060208301356113ea816111bc565b809150509250929050565b60006020828403121561140757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156110755761107561140e565b818103818111156110755761107561140e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60808152600061148760808301888a61144a565b828103602084015261149a81878961144a565b604084019590955250506001600160a01b0391909116606090910152949350505050565b6060815260006114d260608301878961144a565b82810360208401526114e581868861144a565b91505060018060a01b03831660408301529695505050505050565b60006020828403121561151257600080fd5b815160ff8116811461111f57600080fd5b60006020828403121561153557600080fd5b8151801515811461111f57600080fd5b60006020828403121561155757600080fd5b815161111f816111bc56fea2646970667358221220159bede09f7ed738deda3bfba7405d6e22b06e25bef90ab27cd0f01725af995864736f6c634300081700330000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063878003b81161008c578063b1e6d2a111610066578063b1e6d2a11461021c578063c6c116bd1461022f578063ea78803f14610257578063f12b64a51461028057600080fd5b8063878003b8146101cf57806388bc2ef3146101e2578063aab68bdb1461020957600080fd5b806358178191116100c8578063581781911461014a57806366d542161461017557806375b0d9cd1461019557806382bfefc8146101a857600080fd5b80630f85421b146100ef578063124d91e514610122578063303f5dfa14610137575b600080fd5b61010f6100fd3660046111d1565b60016020526000908152604090205481565b6040519081526020015b60405180910390f35b6101356101303660046111ee565b610293565b005b610135610145366004611223565b6104ee565b61015d6101583660046112b6565b610663565b6040516001600160a01b039091168152602001610119565b61010f610183366004611338565b60036020526000908152604090205481565b61010f6101a3366004611338565b610881565b61015d7f000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a81565b61010f6101dd366004611351565b610920565b61015d7f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa4181565b61015d6102173660046111ee565b6109d3565b61013561022a36600461137d565b610b63565b61010f61023d366004611351565b600060208181529281526040808220909352908152205481565b61015d610265366004611338565b6002602052600090815260409020546001600160a01b031681565b61013561028e3660046113c5565b610c5b565b8161029d81610f1a565b6000838152600260209081526040808320546001600160a01b038881168552848452828520888652909352908320549116918215610344576040516370a0823160e01b81526001600160a01b0388811660048301528416906370a0823190602401602060405180830381865afa15801561031b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061033f91906113f5565b610347565b60005b90506103538282611424565b85111561038c57846103658383611424565b6040516305dc356160e51b8152600481019290925260248201526044015b60405180910390fd5b600081156103a9578583106103a25760006103a6565b8286035b90505b808603868214610426576001600160a01b0389166000908152602081815260408083208b84529091529020546103e0908290611437565b6001600160a01b038a166000908152602081815260408083208c8452825280832093909355600390522054610416908290611437565b6000898152600360205260409020555b604080518881526020810186905290810184905233606082015288906001600160a01b038b16907fa6a919b3314fbbdb84c4a64d62f381f104d0c1747b789163262d2fcfeec292689060800160405180910390a381156104e357604051632770a7eb60e21b81526001600160a01b038a8116600483015260248201849052861690639dc29fac90604401600060405180830381600087803b1580156104ca57600080fd5b505af11580156104de573d6000803e3d6000fd5b505050505b505050505050505050565b826104f881610f1a565b6000848152600260205260409020546001600160a01b03168061052e576040516335fb0a2760e11b815260040160405180910390fd5b6001600160a01b0386166000908152602081815260408083208884529091529020548085111561057b5760405163914993a160e01b81526004810186905260248101829052604401610383565b6001600160a01b038781166000818152602081815260408083208b845282528083208a87039055600382529182902080548a9003905581518581529081018990529287169083015233606083015287917fde5600808a2321d39207ba773327f7a932a4b0b019107fb5a95618006cd0ff009060800160405180910390a36040516340c10f1960e01b81526001600160a01b038581166004830152602482018790528316906340c10f1990604401600060405180830381600087803b15801561064257600080fd5b505af1158015610656573d6000803e3d6000fd5b5050505050505050505050565b60008661066f81610f1a565b60008690036106915760405163109f035760e21b815260040160405180910390fd5b60008490036106b357604051630d1a676960e31b815260040160405180910390fd5b6000888152600260205260409020546001600160a01b03161561070557600088815260026020526040908190205490516378ed73ed60e11b81526001600160a01b039091166004820152602401610383565b8215610764576040805133602082015290810184905261075f907f000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a9060600160405160208183030381529060405280519060200120611064565b61078d565b61078d7f000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a61107b565b600089815260026020908152604080832080546001600160a01b0319166001600160a01b0386169081179091558084526001909252918290208b905590519193509089907fb4510654a5884cae50948507300dc482833ed1446cef375e064bef00b6b4ba4e90610808908b908b908b908b908b903390611473565b60405180910390a36040516303bf912560e11b81526001600160a01b0383169063077f224a90610844908a908a908a908a9030906004016114be565b600060405180830381600087803b15801561085e57600080fd5b505af1158015610872573d6000803e3d6000fd5b50505050509695505050505050565b6000818152600360209081526040808320546002909252909120546001600160a01b0316801561091a57806001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090d91906113f5565b6109179083611424565b91505b50919050565b6001600160a01b0380831660009081526020818152604080832085845282528083205460029092529091205490911680156109cc576040516370a0823160e01b81526001600160a01b0385811660048301528216906370a0823190602401602060405180830381865afa15801561099b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bf91906113f5565b6109c99083611424565b91505b5092915050565b6000826109df81610f1a565b6000848152600260205260409020546001600160a01b031691508115801590610a69576040516340c10f1960e01b81526001600160a01b038781166004830152602482018690528416906340c10f1990604401600060405180830381600087803b158015610a4c57600080fd5b505af1158015610a60573d6000803e3d6000fd5b50505050610ac3565b6001600160a01b03861660009081526020818152604080832088845290915281208054869290610a9a908490611424565b909155505060008581526003602052604081208054869290610abd908490611424565b90915550505b6001600160d01b03610ad486610881565b1115610b0d57610ae385610881565b60405163a2f5932960e01b815260048101919091526001600160d01b036024820152604401610383565b6040805185815282151560208201523381830152905186916001600160a01b038916917f0153be209252ccc3b70df14d55d2cc93fa5a74e263b163d9a1caf45152fd0e869181900360600190a350509392505050565b82610b6d81610f1a565b6001600160a01b03851660009081526020818152604080832087845290915290205480831115610bba5760405163914993a160e01b81526004810184905260248101829052604401610383565b6001600160a01b0380871660009081526020818152604080832089845282528083208786039055928716825281815282822088835290529081208054859290610c04908490611424565b9091555050604080518481523360208201526001600160a01b03808716928892918a16917f6d86dde1e9f07a2ad1e0f3e611b7bb8343d629126c5ca73f1a5951177d87143f910160405180910390a4505050505050565b81610c6581610f1a565b6001600160a01b038216610c8c57604051637661e72d60e01b815260040160405180910390fd5b6000838152600260205260409020546001600160a01b031615610cde57600083815260026020526040908190205490516378ed73ed60e11b81526001600160a01b039091166004820152602401610383565b6001600160a01b03821660009081526001602052604090205415610d33576001600160a01b0382166000908152600160205260409081902054905163487d5b8b60e11b81526004810191909152602401610383565b816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d959190611500565b60ff16601214610e2057816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ddd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e019190611500565b604051630a51f6ff60e41b815260ff9091166004820152602401610383565b60405163372ff0f960e11b8152600481018490526001600160a01b03831690636e5fe1f290602401602060405180830381865afa158015610e65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e899190611523565b610ea9576040516305b5c3d160e31b815260048101849052602401610383565b600083815260026020908152604080832080546001600160a01b0319166001600160a01b03871690811790915580845260018352928190208690555133815285917f768e177d7f9dac714049e6d43d9ac533cf0c6cc23cddcfe642bfd7a18bee3772910160405180910390a3505050565b604051632eec7b5560e11b81526004810182905233906001600160a01b037f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa411690635dd8f6aa90602401602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa59190611545565b6001600160a01b03161461106157604051632eec7b5560e11b8152600481018290527f0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa416001600160a01b031690635dd8f6aa90602401602060405180830381865afa158015611018573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103c9190611545565b604051639a007b3960e01b81526001600160a01b039091166004820152602401610383565b50565b600061107283836000611088565b90505b92915050565b6000611075826000611126565b6000814710156110b45760405163cf47918160e01b815247600482015260248101839052604401610383565b763d602d80600a3d3981f3363d3d373d3d3d363d730000008460601b60e81c176000526e5af43d82803e903d91602b57fd5bf38460781b17602052826037600984f590506001600160a01b03811661111f5760405163b06ebf3d60e01b815260040160405180910390fd5b9392505050565b6000814710156111525760405163cf47918160e01b815247600482015260248101839052604401610383565b763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b176020526037600983f090506001600160a01b0381166110755760405163b06ebf3d60e01b815260040160405180910390fd5b6001600160a01b038116811461106157600080fd5b6000602082840312156111e357600080fd5b813561111f816111bc565b60008060006060848603121561120357600080fd5b833561120e816111bc565b95602085013595506040909401359392505050565b6000806000806080858703121561123957600080fd5b8435611244816111bc565b935060208501359250604085013591506060850135611262816111bc565b939692955090935050565b60008083601f84011261127f57600080fd5b50813567ffffffffffffffff81111561129757600080fd5b6020830191508360208285010111156112af57600080fd5b9250929050565b600080600080600080608087890312156112cf57600080fd5b86359550602087013567ffffffffffffffff808211156112ee57600080fd5b6112fa8a838b0161126d565b9097509550604089013591508082111561131357600080fd5b5061132089828a0161126d565b979a9699509497949695606090950135949350505050565b60006020828403121561134a57600080fd5b5035919050565b6000806040838503121561136457600080fd5b823561136f816111bc565b946020939093013593505050565b6000806000806080858703121561139357600080fd5b843561139e816111bc565b93506020850135925060408501356113b5816111bc565b9396929550929360600135925050565b600080604083850312156113d857600080fd5b8235915060208301356113ea816111bc565b809150509250929050565b60006020828403121561140757600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156110755761107561140e565b818103818111156110755761107561140e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60808152600061148760808301888a61144a565b828103602084015261149a81878961144a565b604084019590955250506001600160a01b0391909116606090910152949350505050565b6060815260006114d260608301878961144a565b82810360208401526114e581868861144a565b91505060018060a01b03831660408301529695505050505050565b60006020828403121561151257600080fd5b815160ff8116811461111f57600080fd5b60006020828403121561153557600080fd5b8151801515811461111f57600080fd5b60006020828403121561155757600080fd5b815161111f816111bc56fea2646970667358221220159bede09f7ed738deda3bfba7405d6e22b06e25bef90ab27cd0f01725af995864736f6c63430008170033

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

0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a

-----Decoded View---------------
Arg [0] : directory (address): 0x0bC9F153DEe4d3D474ce0903775b9b2AAae9AA41
Arg [1] : token (address): 0x920F1c48f04430D4C68A1BE1fa853f3828c7256a

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000bc9f153dee4d3d474ce0903775b9b2aaae9aa41
Arg [1] : 000000000000000000000000920f1c48f04430d4c68a1be1fa853f3828c7256a


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Juicebox is a programmable crypto fundraising platform for web3.

Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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.