Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract 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
Contract Source Code (Solidity Standard Json-Input format)
// 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)
}
}
}// 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);
}// 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)));
}
}
}// 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;
}// 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;
}// 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;
}// 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;
}{
"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
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
OVERVIEW
Juicebox is a programmable crypto fundraising platform for web3.Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.