Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Loading...
Loading
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 Name:
ReceiptTokenManager
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 10000 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity >=0.8.20;
// Interfaces
import {IERC20} from "src/interfaces/IERC20.sol";
import {IReceiptTokenManager} from "src/policies/interfaces/deposits/IReceiptTokenManager.sol";
import {IERC165} from "@openzeppelin-5.3.0/interfaces/IERC165.sol";
// Libraries
import {ERC6909Wrappable} from "src/libraries/ERC6909Wrappable.sol";
import {CloneableReceiptToken} from "src/libraries/CloneableReceiptToken.sol";
import {uint2str} from "src/libraries/Uint2Str.sol";
import {String} from "src/libraries/String.sol";
import {IDepositReceiptToken} from "src/interfaces/IDepositReceiptToken.sol";
/// @title ReceiptTokenManager
/// @notice Manager contract for creating and managing ERC6909 receipt tokens for deposits
/// @dev Extracted from DepositManager to reduce contract size.
///
/// Key Features:
/// - Creator-only minting/burning: Only the contract that creates a token can mint/burn it
/// - ERC6909 compatibility with optional ERC20 wrapping via CloneableReceiptToken clones
/// - Deterministic token ID generation based on owner, asset, deposit period, and operator
/// - Automatic wrapped token creation for seamless DeFi integration
///
/// Security Model:
/// - Token ownership is immutable and set to msg.sender during creation
/// - All mint/burn operations are gated by onlyTokenOwner modifier
/// - Token IDs include owner address to prevent collision attacks
contract ReceiptTokenManager is ERC6909Wrappable, IReceiptTokenManager {
using String for string;
// ========== STATE VARIABLES ========== //
/// @notice Maps token ID to the authorized owner (for mint/burn operations)
mapping(uint256 tokenId => address authorizedOwner) internal _tokenOwners;
// ========== CONSTRUCTOR ========== //
constructor() ERC6909Wrappable(address(new CloneableReceiptToken())) {}
// ========== TOKEN CREATION ========== //
/// @inheritdoc IReceiptTokenManager
/// @dev This function reverts if:
/// - The asset is the zero address
/// - The deposit period is 0
/// - The operator is the zero address
/// - A token with the same parameters already exists
function createToken(
IERC20 asset_,
uint8 depositPeriod_,
address operator_,
string memory operatorName_
) external returns (uint256 tokenId) {
// Validate parameters
if (address(asset_) == address(0)) {
revert ReceiptTokenManager_InvalidParams("asset");
}
if (depositPeriod_ == 0) {
revert ReceiptTokenManager_InvalidParams("depositPeriod");
}
if (operator_ == address(0)) {
revert ReceiptTokenManager_InvalidParams("operator");
}
// Use msg.sender as the owner for security
address owner = msg.sender;
// Generate token ID including owner in the hash
tokenId = getReceiptTokenId(owner, asset_, depositPeriod_, operator_);
// Validate token doesn't already exist
if (isValidTokenId(tokenId)) {
revert ReceiptTokenManager_TokenExists(tokenId);
}
// Store the authorized owner for this token
_tokenOwners[tokenId] = owner;
// Create the wrappable token with proper metadata layout for CloneableReceiptToken
string memory tokenName = string
.concat(
operatorName_,
asset_.name(),
" - ",
uint2str(depositPeriod_),
depositPeriod_ == 1 ? " month" : " months"
)
.truncate32();
string memory tokenSymbol = string
.concat(operatorName_, asset_.symbol(), "-", uint2str(depositPeriod_), "m")
.truncate32();
_createWrappableToken(
tokenId,
tokenName,
tokenSymbol,
asset_.decimals(),
abi.encodePacked(
address(this), // Owner at 0x41
address(asset_), // Asset at 0x55
depositPeriod_, // Deposit Period at 0x69
operator_ // Operator at 0x6A
),
true // Automatically create the wrapped token
);
emit TokenCreated(tokenId, owner, address(asset_), depositPeriod_, operator_);
return tokenId;
}
// ========== MINTING/BURNING ========== //
function _onlyTokenOwner(uint256 tokenId_) internal view {
address owner = getTokenOwner(tokenId_);
if (msg.sender != owner) {
revert ReceiptTokenManager_NotOwner(msg.sender, owner);
}
}
modifier onlyTokenOwner(uint256 tokenId_) {
_onlyTokenOwner(tokenId_);
_;
}
/// @inheritdoc IReceiptTokenManager
/// @dev This function reverts if:
/// - The token ID is invalid (not created)
/// - The caller is not the token owner
/// - The recipient is the zero address
/// - The amount is 0
function mint(
address to_,
uint256 tokenId_,
uint256 amount_,
bool shouldWrap_
) external onlyValidTokenId(tokenId_) onlyTokenOwner(tokenId_) {
_mint(to_, tokenId_, amount_, shouldWrap_);
}
/// @inheritdoc IReceiptTokenManager
/// @dev This function reverts if:
/// - The token ID is invalid (not created)
/// - The caller is not the token owner
/// - The account is the zero address
/// - The amount is 0
/// - For wrapped tokens: account has not approved ReceiptTokenManager to spend the wrapped ERC20 token
/// - For unwrapped tokens: account has not approved the caller to spend ERC6909 tokens
/// - The account has insufficient token balance
function burn(
address from_,
uint256 tokenId_,
uint256 amount_,
bool isWrapped_
) external onlyValidTokenId(tokenId_) onlyTokenOwner(tokenId_) {
_burn(from_, tokenId_, amount_, isWrapped_);
}
// ========== VIEW FUNCTIONS ========== //
/// @inheritdoc IReceiptTokenManager
function getReceiptTokenId(
address owner_,
IERC20 asset_,
uint8 depositPeriod_,
address operator_
) public pure override returns (uint256) {
return uint256(keccak256(abi.encode(owner_, asset_, depositPeriod_, operator_)));
}
/// @inheritdoc IReceiptTokenManager
function getTokenName(uint256 tokenId_) public view override returns (string memory) {
return name(tokenId_);
}
/// @inheritdoc IReceiptTokenManager
function getTokenSymbol(uint256 tokenId_) public view override returns (string memory) {
return symbol(tokenId_);
}
/// @inheritdoc IReceiptTokenManager
function getTokenDecimals(uint256 tokenId_) public view override returns (uint8) {
return decimals(tokenId_);
}
/// @inheritdoc IReceiptTokenManager
function getTokenOwner(uint256 tokenId_) public view override returns (address) {
return _tokenOwners[tokenId_];
}
/// @inheritdoc IReceiptTokenManager
function getTokenAsset(uint256 tokenId_) external view override returns (IERC20) {
address wrappedToken = getWrappedToken(tokenId_);
if (wrappedToken == address(0)) return IERC20(address(0));
return IDepositReceiptToken(wrappedToken).asset();
}
/// @inheritdoc IReceiptTokenManager
function getTokenDepositPeriod(uint256 tokenId_) external view override returns (uint8) {
address wrappedToken = getWrappedToken(tokenId_);
if (wrappedToken == address(0)) return 0;
return IDepositReceiptToken(wrappedToken).depositPeriod();
}
/// @inheritdoc IReceiptTokenManager
function getTokenOperator(uint256 tokenId_) external view override returns (address) {
address wrappedToken = getWrappedToken(tokenId_);
if (wrappedToken == address(0)) return address(0);
return IDepositReceiptToken(wrappedToken).operator();
}
// ========== ERC165 ========== //
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC6909Wrappable, IERC165) returns (bool) {
return
interfaceId == type(IReceiptTokenManager).interfaceId ||
ERC6909Wrappable.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
// Imported from forge-std
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
/// is the new allowance.
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed
/// to spend on behalf of `owner`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
/// `amount` is then deducted from the caller's allowance.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Returns the name of the token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the decimals places of the token.
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import {IERC20} from "src/interfaces/IERC20.sol";
import {IERC6909} from "@openzeppelin-5.3.0/interfaces/draft-IERC6909.sol";
import {IERC6909Wrappable} from "src/interfaces/IERC6909Wrappable.sol";
/// @title IReceiptTokenManager
/// @notice Interface for the contract that creates and manages receipt tokens
interface IReceiptTokenManager is IERC6909, IERC6909Wrappable {
// ========== EVENTS ========== //
event TokenCreated(
uint256 indexed tokenId,
address indexed owner,
address indexed asset,
uint8 depositPeriod,
address operator
);
// ========== ERRORS ========== //
error ReceiptTokenManager_TokenExists(uint256 tokenId);
error ReceiptTokenManager_NotOwner(address caller, address owner);
error ReceiptTokenManager_InvalidParams(string reason);
// ========== FUNCTIONS ========== //
/// @notice Creates a new receipt token
/// @dev The caller (msg.sender) becomes the owner of the token for security
///
/// @param asset_ The underlying asset
/// @param depositPeriod_ The deposit period
/// @param operator_ The operator address
/// @param operatorName_ The operator name for token metadata
/// @return tokenId The created token ID
function createToken(
IERC20 asset_,
uint8 depositPeriod_,
address operator_,
string memory operatorName_
) external returns (uint256 tokenId);
/// @notice Mints tokens to a recipient
/// @dev Gated to the owner (creator) of the token
///
/// @param to_ The recipient
/// @param tokenId_ The token ID
/// @param amount_ The amount to mint
/// @param shouldWrap_ Whether to wrap as ERC20
function mint(address to_, uint256 tokenId_, uint256 amount_, bool shouldWrap_) external;
/// @notice Burns tokens from a holder
/// @dev Gated to the owner (creator) of the token
///
/// @param from_ The holder
/// @param tokenId_ The token ID
/// @param amount_ The amount to burn
/// @param isWrapped_ Whether the tokens are wrapped
function burn(address from_, uint256 tokenId_, uint256 amount_, bool isWrapped_) external;
/// @notice Generates a receipt token ID
///
/// @param owner_ The owner address
/// @param asset_ The asset
/// @param depositPeriod_ The deposit period
/// @param operator_ The operator
/// @return tokenId The generated token ID
function getReceiptTokenId(
address owner_,
IERC20 asset_,
uint8 depositPeriod_,
address operator_
) external pure returns (uint256 tokenId);
/// @notice Returns the name of a receipt token
///
/// @param tokenId_ The ID of the receipt token
/// @return name The name of the receipt token
function getTokenName(uint256 tokenId_) external view returns (string memory name);
/// @notice Returns the symbol of a receipt token
///
/// @param tokenId_ The ID of the receipt token
/// @return symbol The symbol of the receipt token
function getTokenSymbol(uint256 tokenId_) external view returns (string memory symbol);
/// @notice Returns the decimals of a receipt token
///
/// @param tokenId_ The ID of the receipt token
/// @return decimals The decimals of the receipt token
function getTokenDecimals(uint256 tokenId_) external view returns (uint8 decimals);
/// @notice Gets the owner of a token
///
/// @param tokenId_ The token ID
/// @return owner The token owner
function getTokenOwner(uint256 tokenId_) external view returns (address owner);
/// @notice Gets the asset of a token
///
/// @param tokenId_ The token ID
/// @return asset The underlying asset
function getTokenAsset(uint256 tokenId_) external view returns (IERC20 asset);
/// @notice Gets the deposit period of a token
///
/// @param tokenId_ The token ID
/// @return depositPeriod The deposit period
function getTokenDepositPeriod(uint256 tokenId_) external view returns (uint8 depositPeriod);
/// @notice Gets the operator of a token
///
/// @param tokenId_ The token ID
/// @return operator The operator address
function getTokenOperator(uint256 tokenId_) external view returns (address operator);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
pragma solidity >=0.8.20;
// Interfaces
import {IERC20BurnableMintable} from "src/interfaces/IERC20BurnableMintable.sol";
import {IERC165} from "@openzeppelin-5.3.0/interfaces/IERC165.sol";
import {IERC6909Metadata, IERC6909TokenSupply} from "@openzeppelin-5.3.0/interfaces/draft-IERC6909.sol";
import {IERC6909Wrappable} from "src/interfaces/IERC6909Wrappable.sol";
// Libraries
import {ERC6909} from "@openzeppelin-5.3.0/token/ERC6909/draft-ERC6909.sol";
import {ERC6909Metadata} from "@openzeppelin-5.3.0/token/ERC6909/extensions/draft-ERC6909Metadata.sol";
import {ClonesWithImmutableArgs} from "@clones-with-immutable-args-1.1.2/ClonesWithImmutableArgs.sol";
import {EnumerableSet} from "@openzeppelin-5.3.0/utils/structs/EnumerableSet.sol";
/// @title ERC6909Wrappable
/// @notice This abstract contract extends ERC6909 to allow for wrapping and unwrapping of the token to an ERC20 token.
/// It extends the ERC6909Metadata contract, and additionally implements the IERC6909TokenSupply interface.
abstract contract ERC6909Wrappable is ERC6909Metadata, IERC6909Wrappable, IERC6909TokenSupply {
using ClonesWithImmutableArgs for address;
using EnumerableSet for EnumerableSet.UintSet;
/// @notice The address of the implementation of the ERC20 contract
address private immutable _ERC20_IMPLEMENTATION;
/// @notice The set of all token IDs
EnumerableSet.UintSet internal _wrappableTokenIds;
/// @notice The total supply of each token
mapping(uint256 tokenId => uint256) private _totalSupplies;
/// @notice Additional metadata for each token
mapping(uint256 tokenId => bytes) private _tokenMetadataAdditional;
/// @notice The address of the wrapped ERC20 token for each token
mapping(uint256 tokenId => address) internal _wrappedTokens;
constructor(address erc20Implementation_) {
// Validate that the ERC20 implementation implements the required interface
if (
!IERC165(erc20Implementation_).supportsInterface(
type(IERC20BurnableMintable).interfaceId
)
) revert ERC6909Wrappable_InvalidERC20Implementation(erc20Implementation_);
_ERC20_IMPLEMENTATION = erc20Implementation_;
}
/// @notice Returns the clone initialisation data for a given token ID
///
/// @param tokenId_ The token ID
/// @return tokenData Packed bytes including the name, symbol, decimals and additional metadata
function _getTokenData(uint256 tokenId_) internal view returns (bytes memory tokenData) {
bytes memory additionalMetadata = _tokenMetadataAdditional[tokenId_];
return
abi.encodePacked(
bytes32(bytes(name(tokenId_))),
bytes32(bytes(symbol(tokenId_))),
decimals(tokenId_),
additionalMetadata
);
}
/// @notice Returns the additional metadata for a token ID
///
/// @param tokenId_ The token ID
/// @return additionalData The additional metadata bytes
function _getTokenAdditionalData(
uint256 tokenId_
) internal view returns (bytes memory additionalData) {
return _tokenMetadataAdditional[tokenId_];
}
// ========== MINT/BURN FUNCTIONS ========== //
/// @notice Mints the ERC6909 or ERC20 wrapped token to the recipient
///
/// @param onBehalfOf_ The address to mint the token to
/// @param tokenId_ The ID of the ERC6909 token
/// @param amount_ The amount of tokens to mint
/// @param shouldWrap_ Whether to wrap the token to an ERC20 token
function _mint(
address onBehalfOf_,
uint256 tokenId_,
uint256 amount_,
bool shouldWrap_
) internal onlyValidTokenId(tokenId_) {
if (amount_ == 0) revert ERC6909Wrappable_ZeroAmount();
if (onBehalfOf_ == address(0)) revert ERC6909InvalidReceiver(onBehalfOf_);
if (shouldWrap_) {
_getWrappedToken(tokenId_).mintFor(onBehalfOf_, amount_);
} else {
_mint(onBehalfOf_, tokenId_, amount_);
}
}
/// @notice Burns the ERC6909 or ERC20 wrapped token from the recipient
/// @dev This function reverts if:
/// - amount_ is 0
/// - onBehalfOf_ is 0
/// - onBehalfOf_ is not the caller and has not approved the caller to spend the ERC6909 tokens (note: ERC6909 allowances govern both wrapped and unwrapped token burns)
/// - ERC6909 token handling reverts
///
/// @param onBehalfOf_ The address to burn the token from
/// @param tokenId_ The ID of the ERC6909 token
/// @param amount_ The amount of tokens to burn
/// @param wrapped_ Whether the token is wrapped
function _burn(
address onBehalfOf_,
uint256 tokenId_,
uint256 amount_,
bool wrapped_
) internal onlyValidTokenId(tokenId_) {
if (amount_ == 0) revert ERC6909Wrappable_ZeroAmount();
if (onBehalfOf_ == address(0)) revert ERC6909InvalidSender(onBehalfOf_);
// If the caller is not the owner, check allowance
if (onBehalfOf_ != msg.sender) {
// Spend allowance (since it is not implemented in `ERC6909._burn()` or `CloneableReceiptToken.burnFrom()`)
// The caller is the spender, not this contract
_spendAllowance(onBehalfOf_, msg.sender, tokenId_, amount_);
}
if (wrapped_) {
// Burn the ERC20 token
_getWrappedToken(tokenId_).burnFrom(onBehalfOf_, amount_);
} else {
// Burn the ERC6909 token
_burn(onBehalfOf_, tokenId_, amount_);
}
}
// ========== TOTAL SUPPLY EXTENSION ========== //
/// @inheritdoc IERC6909TokenSupply
function totalSupply(uint256 tokenId_) public view virtual override returns (uint256) {
return _totalSupplies[tokenId_];
}
/// @dev Copied from draft-ERC6909TokenSupply.sol
function _update(
address from,
address to,
uint256 id,
uint256 amount
) internal virtual override {
// Calls ERC6909Metadata._update()
super._update(from, to, id, amount);
if (from == address(0)) {
_totalSupplies[id] += amount;
}
if (to == address(0)) {
unchecked {
// amount <= _balances[from][id] <= _totalSupplies[id]
_totalSupplies[id] -= amount;
}
}
}
// ========== WRAP/UNWRAP FUNCTIONS ========== //
/// @dev Returns the address of the wrapped ERC20 token for a given token ID, or creates a new one if it does not exist
function _getWrappedToken(
uint256 tokenId_
) internal returns (IERC20BurnableMintable wrappedToken) {
// If the wrapped token exists, return it
if (_wrappedTokens[tokenId_] != address(0))
return IERC20BurnableMintable(_wrappedTokens[tokenId_]);
// Validate that the token id exists
bytes memory tokenData = _getTokenData(tokenId_);
if (tokenData.length == 0) revert ERC6909Wrappable_InvalidTokenId(tokenId_);
// Otherwise, create a new wrapped token
wrappedToken = IERC20BurnableMintable(_ERC20_IMPLEMENTATION.clone(tokenData));
_wrappedTokens[tokenId_] = address(wrappedToken);
return wrappedToken;
}
/// @inheritdoc IERC6909Wrappable
function getWrappedToken(uint256 tokenId_) public view returns (address wrappedToken) {
return _wrappedTokens[tokenId_];
}
/// @inheritdoc IERC6909Wrappable
/// @dev This function will burn the ERC6909 token from the caller and mint the wrapped ERC20 token to the same address.
///
/// This function reverts if:
/// - The token ID does not exist
/// - The amount is zero
/// - The caller has an insufficient balance of the token
function wrap(uint256 tokenId_, uint256 amount_) public returns (address wrappedToken) {
// Burn the ERC6909 token
_burn(msg.sender, tokenId_, amount_, false);
// Mint the wrapped ERC20 token to the recipient
IERC20BurnableMintable wrappedToken_ = _getWrappedToken(tokenId_);
wrappedToken_.mintFor(msg.sender, amount_);
// Emit the Wrapped event
emit Wrapped(tokenId_, address(wrappedToken_), msg.sender, amount_);
return address(wrappedToken_);
}
/// @inheritdoc IERC6909Wrappable
/// @dev This function will burn the wrapped ERC20 token from the caller and mint the ERC6909 token to the same address.
///
/// This function reverts if:
/// - The token ID does not exist
/// - The amount is zero
/// - The caller has an insufficient balance of the wrapped token
function unwrap(uint256 tokenId_, uint256 amount_) public {
// Burn the wrapped ERC20 token
_burn(msg.sender, tokenId_, amount_, true);
// Mint the ERC6909 token
_mint(msg.sender, tokenId_, amount_);
// Emit the Unwrapped event
emit Unwrapped(tokenId_, _wrappedTokens[tokenId_], msg.sender, amount_);
}
// ========== TOKEN FUNCTIONS ========== //
/// @inheritdoc IERC6909Wrappable
function isValidTokenId(uint256 tokenId_) public view returns (bool) {
return _wrappableTokenIds.contains(tokenId_);
}
function _onlyValidTokenId(uint256 tokenId_) internal view {
if (!isValidTokenId(tokenId_)) revert ERC6909Wrappable_InvalidTokenId(tokenId_);
}
modifier onlyValidTokenId(uint256 tokenId_) {
_onlyValidTokenId(tokenId_);
_;
}
/// @notice Creates a new wrappable token
/// @dev Reverts if the token ID already exists
function _createWrappableToken(
uint256 tokenId_,
string memory name_,
string memory symbol_,
uint8 decimals_,
bytes memory additionalMetadata_,
bool createWrappedToken_
) internal {
// If the token ID already exists, revert
if (_wrappableTokenIds.contains(tokenId_))
revert ERC6909Wrappable_TokenIdAlreadyExists(tokenId_);
_setName(tokenId_, name_);
_setSymbol(tokenId_, symbol_);
_setDecimals(tokenId_, decimals_);
_tokenMetadataAdditional[tokenId_] = additionalMetadata_;
if (createWrappedToken_) {
_getWrappedToken(tokenId_);
}
// Record the token ID
_wrappableTokenIds.add(tokenId_);
}
/// @inheritdoc IERC6909Wrappable
function getWrappableTokens()
public
view
override
returns (uint256[] memory tokenIds, address[] memory wrappedTokens)
{
tokenIds = _wrappableTokenIds.values();
wrappedTokens = new address[](tokenIds.length);
for (uint256 i; i < tokenIds.length; ++i) {
wrappedTokens[i] = _wrappedTokens[tokenIds[i]];
}
return (tokenIds, wrappedTokens);
}
// ========== ERC165 ========== //
function supportsInterface(
bytes4 interfaceId_
) public view virtual override(ERC6909, IERC165) returns (bool) {
return
interfaceId_ == type(IERC165).interfaceId ||
interfaceId_ == type(IERC6909Wrappable).interfaceId ||
interfaceId_ == type(IERC6909Metadata).interfaceId ||
interfaceId_ == type(IERC6909TokenSupply).interfaceId ||
super.supportsInterface(interfaceId_);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.15;
// Interfaces
import {IERC20} from "src/interfaces/IERC20.sol";
import {IERC20BurnableMintable} from "src/interfaces/IERC20BurnableMintable.sol";
import {IDepositReceiptToken} from "src/interfaces/IDepositReceiptToken.sol";
import {IERC165} from "@openzeppelin-5.3.0/interfaces/IERC165.sol";
// Libraries
import {CloneERC20} from "src/external/clones/CloneERC20.sol";
/// @title CloneableReceiptToken
/// @notice ERC20 implementation that is deployed as a clone
/// with immutable arguments for each supported input token.
contract CloneableReceiptToken is CloneERC20, IERC20BurnableMintable, IDepositReceiptToken {
// ========== IMMUTABLE ARGS ========== //
// Storage layout:
// 0x00 - name, 32 bytes
// 0x20 - symbol, 32 bytes
// 0x40 - decimals, 1 byte
// 0x41 - owner, 20 bytes
// 0x55 - asset, 20 bytes
// 0x69 - depositPeriod, 1 byte
// 0x6A - operator, 20 bytes
/// @notice The owner of the clone
/// @return _owner The owner address stored in immutable args
function owner() public pure returns (address _owner) {
_owner = _getArgAddress(0x41);
}
/// @notice The underlying asset
/// @return _asset The asset address stored in immutable args
function asset() public pure returns (IERC20 _asset) {
_asset = IERC20(_getArgAddress(0x55));
}
/// @notice The deposit period (in months)
/// @return _depositPeriod The deposit period stored in immutable args
function depositPeriod() public pure returns (uint8 _depositPeriod) {
_depositPeriod = _getArgUint8(0x69);
}
/// @notice The operator that issued the receipt token
/// @return _operator The operator address stored in immutable args
function operator() public pure returns (address _operator) {
_operator = _getArgAddress(0x6A);
}
// ========== OWNER-ONLY FUNCTIONS ========== //
function _onlyOwner() internal view {
if (msg.sender != owner()) revert OnlyOwner();
}
/// @notice Only the owner can call this function
modifier onlyOwner() {
_onlyOwner();
_;
}
/// @notice Mint tokens to the specified address
/// @dev This is owner-only, as the underlying token is custodied by the owner.
/// Minting should be performed through the owner contract.
///
/// @param to_ The address to mint tokens to
/// @param amount_ The amount of tokens to mint
function mintFor(address to_, uint256 amount_) external onlyOwner {
_mint(to_, amount_);
}
/// @notice Burn tokens from the specified address
/// @dev This is gated to the owner, as burning is controlled.
/// Burning should be performed through the owner contract.
/// The owner is expected to handle spending approval before calling this function.
/// This function does NOT check or update allowances.
///
/// @param from_ The address to burn tokens from
/// @param amount_ The amount of tokens to burn
function burnFrom(address from_, uint256 amount_) external onlyOwner {
_burn(from_, amount_);
}
// ========== ERC165 ========== //
function supportsInterface(bytes4 interfaceId_) public pure returns (bool) {
// super does not implement ERC165, so no need to call it
return
interfaceId_ == type(IERC165).interfaceId ||
interfaceId_ == type(IERC20).interfaceId ||
interfaceId_ == type(IERC20BurnableMintable).interfaceId ||
interfaceId_ == type(IDepositReceiptToken).interfaceId;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8;
// Some fancy math to convert a uint into a string, courtesy of Provable Things.
// Updated to work with solc 0.8.0.
// https://github.com/provable-things/ethereum-api/blob/master/provableAPI_0.6.sol
function uint2str(uint256 _i) pure returns (string memory) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (_i != 0) {
k = k - 1;
bstr[k] = bytes1(uint8(48 + (_i % 10)));
_i /= 10;
}
return string(bstr);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.15;
library String {
error EndBeforeStartIndex(uint256 startIndex, uint256 endIndex);
error EndIndexOutOfBounds(uint256 endIndex, uint256 length);
/// @notice Truncates a string to 32 bytes
function truncate32(string memory str_) internal pure returns (string memory) {
return string(abi.encodePacked(bytes32(abi.encodePacked(str_))));
}
/// @notice Returns a substring of a string
///
/// @param str_ The string to get the substring of
/// @param startIndex_ The index to start the substring at
/// @param endIndex_ The index to end the substring at
/// @return resultString The substring
function substring(
string memory str_,
uint256 startIndex_,
uint256 endIndex_
) internal pure returns (string memory) {
bytes memory strBytes = bytes(str_);
if (endIndex_ < startIndex_) revert EndBeforeStartIndex(startIndex_, endIndex_);
if (endIndex_ > strBytes.length) revert EndIndexOutOfBounds(endIndex_, strBytes.length);
bytes memory result = new bytes(endIndex_ - startIndex_);
for (uint256 i = startIndex_; i < endIndex_; i++) {
result[i - startIndex_] = strBytes[i];
}
return string(result);
}
/// @notice Returns a substring of a string from a given index
///
/// @param str_ The string to get the substring of
/// @param startIndex_ The index to start the substring at
/// @return resultString The substring
function substringFrom(
string memory str_,
uint256 startIndex_
) internal pure returns (string memory) {
return substring(str_, startIndex_, bytes(str_).length);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.15;
import {IERC20} from "src/interfaces/IERC20.sol";
/// @title IDepositReceiptToken
/// @notice Interface for a deposit receipt token
/// @dev This interface adds additional metadata to the IERC20 interface that is necessary for deposit receipt tokens.
interface IDepositReceiptToken is IERC20 {
// ========== ERRORS ========== //
error OnlyOwner();
// ========== VIEW FUNCTIONS ========== //
function owner() external view returns (address _owner);
function asset() external view returns (IERC20 _asset);
function depositPeriod() external view returns (uint8 _depositPeriod);
function operator() external view returns (address _operator);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/draft-IERC6909.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-6909 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-6909[ERC].
*/
interface IERC6909 is IERC165 {
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`.
* The new allowance is `amount`.
*/
event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount);
/**
* @dev Emitted when `owner` grants or revokes operator status for a `spender`.
*/
event OperatorSet(address indexed owner, address indexed spender, bool approved);
/**
* @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`.
*/
event Transfer(
address caller,
address indexed sender,
address indexed receiver,
uint256 indexed id,
uint256 amount
);
/**
* @dev Returns the amount of tokens of type `id` owned by `owner`.
*/
function balanceOf(address owner, uint256 id) external view returns (uint256);
/**
* @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`.
*
* NOTE: Does not include operator allowances.
*/
function allowance(address owner, address spender, uint256 id) external view returns (uint256);
/**
* @dev Returns true if `spender` is set as an operator for `owner`.
*/
function isOperator(address owner, address spender) external view returns (bool);
/**
* @dev Sets an approval to `spender` for `amount` of tokens of type `id` from the caller's tokens. An `amount` of
* `type(uint256).max` signifies an unlimited approval.
*
* Must return true.
*/
function approve(address spender, uint256 id, uint256 amount) external returns (bool);
/**
* @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens.
*
* Must return true.
*/
function setOperator(address spender, bool approved) external returns (bool);
/**
* @dev Transfers `amount` of token type `id` from the caller's account to `receiver`.
*
* Must return true.
*/
function transfer(address receiver, uint256 id, uint256 amount) external returns (bool);
/**
* @dev Transfers `amount` of token type `id` from `sender` to `receiver`.
*
* Must return true.
*/
function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool);
}
/**
* @dev Optional extension of {IERC6909} that adds metadata functions.
*/
interface IERC6909Metadata is IERC6909 {
/**
* @dev Returns the name of the token of type `id`.
*/
function name(uint256 id) external view returns (string memory);
/**
* @dev Returns the ticker symbol of the token of type `id`.
*/
function symbol(uint256 id) external view returns (string memory);
/**
* @dev Returns the number of decimals for the token of type `id`.
*/
function decimals(uint256 id) external view returns (uint8);
}
/**
* @dev Optional extension of {IERC6909} that adds content URI functions.
*/
interface IERC6909ContentURI is IERC6909 {
/**
* @dev Returns URI for the contract.
*/
function contractURI() external view returns (string memory);
/**
* @dev Returns the URI for the token of type `id`.
*/
function tokenURI(uint256 id) external view returns (string memory);
}
/**
* @dev Optional extension of {IERC6909} that adds a token supply function.
*/
interface IERC6909TokenSupply is IERC6909 {
/**
* @dev Returns the total supply of the token of type `id`.
*/
function totalSupply(uint256 id) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title IERC6909Wrappable
/// @notice Declares interface for an ERC6909 implementation that allows for wrapping and unwrapping ERC6909 tokens to and from ERC20 tokens
interface IERC6909Wrappable {
// ========== EVENTS ========== //
event Wrapped(
uint256 indexed tokenId,
address indexed wrappedToken,
address indexed account,
uint256 amount
);
event Unwrapped(
uint256 indexed tokenId,
address indexed wrappedToken,
address indexed account,
uint256 amount
);
// ========== ERRORS ========== //
error ERC6909Wrappable_TokenIdAlreadyExists(uint256 tokenId);
error ERC6909Wrappable_InvalidTokenId(uint256 tokenId);
error ERC6909Wrappable_InvalidERC20Implementation(address erc20Implementation);
error ERC6909Wrappable_ZeroAmount();
// ========== WRAP/UNWRAP FUNCTIONS ========== //
/// @notice Wraps an ERC6909 token to an ERC20 token
///
/// @param tokenId_ The ID of the ERC6909 token
/// @param amount_ The amount of tokens to wrap
/// @return wrappedToken The address of the wrapped ERC20 token
function wrap(uint256 tokenId_, uint256 amount_) external returns (address wrappedToken);
/// @notice Unwraps an ERC20 token to an ERC6909 token
///
/// @param tokenId_ The ID of the ERC6909 token
/// @param amount_ The amount of tokens to unwrap
function unwrap(uint256 tokenId_, uint256 amount_) external;
/// @notice Returns the address of the wrapped ERC20 token for a given token ID
///
/// @param tokenId_ The ID of the ERC6909 token
/// @return wrappedToken The address of the wrapped ERC20 token (or zero address)
function getWrappedToken(uint256 tokenId_) external view returns (address wrappedToken);
// ========== TOKEN FUNCTIONS ========== //
/// @notice Returns whether a token ID is valid
///
/// @param tokenId_ The ID of the ERC6909 token
/// @return isValid Whether the token ID is valid
function isValidTokenId(uint256 tokenId_) external view returns (bool isValid);
/// @notice Returns the token IDs and wrapped token addresses of all tokens
///
/// @return tokenIds The IDs of all tokens
/// @return wrappedTokens The wrapped token addresses of all tokens
function getWrappableTokens()
external
view
returns (uint256[] memory tokenIds, address[] memory wrappedTokens);
}// 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.15;
import {IERC20} from "src/interfaces/IERC20.sol";
interface IERC20BurnableMintable is IERC20 {
/// @notice Mints tokens to the specified address
///
/// @param to_ The address to mint tokens to
/// @param amount_ The amount of tokens to mint
function mintFor(address to_, uint256 amount_) external;
/// @notice Burns tokens from the specified address
///
/// @param from_ The address to burn tokens from
/// @param amount_ The amount of tokens to burn
function burnFrom(address from_, uint256 amount_) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/draft-ERC6909.sol)
pragma solidity ^0.8.20;
import {IERC6909} from "../../interfaces/draft-IERC6909.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of ERC-6909.
* See https://eips.ethereum.org/EIPS/eip-6909
*/
contract ERC6909 is Context, ERC165, IERC6909 {
mapping(address owner => mapping(uint256 id => uint256)) private _balances;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
mapping(address owner => mapping(address spender => mapping(uint256 id => uint256))) private _allowances;
error ERC6909InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 id);
error ERC6909InsufficientAllowance(address spender, uint256 allowance, uint256 needed, uint256 id);
error ERC6909InvalidApprover(address approver);
error ERC6909InvalidReceiver(address receiver);
error ERC6909InvalidSender(address sender);
error ERC6909InvalidSpender(address spender);
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC6909).interfaceId || super.supportsInterface(interfaceId);
}
/// @inheritdoc IERC6909
function balanceOf(address owner, uint256 id) public view virtual override returns (uint256) {
return _balances[owner][id];
}
/// @inheritdoc IERC6909
function allowance(address owner, address spender, uint256 id) public view virtual override returns (uint256) {
return _allowances[owner][spender][id];
}
/// @inheritdoc IERC6909
function isOperator(address owner, address spender) public view virtual override returns (bool) {
return _operatorApprovals[owner][spender];
}
/// @inheritdoc IERC6909
function approve(address spender, uint256 id, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, id, amount);
return true;
}
/// @inheritdoc IERC6909
function setOperator(address spender, bool approved) public virtual override returns (bool) {
_setOperator(_msgSender(), spender, approved);
return true;
}
/// @inheritdoc IERC6909
function transfer(address receiver, uint256 id, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), receiver, id, amount);
return true;
}
/// @inheritdoc IERC6909
function transferFrom(
address sender,
address receiver,
uint256 id,
uint256 amount
) public virtual override returns (bool) {
address caller = _msgSender();
if (sender != caller && !isOperator(sender, caller)) {
_spendAllowance(sender, caller, id, amount);
}
_transfer(sender, receiver, id, amount);
return true;
}
/**
* @dev Creates `amount` of token `id` and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address to, uint256 id, uint256 amount) internal {
if (to == address(0)) {
revert ERC6909InvalidReceiver(address(0));
}
_update(address(0), to, id, amount);
}
/**
* @dev Moves `amount` of token `id` from `from` to `to` without checking for approvals. This function verifies
* that neither the sender nor the receiver are address(0), which means it cannot mint or burn tokens.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 id, uint256 amount) internal {
if (from == address(0)) {
revert ERC6909InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC6909InvalidReceiver(address(0));
}
_update(from, to, id, amount);
}
/**
* @dev Destroys a `amount` of token `id` from `account`.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address from, uint256 id, uint256 amount) internal {
if (from == address(0)) {
revert ERC6909InvalidSender(address(0));
}
_update(from, address(0), id, amount);
}
/**
* @dev Transfers `amount` of token `id` from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 id, uint256 amount) internal virtual {
address caller = _msgSender();
if (from != address(0)) {
uint256 fromBalance = _balances[from][id];
if (fromBalance < amount) {
revert ERC6909InsufficientBalance(from, fromBalance, amount, id);
}
unchecked {
// Overflow not possible: amount <= fromBalance.
_balances[from][id] = fromBalance - amount;
}
}
if (to != address(0)) {
_balances[to][id] += amount;
}
emit Transfer(caller, from, to, id, amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`'s `id` tokens.
*
* This internal function is equivalent to `approve`, and can be used to e.g. set automatic allowances for certain
* subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 id, uint256 amount) internal virtual {
if (owner == address(0)) {
revert ERC6909InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC6909InvalidSpender(address(0));
}
_allowances[owner][spender][id] = amount;
emit Approval(owner, spender, id, amount);
}
/**
* @dev Approve `spender` to operate on all of `owner`'s tokens
*
* This internal function is equivalent to `setOperator`, and can be used to e.g. set automatic allowances for
* certain subsystems, etc.
*
* Emits an {OperatorSet} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _setOperator(address owner, address spender, bool approved) internal virtual {
if (owner == address(0)) {
revert ERC6909InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC6909InvalidSpender(address(0));
}
_operatorApprovals[owner][spender] = approved;
emit OperatorSet(owner, spender, approved);
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 id, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender, id);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < amount) {
revert ERC6909InsufficientAllowance(spender, currentAllowance, amount, id);
}
unchecked {
_allowances[owner][spender][id] = currentAllowance - amount;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC6909/extensions/draft-ERC6909Metadata.sol)
pragma solidity ^0.8.20;
import {ERC6909} from "../draft-ERC6909.sol";
import {IERC6909Metadata} from "../../../interfaces/draft-IERC6909.sol";
/**
* @dev Implementation of the Metadata extension defined in ERC6909. Exposes the name, symbol, and decimals of each token id.
*/
contract ERC6909Metadata is ERC6909, IERC6909Metadata {
struct TokenMetadata {
string name;
string symbol;
uint8 decimals;
}
mapping(uint256 id => TokenMetadata) private _tokenMetadata;
/// @dev The name of the token of type `id` was updated to `newName`.
event ERC6909NameUpdated(uint256 indexed id, string newName);
/// @dev The symbol for the token of type `id` was updated to `newSymbol`.
event ERC6909SymbolUpdated(uint256 indexed id, string newSymbol);
/// @dev The decimals value for token of type `id` was updated to `newDecimals`.
event ERC6909DecimalsUpdated(uint256 indexed id, uint8 newDecimals);
/// @inheritdoc IERC6909Metadata
function name(uint256 id) public view virtual override returns (string memory) {
return _tokenMetadata[id].name;
}
/// @inheritdoc IERC6909Metadata
function symbol(uint256 id) public view virtual override returns (string memory) {
return _tokenMetadata[id].symbol;
}
/// @inheritdoc IERC6909Metadata
function decimals(uint256 id) public view virtual override returns (uint8) {
return _tokenMetadata[id].decimals;
}
/**
* @dev Sets the `name` for a given token of type `id`.
*
* Emits an {ERC6909NameUpdated} event.
*/
function _setName(uint256 id, string memory newName) internal virtual {
_tokenMetadata[id].name = newName;
emit ERC6909NameUpdated(id, newName);
}
/**
* @dev Sets the `symbol` for a given token of type `id`.
*
* Emits an {ERC6909SymbolUpdated} event.
*/
function _setSymbol(uint256 id, string memory newSymbol) internal virtual {
_tokenMetadata[id].symbol = newSymbol;
emit ERC6909SymbolUpdated(id, newSymbol);
}
/**
* @dev Sets the `decimals` for a given token of type `id`.
*
* Emits an {ERC6909DecimalsUpdated} event.
*/
function _setDecimals(uint256 id, uint8 newDecimals) internal virtual {
_tokenMetadata[id].decimals = newDecimals;
emit ERC6909DecimalsUpdated(id, newDecimals);
}
}// SPDX-License-Identifier: BSD
pragma solidity ^0.8.4;
/// @title ClonesWithImmutableArgs
/// @author wighawag, zefram.eth, nick.eth
/// @notice Enables creating clone contracts with immutable args
library ClonesWithImmutableArgs {
/// @dev The CREATE3 proxy bytecode.
uint256 private constant _CREATE3_PROXY_BYTECODE =
0x67363d3d37363d34f03d5260086018f3;
/// @dev Hash of the `_CREATE3_PROXY_BYTECODE`.
/// Equivalent to `keccak256(abi.encodePacked(hex"67363d3d37363d34f03d5260086018f3"))`.
bytes32 private constant _CREATE3_PROXY_BYTECODE_HASH =
0x21c35dbe1b344a2488cf3321d6ce542f8e9f305544ff09e4993a62319a497c1f;
error CreateFail();
error InitializeFail();
enum CloneType {
CREATE,
CREATE2,
PREDICT_CREATE2
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @return instance The address of the created clone
function clone(
address implementation,
bytes memory data
) internal returns (address payable instance) {
return clone(implementation, data, 0);
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @param value The amount of wei to transfer to the created clone
/// @return instance The address of the created clone
function clone(
address implementation,
bytes memory data,
uint256 value
) internal returns (address payable instance) {
bytes memory creationcode = getCreationBytecode(implementation, data);
// solhint-disable-next-line no-inline-assembly
assembly {
instance := create(
value,
add(creationcode, 0x20),
mload(creationcode)
)
}
if (instance == address(0)) {
revert CreateFail();
}
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args,
/// using CREATE2
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @return instance The address of the created clone
function clone2(
address implementation,
bytes memory data
) internal returns (address payable instance) {
return clone2(implementation, data, 0);
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args,
/// using CREATE2
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @param value The amount of wei to transfer to the created clone
/// @return instance The address of the created clone
function clone2(
address implementation,
bytes memory data,
uint256 value
) internal returns (address payable instance) {
bytes memory creationcode = getCreationBytecode(implementation, data);
// solhint-disable-next-line no-inline-assembly
assembly {
instance := create2(
value,
add(creationcode, 0x20),
mload(creationcode),
0
)
}
if (instance == address(0)) {
revert CreateFail();
}
}
/// @notice Computes the address of a clone created using CREATE2
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @return instance The address of the clone
function addressOfClone2(
address implementation,
bytes memory data
) internal view returns (address payable instance) {
bytes memory creationcode = getCreationBytecode(implementation, data);
bytes32 bytecodeHash = keccak256(creationcode);
instance = payable(
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
bytes1(0xff),
address(this),
bytes32(0),
bytecodeHash
)
)
)
)
)
);
}
/// @notice Computes bytecode for a clone
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @return ret Creation bytecode for the clone contract
function getCreationBytecode(
address implementation,
bytes memory data
) internal pure returns (bytes memory ret) {
// unrealistic for memory ptr or data length to exceed 256 bits
unchecked {
uint256 extraLength = data.length + 2; // +2 bytes for telling how much data there is appended to the call
uint256 creationSize = 0x41 + extraLength;
uint256 runSize = creationSize - 10;
uint256 dataPtr;
uint256 ptr;
// solhint-disable-next-line no-inline-assembly
assembly {
ret := mload(0x40)
mstore(ret, creationSize)
mstore(0x40, add(ret, creationSize))
ptr := add(ret, 0x20)
// -------------------------------------------------------------------------------------------------------------
// CREATION (10 bytes)
// -------------------------------------------------------------------------------------------------------------
// 61 runtime | PUSH2 runtime (r) | r | –
mstore(
ptr,
0x6100000000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x01), shl(240, runSize)) // size of the contract running bytecode (16 bits)
// creation size = 0a
// 3d | RETURNDATASIZE | 0 r | –
// 81 | DUP2 | r 0 r | –
// 60 creation | PUSH1 creation (c) | c r 0 r | –
// 3d | RETURNDATASIZE | 0 c r 0 r | –
// 39 | CODECOPY | 0 r | [0-runSize): runtime code
// f3 | RETURN | | [0-runSize): runtime code
// -------------------------------------------------------------------------------------------------------------
// RUNTIME (55 bytes + extraLength)
// -------------------------------------------------------------------------------------------------------------
// 3d | RETURNDATASIZE | 0 | –
// 3d | RETURNDATASIZE | 0 0 | –
// 3d | RETURNDATASIZE | 0 0 0 | –
// 3d | RETURNDATASIZE | 0 0 0 0 | –
// 36 | CALLDATASIZE | cds 0 0 0 0 | –
// 3d | RETURNDATASIZE | 0 cds 0 0 0 0 | –
// 3d | RETURNDATASIZE | 0 0 cds 0 0 0 0 | –
// 37 | CALLDATACOPY | 0 0 0 0 | [0, cds) = calldata
// 61 | PUSH2 extra | extra 0 0 0 0 | [0, cds) = calldata
mstore(
add(ptr, 0x03),
0x3d81600a3d39f33d3d3d3d363d3d376100000000000000000000000000000000
)
mstore(add(ptr, 0x13), shl(240, extraLength))
// 60 0x37 | PUSH1 0x37 | 0x37 extra 0 0 0 0 | [0, cds) = calldata // 0x37 (55) is runtime size - data
// 36 | CALLDATASIZE | cds 0x37 extra 0 0 0 0 | [0, cds) = calldata
// 39 | CODECOPY | 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 36 | CALLDATASIZE | cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 61 extra | PUSH2 extra | extra cds 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
mstore(
add(ptr, 0x15),
0x6037363936610000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x1b), shl(240, extraLength))
// 01 | ADD | cds+extra 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 3d | RETURNDATASIZE | 0 cds+extra 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 73 addr | PUSH20 0x123… | addr 0 cds+extra 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
mstore(
add(ptr, 0x1d),
0x013d730000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x20), shl(0x60, implementation))
// 5a | GAS | gas addr 0 cds+extra 0 0 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// f4 | DELEGATECALL | success 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 3d | RETURNDATASIZE | rds success 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 3d | RETURNDATASIZE | rds rds success 0 0 | [0, cds) = calldata, [cds, cds+extra) = extraData
// 93 | SWAP4 | 0 rds success 0 rds | [0, cds) = calldata, [cds, cds+extra) = extraData
// 80 | DUP1 | 0 0 rds success 0 rds | [0, cds) = calldata, [cds, cds+extra) = extraData
// 3e | RETURNDATACOPY | success 0 rds | [0, rds) = return data (there might be some irrelevant leftovers in memory [rds, cds+0x37) when rds < cds+0x37)
// 60 0x35 | PUSH1 0x35 | 0x35 sucess 0 rds | [0, rds) = return data
// 57 | JUMPI | 0 rds | [0, rds) = return data
// fd | REVERT | – | [0, rds) = return data
// 5b | JUMPDEST | 0 rds | [0, rds) = return data
// f3 | RETURN | – | [0, rds) = return data
mstore(
add(ptr, 0x34),
0x5af43d3d93803e603557fd5bf300000000000000000000000000000000000000
)
}
// -------------------------------------------------------------------------------------------------------------
// APPENDED DATA (Accessible from extcodecopy)
// (but also send as appended data to the delegatecall)
// -------------------------------------------------------------------------------------------------------------
extraLength -= 2;
uint256 counter = extraLength;
uint256 copyPtr = ptr + 0x41;
// solhint-disable-next-line no-inline-assembly
assembly {
dataPtr := add(data, 32)
}
for (; counter >= 32; counter -= 32) {
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, mload(dataPtr))
}
copyPtr += 32;
dataPtr += 32;
}
uint256 mask = ~(256 ** (32 - counter) - 1);
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, and(mload(dataPtr), mask))
}
copyPtr += counter;
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, shl(240, extraLength))
}
}
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args. Uses CREATE3
/// to implement deterministic deployment.
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @param salt The salt used by the CREATE3 deployment
/// @return deployed The address of the created clone
function clone3(
address implementation,
bytes memory data,
bytes32 salt
) internal returns (address deployed) {
return clone3(implementation, data, salt, 0);
}
/// @notice Creates a clone proxy of the implementation contract, with immutable args. Uses CREATE3
/// to implement deterministic deployment.
/// @dev data cannot exceed 65535 bytes, since 2 bytes are used to store the data length
/// @param implementation The implementation contract to clone
/// @param data Encoded immutable args
/// @param salt The salt used by the CREATE3 deployment
/// @param value The amount of wei to transfer to the created clone
/// @return deployed The address of the created clone
function clone3(
address implementation,
bytes memory data,
bytes32 salt,
uint256 value
) internal returns (address deployed) {
// unrealistic for memory ptr or data length to exceed 256 bits
unchecked {
uint256 extraLength = data.length + 2; // +2 bytes for telling how much data there is appended to the call
uint256 creationSize = 0x43 + extraLength;
uint256 ptr;
// solhint-disable-next-line no-inline-assembly
assembly {
ptr := mload(0x40)
// -------------------------------------------------------------------------------------------------------------
// CREATION (11 bytes)
// -------------------------------------------------------------------------------------------------------------
// 3d | RETURNDATASIZE | 0 | –
// 61 runtime | PUSH2 runtime (r) | r 0 | –
mstore(
ptr,
0x3d61000000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x02), shl(240, sub(creationSize, 11))) // size of the contract running bytecode (16 bits)
// creation size = 0b
// 80 | DUP1 | r r 0 | –
// 60 creation | PUSH1 creation (c) | c r r 0 | –
// 3d | RETURNDATASIZE | 0 c r r 0 | –
// 39 | CODECOPY | r 0 | [0-2d]: runtime code
// 81 | DUP2 | 0 c 0 | [0-2d]: runtime code
// f3 | RETURN | 0 | [0-2d]: runtime code
mstore(
add(ptr, 0x04),
0x80600b3d3981f300000000000000000000000000000000000000000000000000
)
// -------------------------------------------------------------------------------------------------------------
// RUNTIME
// -------------------------------------------------------------------------------------------------------------
// 36 | CALLDATASIZE | cds | –
// 3d | RETURNDATASIZE | 0 cds | –
// 3d | RETURNDATASIZE | 0 0 cds | –
// 37 | CALLDATACOPY | – | [0, cds] = calldata
// 61 | PUSH2 extra | extra | [0, cds] = calldata
mstore(
add(ptr, 0x0b),
0x363d3d3761000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x10), shl(240, extraLength))
// 60 0x38 | PUSH1 0x38 | 0x38 extra | [0, cds] = calldata // 0x38 (56) is runtime size - data
// 36 | CALLDATASIZE | cds 0x38 extra | [0, cds] = calldata
// 39 | CODECOPY | _ | [0, cds] = calldata
// 3d | RETURNDATASIZE | 0 | [0, cds] = calldata
// 3d | RETURNDATASIZE | 0 0 | [0, cds] = calldata
// 3d | RETURNDATASIZE | 0 0 0 | [0, cds] = calldata
// 36 | CALLDATASIZE | cds 0 0 0 | [0, cds] = calldata
// 61 extra | PUSH2 extra | extra cds 0 0 0 | [0, cds] = calldata
mstore(
add(ptr, 0x12),
0x603836393d3d3d36610000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x1b), shl(240, extraLength))
// 01 | ADD | cds+extra 0 0 0 | [0, cds] = calldata
// 3d | RETURNDATASIZE | 0 cds 0 0 0 | [0, cds] = calldata
// 73 addr | PUSH20 0x123… | addr 0 cds 0 0 0 | [0, cds] = calldata
mstore(
add(ptr, 0x1d),
0x013d730000000000000000000000000000000000000000000000000000000000
)
mstore(add(ptr, 0x20), shl(0x60, implementation))
// 5a | GAS | gas addr 0 cds 0 0 0 | [0, cds] = calldata
// f4 | DELEGATECALL | success 0 | [0, cds] = calldata
// 3d | RETURNDATASIZE | rds success 0 | [0, cds] = calldata
// 82 | DUP3 | 0 rds success 0 | [0, cds] = calldata
// 80 | DUP1 | 0 0 rds success 0 | [0, cds] = calldata
// 3e | RETURNDATACOPY | success 0 | [0, rds] = return data (there might be some irrelevant leftovers in memory [rds, cds] when rds < cds)
// 90 | SWAP1 | 0 success | [0, rds] = return data
// 3d | RETURNDATASIZE | rds 0 success | [0, rds] = return data
// 91 | SWAP2 | success 0 rds | [0, rds] = return data
// 60 0x36 | PUSH1 0x36 | 0x36 sucess 0 rds | [0, rds] = return data
// 57 | JUMPI | 0 rds | [0, rds] = return data
// fd | REVERT | – | [0, rds] = return data
// 5b | JUMPDEST | 0 rds | [0, rds] = return data
// f3 | RETURN | – | [0, rds] = return data
mstore(
add(ptr, 0x34),
0x5af43d82803e903d91603657fd5bf30000000000000000000000000000000000
)
}
// -------------------------------------------------------------------------------------------------------------
// APPENDED DATA (Accessible from extcodecopy)
// (but also send as appended data to the delegatecall)
// -------------------------------------------------------------------------------------------------------------
extraLength -= 2;
uint256 counter = extraLength;
uint256 copyPtr = ptr + 0x43;
uint256 dataPtr;
// solhint-disable-next-line no-inline-assembly
assembly {
dataPtr := add(data, 32)
}
for (; counter >= 32; counter -= 32) {
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, mload(dataPtr))
}
copyPtr += 32;
dataPtr += 32;
}
uint256 mask = ~(256 ** (32 - counter) - 1);
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, and(mload(dataPtr), mask))
}
copyPtr += counter;
// solhint-disable-next-line no-inline-assembly
assembly {
mstore(copyPtr, shl(240, extraLength))
}
/// @solidity memory-safe-assembly
// solhint-disable-next-line no-inline-assembly
assembly {
// Store the `_PROXY_BYTECODE` into scratch space.
mstore(0x00, _CREATE3_PROXY_BYTECODE)
// Deploy a new contract with our pre-made bytecode via CREATE2.
let proxy := create2(0, 0x10, 0x10, salt)
// If the result of `create2` is the zero address, revert.
if iszero(proxy) {
// Store the function selector of `CreateFail()`.
mstore(0x00, 0xebfef188)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Store the proxy's address.
mstore(0x14, proxy)
// 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
// 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
mstore(0x00, 0xd694)
// Nonce of the proxy contract (1).
mstore8(0x34, 0x01)
deployed := and(
keccak256(0x1e, 0x17),
0xffffffffffffffffffffffffffffffffffffffff
)
// If the `call` fails or the code size of `deployed` is zero, revert.
// The second argument of the or() call is evaluated first, which is important
// here because extcodesize(deployed) is only non-zero after the call() to the proxy
// is made and the contract is successfully deployed.
if or(
iszero(extcodesize(deployed)),
iszero(
call(
gas(), // Gas remaining.
proxy, // Proxy's address.
value, // Ether value.
ptr, // Pointer to the creation code
creationSize, // Size of the creation code
0x00, // Offset of output.
0x00 // Length of output.
)
)
) {
// Store the function selector of `InitializeFail()`.
mstore(0x00, 0x8f86d2f1)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
}
}
}
/// @notice Returns the CREATE3 deterministic address of the contract deployed via cloneDeterministic().
/// @dev Forked from https://github.com/Vectorized/solady/blob/main/src/utils/CREATE3.sol
/// @param salt The salt used by the CREATE3 deployment
function addressOfClone3(
bytes32 salt
) internal view returns (address deployed) {
/// @solidity memory-safe-assembly
// solhint-disable-next-line no-inline-assembly
assembly {
// Cache the free memory pointer.
let m := mload(0x40)
// Store `address(this)`.
mstore(0x00, address())
// Store the prefix.
mstore8(0x0b, 0xff)
// Store the salt.
mstore(0x20, salt)
// Store the bytecode hash.
mstore(0x40, _CREATE3_PROXY_BYTECODE_HASH)
// Store the proxy's address.
mstore(0x14, keccak256(0x0b, 0x55))
// Restore the free memory pointer.
mstore(0x40, m)
// 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01).
// 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex).
mstore(0x00, 0xd694)
// Nonce of the proxy contract (1).
mstore8(0x34, 0x01)
deployed := and(
keccak256(0x1e, 0x17),
0xffffffffffffffffffffffffffffffffffffffff
)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
import {Arrays} from "../Arrays.sol";
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function _clear(Set storage set) private {
uint256 len = _length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(Bytes32Set storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(AddressSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(UintSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: BSD
pragma solidity >=0.8.0;
import {Clone} from "@clones-with-immutable-args-1.1.2/Clone.sol";
import {IERC20} from "src/interfaces/IERC20.sol";
/// @notice Modern and gas efficient ERC20 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract CloneERC20 is Clone, IERC20 {
/*///////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*///////////////////////////////////////////////////////////////
METADATA
//////////////////////////////////////////////////////////////*/
function name() external pure returns (string memory) {
return string(abi.encodePacked(_getArgUint256(0)));
}
function symbol() external pure returns (string memory) {
return string(abi.encodePacked(_getArgUint256(0x20)));
}
function decimals() external pure returns (uint8) {
return _getArgUint8(0x40);
}
/*///////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function increaseAllowance(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] += amount;
emit Approval(msg.sender, spender, allowance[msg.sender][spender]);
return true;
}
function decreaseAllowance(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] -= amount;
emit Approval(msg.sender, spender, allowance[msg.sender][spender]);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*///////////////////////////////////////////////////////////////
INTERNAL LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
pragma solidity ^0.8.20;
import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
/**
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
uint256[] memory array,
function(uint256, uint256) pure returns (bool) comp
) internal pure returns (uint256[] memory) {
_quickSort(_begin(array), _end(array), comp);
return array;
}
/**
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
*/
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
sort(array, Comparators.lt);
return array;
}
/**
* @dev Sort an array of address (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
address[] memory array,
function(address, address) pure returns (bool) comp
) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of address in increasing order.
*/
function sort(address[] memory array) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
bytes32[] memory array,
function(bytes32, bytes32) pure returns (bool) comp
) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
*/
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
* at end (exclusive). Sorting follows the `comp` comparator.
*
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
*
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
* be used only if the limits are within a memory array.
*/
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
unchecked {
if (end - begin < 0x40) return;
// Use first element as pivot
uint256 pivot = _mload(begin);
// Position where the pivot should be at the end of the loop
uint256 pos = begin;
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
if (comp(_mload(it), pivot)) {
// If the value stored at the iterator's position comes before the pivot, we increment the
// position of the pivot and move the value there.
pos += 0x20;
_swap(pos, it);
}
}
_swap(begin, pos); // Swap pivot into place
_quickSort(begin, pos, comp); // Sort the left side of the pivot
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
}
}
/**
* @dev Pointer to the memory location of the first element of `array`.
*/
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
assembly ("memory-safe") {
ptr := add(array, 0x20)
}
}
/**
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
* that comes just after the last element of the array.
*/
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
unchecked {
return _begin(array) + array.length * 0x20;
}
}
/**
* @dev Load memory word (as a uint256) at location `ptr`.
*/
function _mload(uint256 ptr) private pure returns (uint256 value) {
assembly {
value := mload(ptr)
}
}
/**
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
*/
function _swap(uint256 ptr1, uint256 ptr2) private pure {
assembly {
let value1 := mload(ptr1)
let value2 := mload(ptr2)
mstore(ptr1, value2)
mstore(ptr2, value1)
}
}
/// @dev Helper: low level cast address memory array to uint256 memory array
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast address comp function to uint256 comp function
function _castToUint256Comp(
function(address, address) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
function _castToUint256Comp(
function(bytes32, bytes32) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* NOTE: The `array` is expected to be sorted in ascending order, and to
* contain no repeated elements.
*
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
* support for repeated elements in the array. The {lowerBound} function should
* be used instead.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value greater or equal than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
*/
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value strictly greater than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
*/
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Same as {lowerBound}, but with an array in memory.
*/
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Same as {upperBound}, but with an array in memory.
*/
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(address[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
}// SPDX-License-Identifier: BSD
pragma solidity ^0.8.4;
/// @title Clone
/// @author zefram.eth
/// @notice Provides helper functions for reading immutable args from calldata
contract Clone {
/// @notice Reads an immutable arg with type address
/// @param argOffset The offset of the arg in the packed data
/// @return arg The arg value
function _getArgAddress(
uint256 argOffset
) internal pure returns (address arg) {
uint256 offset = _getImmutableArgsOffset();
// solhint-disable-next-line no-inline-assembly
assembly {
arg := shr(0x60, calldataload(add(offset, argOffset)))
}
}
/// @notice Reads an immutable arg with type uint256
/// @param argOffset The offset of the arg in the packed data
/// @return arg The arg value
function _getArgUint256(
uint256 argOffset
) internal pure returns (uint256 arg) {
uint256 offset = _getImmutableArgsOffset();
// solhint-disable-next-line no-inline-assembly
assembly {
arg := calldataload(add(offset, argOffset))
}
}
/// @notice Reads a uint256 array stored in the immutable args.
/// @param argOffset The offset of the arg in the packed data
/// @param arrLen Number of elements in the array
/// @return arr The array
function _getArgUint256Array(
uint256 argOffset,
uint64 arrLen
) internal pure returns (uint256[] memory arr) {
uint256 offset = _getImmutableArgsOffset();
uint256 el;
arr = new uint256[](arrLen);
for (uint64 i = 0; i < arrLen; i++) {
// solhint-disable-next-line no-inline-assembly
assembly {
el := calldataload(add(add(offset, argOffset), mul(i, 32)))
}
arr[i] = el;
}
return arr;
}
/// @notice Reads an immutable arg with type uint64
/// @param argOffset The offset of the arg in the packed data
/// @return arg The arg value
function _getArgUint64(
uint256 argOffset
) internal pure returns (uint64 arg) {
uint256 offset = _getImmutableArgsOffset();
// solhint-disable-next-line no-inline-assembly
assembly {
arg := shr(0xc0, calldataload(add(offset, argOffset)))
}
}
/// @notice Reads an immutable arg with type uint8
/// @param argOffset The offset of the arg in the packed data
/// @return arg The arg value
function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) {
uint256 offset = _getImmutableArgsOffset();
// solhint-disable-next-line no-inline-assembly
assembly {
arg := shr(0xf8, calldataload(add(offset, argOffset)))
}
}
/// @return offset The offset of the packed immutable args in calldata
function _getImmutableArgsOffset() internal pure returns (uint256 offset) {
// solhint-disable-next-line no-inline-assembly
assembly {
offset := sub(
calldatasize(),
add(shr(240, calldataload(sub(calldatasize(), 2))), 2)
)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to compare values.
*
* _Available since v5.1._
*/
library Comparators {
function lt(uint256 a, uint256 b) internal pure returns (bool) {
return a < b;
}
function gt(uint256 a, uint256 b) internal pure returns (bool) {
return a > b;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
pragma solidity ^0.8.20;
/**
* @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
* corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
* the solidity language / compiler.
*
* See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
*
* Example usage:
* ```solidity
* contract Example {
* // Add the library methods
* using StorageSlot for bytes32;
* using SlotDerivation for bytes32;
*
* // Declare a namespace
* string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
*
* function setValueInNamespace(uint256 key, address newValue) internal {
* _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
* }
*
* function getValueInNamespace(uint256 key) internal view returns (address) {
* return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
* }
* }
* ```
*
* TIP: Consider using this library along with {StorageSlot}.
*
* NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
* upgrade safety will ignore the slots accessed through this library.
*
* _Available since v5.1._
*/
library SlotDerivation {
/**
* @dev Derive an ERC-7201 slot from a string (namespace).
*/
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
assembly ("memory-safe") {
mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
slot := and(keccak256(0x00, 0x20), not(0xff))
}
}
/**
* @dev Add an offset to a slot to get the n-th element of a structure or an array.
*/
function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
unchecked {
return bytes32(uint256(slot) + pos);
}
}
/**
* @dev Derive the location of the first element in an array from the slot where the length is stored.
*/
function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, slot)
result := keccak256(0x00, 0x20)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, and(key, shr(96, not(0))))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, iszero(iszero(key)))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}{
"remappings": [
"interfaces/=src/interfaces/",
"modules/=src/modules/",
"policies/=src/policies/",
"libraries/=src/libraries/",
"test/=src/test/",
"test/mocks/=src/test/mocks/",
"test/lib/=src/test/lib/",
"@base64-1.1.0/=dependencies/base64-1.1.0/",
"@surl-1.0.0/=dependencies/surl-1.0.0/src/",
"@chainlink-ccip-1.6.0/=dependencies/chainlink-ccip-1.6.0/contracts/src/v0.8/",
"@chainlink-local-0.2.5/=dependencies/chainlink-local-0.2.5/src/",
"@chainlink/contracts-ccip/contracts/=dependencies/chainlink-ccip-1.6.0/contracts/src/v0.8/ccip/",
"@chainlink/contracts/=dependencies/chainlink-ccip-1.6.0/contracts/",
"@forge-std-1.9.6/=dependencies/forge-std-1.9.6/src/",
"forge-std/=dependencies/forge-std-1.9.6/src/",
"@safe-utils-0.0.13/=dependencies/safe-utils-0.0.13/src/",
"@base58-solidity-1.0.3/=dependencies/base58-solidity-1.0.3/contracts/",
"@clones-with-immutable-args-1.1.2/=dependencies/clones-with-immutable-args-1.1.2/src/",
"clones/=dependencies/clones-with-immutable-args-1.1.2/src/",
"@layer-zero-endpoint-v1-0.0.6/=dependencies/layer-zero-endpoint-v1-0.0.6/contracts/",
"layer-zero/=dependencies/layer-zero-endpoint-v1-0.0.6/contracts/",
"@solmate-6.2.0/=dependencies/solmate-6.2.0/src/",
"solmate/=dependencies/solmate-6.2.0/src/",
"@openzeppelin-4.8.0/=dependencies/openzeppelin-4.8.0/contracts/",
"@openzeppelin/contracts/=dependencies/openzeppelin-4.8.0/contracts/",
"openzeppelin/=dependencies/openzeppelin-4.8.0/contracts/",
"@openzeppelin-5.3.0/=dependencies/openzeppelin-new-5.3.0/contracts/",
"proposal-sim/=dependencies/forge-proposal-simulator-1.0.1/",
"dependencies/forge-proposal-simulator-1.0.1/:@addresses/=dependencies/forge-proposal-simulator-1.0.1/addresses/",
"dependencies/forge-proposal-simulator-1.0.1/:@utils/=dependencies/forge-proposal-simulator-1.0.1/utils/",
"dependencies/forge-proposal-simulator-1.0.1/:@proposals/=dependencies/forge-proposal-simulator-1.0.1/proposals/",
"Governors/=dependencies/forge-proposal-simulator-1.0.1/Governors/",
"safe-smart-account/=dependencies/safe-smart-account-1.4.1/contracts/",
"solidity-http/=dependencies/solidity-http-0.0.6/src/",
"@addresses/=dependencies/forge-proposal-simulator-1.0.1/addresses/",
"@chainlink/local/src/=dependencies/chainlink-local-0.2.5/src/",
"@examples/=dependencies/forge-proposal-simulator-1.0.1/examples/",
"@proposals/=dependencies/forge-proposal-simulator-1.0.1/proposals/",
"@script/=dependencies/forge-proposal-simulator-1.0.1/script/",
"@test/=dependencies/forge-proposal-simulator-1.0.1/test/",
"@utils/=dependencies/forge-proposal-simulator-1.0.1/utils/",
"base58-solidity-1.0.3/=dependencies/base58-solidity-1.0.3/contracts/",
"base64-1.1.0/=dependencies/base64-1.1.0/",
"chainlink-ccip-1.6.0/=dependencies/chainlink-ccip-1.6.0/",
"chainlink-local-0.2.5/=dependencies/chainlink-local-0.2.5/src/",
"clones-with-immutable-args-1.1.2/=dependencies/clones-with-immutable-args-1.1.2/src/",
"comp-governance/=dependencies/forge-proposal-simulator-1.0.1/lib/compound-governance/contracts/",
"ds-test/=dependencies/clones-with-immutable-args-1.1.2/lib/ds-test/src/",
"forge-proposal-simulator-1.0.1/=dependencies/forge-proposal-simulator-1.0.1/",
"forge-std-1.9.6/=dependencies/forge-std-1.9.6/src/",
"layer-zero-endpoint-v1-0.0.6/=dependencies/layer-zero-endpoint-v1-0.0.6/contracts/",
"openzeppelin-4.8.0/=dependencies/openzeppelin-4.8.0/",
"openzeppelin-new-5.3.0/=dependencies/openzeppelin-new-5.3.0/",
"safe-smart-account-1.4.1/=dependencies/safe-smart-account-1.4.1/",
"safe-utils-0.0.13/=dependencies/safe-utils-0.0.13/src/",
"solidity-http-0.0.6/=dependencies/solidity-http-0.0.6/src/",
"solidity-stringutils/=dependencies/solidity-http-0.0.6/lib/solidity-stringutils/",
"solmate-6.2.0/=dependencies/solmate-6.2.0/src/",
"surl-1.0.0/=dependencies/surl-1.0.0/src/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CreateFail","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC6909InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC6909InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC6909InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC6909InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC6909InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC6909InvalidSpender","type":"error"},{"inputs":[{"internalType":"address","name":"erc20Implementation","type":"address"}],"name":"ERC6909Wrappable_InvalidERC20Implementation","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC6909Wrappable_InvalidTokenId","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC6909Wrappable_TokenIdAlreadyExists","type":"error"},{"inputs":[],"name":"ERC6909Wrappable_ZeroAmount","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"ReceiptTokenManager_InvalidParams","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ReceiptTokenManager_NotOwner","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ReceiptTokenManager_TokenExists","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"newDecimals","type":"uint8"}],"name":"ERC6909DecimalsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"newName","type":"string"}],"name":"ERC6909NameUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"newSymbol","type":"string"}],"name":"ERC6909SymbolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"OperatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint8","name":"depositPeriod","type":"uint8"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"TokenCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"wrappedToken","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unwrapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"wrappedToken","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Wrapped","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bool","name":"isWrapped_","type":"bool"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"uint8","name":"depositPeriod_","type":"uint8"},{"internalType":"address","name":"operator_","type":"address"},{"internalType":"string","name":"operatorName_","type":"string"}],"name":"createToken","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"contract IERC20","name":"asset_","type":"address"},{"internalType":"uint8","name":"depositPeriod_","type":"uint8"},{"internalType":"address","name":"operator_","type":"address"}],"name":"getReceiptTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenAsset","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenDepositPeriod","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTokenSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappableTokens","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address[]","name":"wrappedTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getWrappedToken","outputs":[{"internalType":"address","name":"wrappedToken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"isValidTokenId","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"bool","name":"shouldWrap_","type":"bool"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"wrap","outputs":[{"internalType":"address","name":"wrappedToken","type":"address"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f5ffd5b5060405161001c906100e0565b604051809103905ff080158015610035573d5f5f3e3d5ffd5b506040516301ffc9a760e01b815263a3d57e2360e01b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa15801561007f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100a391906100ed565b6100cf57604051631addc5b160e11b81526001600160a01b038216600482015260240160405180910390fd5b6001600160a01b0316608052610113565b610bf580612c6f83390190565b5f602082840312156100fd575f5ffd5b8151801515811461010c575f5ffd5b9392505050565b608051612b4461012b5f395f6113bf0152612b445ff3fe608060405234801561000f575f5ffd5b50600436106101b9575f3560e01c80636e286671116100f3578063bd85b03911610093578063dbf110a71161006e578063dbf110a714610484578063f90aadd814610497578063fe99049a146104aa578063fef7612d146104bd575f5ffd5b8063bd85b0391461043f578063d6750f0d1461045e578063dbe16c0714610471575f5ffd5b8063a5cd761f116100ce578063a5cd761f146103a1578063a7de07cd146103c9578063b6363cf2146103dc578063b8cac62b14610417575f5ffd5b80636e286671146103655780637b78bd3f146103785780638ba483161461038b575f5ffd5b80633463bd001161015e5780634e41a1fb116101395780634e41a1fb146102ed578063558a729714610300578063598af9e714610313578063665b89a714610352575f5ffd5b80633463bd00146102905780633f47e662146102a3578063426a8493146102da575f5ffd5b8063095bcdb611610199578063095bcdb61461022a57806325ded5861461023d5780632c1b38ee1461026857806331126dd11461027b575f5ffd5b8062ad800c146101bd578062fdd58e146101e657806301ffc9a714610207575b5f5ffd5b6101d06101cb36600461224c565b61051a565b6040516101dd9190612263565b60405180910390f35b6101f96101f43660046122ac565b6105b9565b6040519081526020016101dd565b61021a6102153660046122d6565b6105e1565b60405190151581526020016101dd565b61021a610238366004612315565b610636565b61025061024b366004612347565b61064d565b6040516001600160a01b0390911681526020016101dd565b61021a61027636600461224c565b610730565b61028e61028936600461237b565b61073c565b005b61025061029e36600461224c565b610764565b6102c86102b136600461224c565b5f9081526003602052604090206002015460ff1690565b60405160ff90911681526020016101dd565b61021a6102e8366004612315565b6107ef565b6101d06102fb36600461224c565b6107fc565b61021a61030e3660046123c0565b61081b565b6101f96103213660046123f3565b6001600160a01b039283165f9081526002602090815260408083209490951682529283528381209181529152205490565b61025061036036600461224c565b610830565b61028e610373366004612347565b610890565b6101d061038636600461224c565b6108fc565b610393610907565b6040516101dd929190612431565b6102506103af36600461224c565b5f908152600960205260409020546001600160a01b031690565b6102c86103d736600461224c565b6109db565b61021a6103ea3660046124ba565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205460ff1690565b61025061042536600461224c565b5f908152600860205260409020546001600160a01b031690565b6101f961044d36600461224c565b5f9081526006602052604090205490565b6101f961046c366004612584565b6109f4565b6101d061047f36600461224c565b610f02565b61028e61049236600461237b565b610f0d565b6102c86104a536600461224c565b610f2d565b61021a6104b8366004612635565b610fb1565b6101f96104cb366004612678565b604080516001600160a01b039586166020808301919091529486168183015260ff93909316606084015293166080808301919091528351808303909101815260a0909101909252815191012090565b5f818152600360205260409020805460609190610536906126d1565b80601f0160208091040260200160405190810160405280929190818152602001828054610562906126d1565b80156105ad5780601f10610584576101008083540402835291602001916105ad565b820191905f5260205f20905b81548152906001019060200180831161059057829003601f168201915b50505050509050919050565b6001600160a01b0382165f908152602081815260408083208484529091529020545b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcbd92ac30000000000000000000000000000000000000000000000000000000014806105db57506105db8261101a565b5f61064333858585611153565b5060019392505050565b5f61065a3384845f6111e9565b5f61066484611332565b6040517fda1919b3000000000000000000000000000000000000000000000000000000008152336004820152602481018590529091506001600160a01b0382169063da1919b3906044015f604051808303815f87803b1580156106c5575f5ffd5b505af11580156106d7573d5f5f3e3d5ffd5b50505050336001600160a01b0316816001600160a01b0316857f193440e46486835214d2bf8e8338c225cbade15085ee620409fded080dcbf6388660405161072191815260200190565b60405180910390a49392505050565b5f6105db60048361142b565b8261074681611442565b8361075081611487565b61075c868686866111e9565b505050505050565b5f818152600860205260408120546001600160a01b03168061078857505f92915050565b806001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e89190612722565b9392505050565b5f610643338585856114ec565b5f818152600360205260409020600101805460609190610536906126d1565b5f6108273384846115dd565b50600192915050565b5f818152600860205260408120546001600160a01b03168061085457505f92915050565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c4573d5f5f3e3d5ffd5b61089d33838360016111e9565b6108a83383836116eb565b5f8281526008602090815260409182902054915183815233926001600160a01b03169185917fcdf3a87cc9287f132ab1e52eaa74e0a92ddd0ccd7b65122d234fd0c05ac2d96f910160405180910390a45050565b60606105db826107fc565b606080610914600461173e565b9150815167ffffffffffffffff811115610930576109306124ff565b604051908082528060200260200182016040528015610959578160200160208202803683370190505b5090505f5b82518110156109d65760085f84838151811061097c5761097c61273d565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b03168282815181106109b6576109b661273d565b6001600160a01b039092166020928302919091019091015260010161095e565b509091565b5f8181526003602052604081206002015460ff166105db565b5f6001600160a01b038516610a6a576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f617373657400000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b8360ff165f03610ad6576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6465706f736974506572696f64000000000000000000000000000000000000006044820152606401610a61565b6001600160a01b038316610b46576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f6f70657261746f720000000000000000000000000000000000000000000000006044820152606401610a61565b604080513360208083018290526001600160a01b03808a168486015260ff8916606085015287166080808501919091528451808503909101815260a0909301909352815191909201209150610b9a82610730565b15610bd4576040517f8ae78e4f00000000000000000000000000000000000000000000000000000000815260048101839052602401610a61565b8060095f8481526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f610d2084886001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa158015610c49573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610c70919081019061276a565b610c7c8960ff1661174a565b8960ff16600114610cc2576040518060400160405280600781526020017f206d6f6e74687300000000000000000000000000000000000000000000000000815250610cf9565b6040518060400160405280600681526020017f206d6f6e746800000000000000000000000000000000000000000000000000008152505b604051602001610d0c94939291906127f6565b604051602081830303815290604052611885565b90505f610da785896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015610d62573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d89919081019061276a565b610d958a60ff1661174a565b604051602001610d0c9392919061284e565b9050610ea88483838b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610deb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0f91906128bc565b308d8d8d604051602001610e929493929190606094851b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825293851b8416601482015260f89290921b7fff0000000000000000000000000000000000000000000000000000000000000016602883015290921b166029820152603d0190565b60405160208183030381529060405260016118d8565b6040805160ff891681526001600160a01b038881166020830152808b16929086169187917f044408f3917d74247b3c8a62cfd8dd4b3dff74b645689a1ffc42d2ad8b83b1a8910160405180910390a4505050949350505050565b60606105db8261051a565b82610f1781611442565b83610f2181611487565b61075c86868686611978565b5f818152600860205260408120546001600160a01b031680610f5157505f92915050565b806001600160a01b03166387df2c166040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e891906128bc565b5f336001600160a01b0386168114801590610ff157506001600160a01b038087165f9081526001602090815260408083209385168352929052205460ff16155b156110025761100286828686611a70565b61100e86868686611153565b50600195945050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806110ac57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5483ce2400000000000000000000000000000000000000000000000000000000145b806110f857507fffffffff0000000000000000000000000000000000000000000000000000000082167f71abc79500000000000000000000000000000000000000000000000000000000145b8061114457507fffffffff0000000000000000000000000000000000000000000000000000000082167fbd85b03900000000000000000000000000000000000000000000000000000000145b806105db57506105db82611b38565b6001600160a01b038416611195576040517fa43520800000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b0383166111d7576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6111e384848484611bce565b50505050565b826111f381611442565b825f0361122c576040517fb73b6f7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611277576040517fa43520800000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610a61565b6001600160a01b03851633146112935761129385338686611a70565b8115611320576112a284611332565b6040517f79cc67900000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820186905291909116906379cc6790906044015b5f604051808303815f87803b158015611305575f5ffd5b505af1158015611317573d5f5f3e3d5ffd5b5050505061132b565b61132b858585611c33565b5050505050565b5f818152600860205260408120546001600160a01b03161561136957505f908152600860205260409020546001600160a01b031690565b5f61137383611c81565b905080515f036113b2576040517ff1834b7d00000000000000000000000000000000000000000000000000000000815260048101849052602401610a61565b6113e56001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682611d7f565b5f9384526008602052604090932080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385161790555090919050565b5f81815260018301602052604081205415156107e8565b61144b81610730565b611484576040517ff1834b7d00000000000000000000000000000000000000000000000000000000815260048101829052602401610a61565b50565b5f818152600960205260409020546001600160a01b03163381146114e8576040517f28b8ade10000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610a61565b5050565b6001600160a01b03841661152e576040517fcc766a980000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038316611570576040517f6f65f4650000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038481165f8181526002602090815260408083209488168084529482528083208784528252918290208590559051848152859392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a450505050565b6001600160a01b03831661161f576040517fcc766a980000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038216611661576040517f6f65f4650000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a3505050565b6001600160a01b03831661172d576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6117395f848484611bce565b505050565b60605f6107e883611d8b565b6060815f0361178c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b815f5b81156117b5578061179f81612904565b91506117ae9050600a83612949565b915061178f565b5f8167ffffffffffffffff8111156117cf576117cf6124ff565b6040519080825280601f01601f1916602001820160405280156117f9576020820181803683370190505b509050815b851561187c5761180f60018261295c565b905061181c600a8761296f565b611827906030612982565b60f81b82828151811061183c5761183c61273d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350611875600a87612949565b95506117fe565b50949350505050565b6060816040516020016118989190612995565b6040516020818303038152906040526118b0906129a0565b6040516020016118c291815260200190565b6040516020818303038152906040529050919050565b6118e360048761142b565b1561191d576040517f06afa29900000000000000000000000000000000000000000000000000000000815260048101879052602401610a61565b6119278686611de3565b6119318685611e37565b61193b8684611e82565b5f8681526007602052604090206119528382612a07565b5080156119645761196286611332565b505b61196f600487611ef3565b50505050505050565b8261198281611442565b825f036119bb576040517fb73b6f7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611a06576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610a61565b8115611a6557611a1584611332565b6040517fda1919b30000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201869052919091169063da1919b3906044016112ee565b61132b8585856116eb565b6001600160a01b038481165f9081526002602090815260408083209387168352928152828220858352905220545f1981101561132b5781811015611b00576040517f58a3fd5a0000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602481018290526044810183905260648101849052608401610a61565b6001600160a01b038086165f908152600260209081526040808320938816835292815282822086835290522082820390555050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f0f632fb30000000000000000000000000000000000000000000000000000000014806105db57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146105db565b611bda84848484611efe565b6001600160a01b038416611c0b575f8281526006602052604081208054839290611c05908490612982565b90915550505b6001600160a01b0383166111e3575f8281526006602052604090208054829003905550505050565b6001600160a01b038316611c75576040517fa43520800000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b611739835f8484611bce565b5f81815260076020526040812080546060929190611c9e906126d1565b80601f0160208091040260200160405190810160405280929190818152602001828054611cca906126d1565b8015611d155780601f10611cec57610100808354040283529160200191611d15565b820191905f5260205f20905b815481529060010190602001808311611cf857829003601f168201915b50505050509050611d258361051a565b611d2e906129a0565b611d37846107fc565b611d40906129a0565b5f8581526003602052604090206002015460ff1683604051602001611d689493929190612ac2565b604051602081830303815290604052915050919050565b5f6107e883835f612049565b6060815f018054806020026020016040519081016040528092919081815260200182805480156105ad57602002820191905f5260205f20905b815481526020019060010190808311611dc45750505050509050919050565b5f828152600360205260409020611dfa8282612a07565b50817f6846707b16f55a3623d38bf118700af63d0784698270a53ce28b116dbaa8b79482604051611e2b9190612263565b60405180910390a25050565b5f828152600360205260409020600101611e518282612a07565b50817f8fabcb7b4fbdde605303a7339bc80fb6956cd01a42e9cdf2d15d0f2fdd3b06fa82604051611e2b9190612263565b5f8281526003602090815260409182902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8516908117909155915191825283917fc7435874568017e6134c851002a405d733521c0f4c63f9f25f3a32a4d595b7299101611e2b565b5f6107e883836120a9565b336001600160a01b03851615611fb0576001600160a01b0385165f9081526020818152604080832086845290915290205482811015611f89576040517fb1b4fec00000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602481018290526044810184905260648101859052608401610a61565b6001600160a01b0386165f9081526020818152604080832087845290915290209083900390555b6001600160a01b03841615611ff5576001600160a01b0384165f9081526020818152604080832086845290915281208054849290611fef908490612982565b90915550505b604080516001600160a01b03838116825260208201859052859281881692918916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a45050505050565b5f5f61205585856120f5565b905080516020820184f091506001600160a01b0382166120a1576040517febfef18800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b5f8181526001830160205260408120546120ee57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556105db565b505f6105db565b805160408051604380840180835282850190910183527f610000000000000000000000000000000000000000000000000000000000000060208084019182526039860160f081811b60218701527f3d81600a3d39f33d3d3d3d363d3d376100000000000000000000000000000000602387015260028801901b603386018190527f60373639366100000000000000000000000000000000000000000000000000006035870152603b8601527f013d730000000000000000000000000000000000000000000000000000000000603d860152606089901b958501959095527f5af43d3d93803e603557fd5bf3000000000000000000000000000000000000006054850152929493919286019084606187015b602082106122255783518152602093840193601f199092019101612206565b92515f1960208390036101000a011916835260f09590951b91909401525091949350505050565b5f6020828403121561225c575f5ffd5b5035919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6001600160a01b0381168114611484575f5ffd5b5f5f604083850312156122bd575f5ffd5b82356122c881612298565b946020939093013593505050565b5f602082840312156122e6575f5ffd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146107e8575f5ffd5b5f5f5f60608486031215612327575f5ffd5b833561233281612298565b95602085013595506040909401359392505050565b5f5f60408385031215612358575f5ffd5b50508035926020909101359150565b80358015158114612376575f5ffd5b919050565b5f5f5f5f6080858703121561238e575f5ffd5b843561239981612298565b935060208501359250604085013591506123b560608601612367565b905092959194509250565b5f5f604083850312156123d1575f5ffd5b82356123dc81612298565b91506123ea60208401612367565b90509250929050565b5f5f5f60608486031215612405575f5ffd5b833561241081612298565b9250602084013561242081612298565b929592945050506040919091013590565b604080825283519082018190525f9060208501906060840190835b8181101561246a57835183526020938401939092019160010161244c565b5050838103602080860191909152855180835291810192508501905f5b818110156124ae5782516001600160a01b0316845260209384019390920191600101612487565b50919695505050505050565b5f5f604083850312156124cb575f5ffd5b82356124d681612298565b915060208301356124e681612298565b809150509250929050565b60ff81168114611484575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612555576125556124ff565b604052919050565b5f67ffffffffffffffff821115612576576125766124ff565b50601f01601f191660200190565b5f5f5f5f60808587031215612597575f5ffd5b84356125a281612298565b935060208501356125b2816124f1565b925060408501356125c281612298565b9150606085013567ffffffffffffffff8111156125dd575f5ffd5b8501601f810187136125ed575f5ffd5b80356126006125fb8261255d565b61252c565b818152886020838501011115612614575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f5f5f60808587031215612648575f5ffd5b843561265381612298565b9350602085013561266381612298565b93969395505050506040820135916060013590565b5f5f5f5f6080858703121561268b575f5ffd5b843561269681612298565b935060208501356126a681612298565b925060408501356126b6816124f1565b915060608501356126c681612298565b939692955090935050565b600181811c908216806126e557607f821691505b60208210810361271c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215612732575f5ffd5b81516107e881612298565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6020828403121561277a575f5ffd5b815167ffffffffffffffff811115612790575f5ffd5b8201601f810184136127a0575f5ffd5b80516127ae6125fb8261255d565b8181528560208385010111156127c2575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518060208401855e5f93019283525090919050565b5f61280a61280483886127df565b866127df565b7f202d200000000000000000000000000000000000000000000000000000000000815261284361283d60038301876127df565b856127df565b979650505050505050565b5f61285c61283d83876127df565b7f2d00000000000000000000000000000000000000000000000000000000000000815261288c60018201856127df565b7f6d0000000000000000000000000000000000000000000000000000000000000081526001019695505050505050565b5f602082840312156128cc575f5ffd5b81516107e8816124f1565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f5f198203612915576129156128d7565b5060010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826129575761295761291c565b500490565b818103818111156105db576105db6128d7565b5f8261297d5761297d61291c565b500690565b808201808211156105db576105db6128d7565b5f6107e882846127df565b8051602080830151919081101561271c575f1960209190910360031b1b16919050565b601f82111561173957805f5260205f20601f840160051c810160208510156129e85750805b601f840160051c820191505b8181101561132b575f81556001016129f4565b815167ffffffffffffffff811115612a2157612a216124ff565b612a3581612a2f84546126d1565b846129c3565b6020601f821160018114612a67575f8315612a505750848201515b5f19600385901b1c1916600184901b17845561132b565b5f84815260208120601f198516915b82811015612a965787850151825560209485019460019092019101612a76565b5084821015612ab357868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8481528360208201527fff000000000000000000000000000000000000000000000000000000000000008360f81b1660408201525f612b0460418301846127df565b969550505050505056fea2646970667358221220a98b3177a4fc1b9fc6c873a5d7f9e212ec6c50466600fb264f6fad3a730f94c964736f6c634300081e00336080604052348015600e575f5ffd5b50610bd98061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061012f575f3560e01c806370a08231116100ad57806395d89b411161007d578063a9059cbb11610063578063a9059cbb1461026d578063da1919b314610280578063dd62ed3e14610293575f5ffd5b806395d89b4114610252578063a457c2d71461025a575f5ffd5b806370a082311461020e57806379cc67901461022d57806387df2c16146102425780638da5cb5b1461024a575f5ffd5b806323b872dd1161010257806338d52e0f116100e857806338d52e0f146101c657806339509351146101f3578063570ca73514610206575f5ffd5b806323b872dd14610199578063313ce567146101ac575f5ffd5b806301ffc9a71461013357806306fdde031461015b578063095ea7b31461017057806318160ddd14610183575b5f5ffd5b6101466101413660046109e3565b6102bd565b60405190151581526020015b60405180910390f35b6101636103ed565b6040516101529190610a29565b61014661017e366004610aa4565b61041e565b61018b5f5481565b604051908152602001610152565b6101466101a7366004610acc565b610496565b6101b46105d6565b60405160ff9091168152602001610152565b6101ce6105e6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610152565b610146610201366004610aa4565b6105f1565b6101ce61069a565b61018b61021c366004610b06565b60016020525f908152604090205481565b61024061023b366004610aa4565b6106a5565b005b6101b46106bb565b6101ce6106c6565b6101636106d1565b610146610268366004610aa4565b6106dd565b61014661027b366004610aa4565b61071e565b61024061028e366004610aa4565b6107a1565b61018b6102a1366004610b1f565b600260209081525f928352604080842090915290825290205481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061034f57507fffffffff0000000000000000000000000000000000000000000000000000000082167f942e8b2200000000000000000000000000000000000000000000000000000000145b8061039b57507fffffffff0000000000000000000000000000000000000000000000000000000082167fa3d57e2300000000000000000000000000000000000000000000000000000000145b806103e757507fffffffff0000000000000000000000000000000000000000000000000000000082167f65a36e7700000000000000000000000000000000000000000000000000000000145b92915050565b60606103f85f6107b3565b60405160200161040a91815260200190565b604051602081830303815290604052905090565b335f81815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906104859086815260200190565b60405180910390a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff83165f9081526002602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610528576104f78382610b7d565b73ffffffffffffffffffffffffffffffffffffffff86165f9081526002602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff85165f908152600160205260408120805485929061055c908490610b7d565b909155505073ffffffffffffffffffffffffffffffffffffffff8085165f81815260016020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906105c39087815260200190565b60405180910390a3506001949350505050565b5f6105e160406107f2565b905090565b5f6105e16055610834565b335f90815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812080548391908390610632908490610b90565b9091555050335f81815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8816808552908352928190205490519081529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259101610485565b5f6105e1606a610834565b6106ad610876565b6106b782826108e4565b5050565b5f6105e160696107f2565b5f6105e16041610834565b60606103f860206107b3565b335f90815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152812080548391908390610632908490610b7d565b335f9081526001602052604081208054839190839061073e908490610b7d565b909155505073ffffffffffffffffffffffffffffffffffffffff83165f81815260016020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104859086815260200190565b6107a9610876565b6106b78282610975565b5f5f6107e77ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe368181013560f01c90030190565b929092013592915050565b5f5f6108267ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe368181013560f01c90030190565b929092013560f81c92915050565b5f5f6108687ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe368181013560f01c90030190565b929092013560601c92915050565b61087e6106c6565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108e2576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526001602052604081208054839290610918908490610b7d565b90915550505f8054829003815560405182815273ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b805f5f8282546109859190610b90565b909155505073ffffffffffffffffffffffffffffffffffffffff82165f818152600160209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610969565b5f602082840312156109f3575f5ffd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610a22575f5ffd5b9392505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a9f575f5ffd5b919050565b5f5f60408385031215610ab5575f5ffd5b610abe83610a7c565b946020939093013593505050565b5f5f5f60608486031215610ade575f5ffd5b610ae784610a7c565b9250610af560208501610a7c565b929592945050506040919091013590565b5f60208284031215610b16575f5ffd5b610a2282610a7c565b5f5f60408385031215610b30575f5ffd5b610b3983610a7c565b9150610b4760208401610a7c565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156103e7576103e7610b50565b808201808211156103e7576103e7610b5056fea2646970667358221220533193ce38beab52e4fb10a31007b996172c3b3ce2b7280eee10fa1c09f7abfa64736f6c634300081e0033
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106101b9575f3560e01c80636e286671116100f3578063bd85b03911610093578063dbf110a71161006e578063dbf110a714610484578063f90aadd814610497578063fe99049a146104aa578063fef7612d146104bd575f5ffd5b8063bd85b0391461043f578063d6750f0d1461045e578063dbe16c0714610471575f5ffd5b8063a5cd761f116100ce578063a5cd761f146103a1578063a7de07cd146103c9578063b6363cf2146103dc578063b8cac62b14610417575f5ffd5b80636e286671146103655780637b78bd3f146103785780638ba483161461038b575f5ffd5b80633463bd001161015e5780634e41a1fb116101395780634e41a1fb146102ed578063558a729714610300578063598af9e714610313578063665b89a714610352575f5ffd5b80633463bd00146102905780633f47e662146102a3578063426a8493146102da575f5ffd5b8063095bcdb611610199578063095bcdb61461022a57806325ded5861461023d5780632c1b38ee1461026857806331126dd11461027b575f5ffd5b8062ad800c146101bd578062fdd58e146101e657806301ffc9a714610207575b5f5ffd5b6101d06101cb36600461224c565b61051a565b6040516101dd9190612263565b60405180910390f35b6101f96101f43660046122ac565b6105b9565b6040519081526020016101dd565b61021a6102153660046122d6565b6105e1565b60405190151581526020016101dd565b61021a610238366004612315565b610636565b61025061024b366004612347565b61064d565b6040516001600160a01b0390911681526020016101dd565b61021a61027636600461224c565b610730565b61028e61028936600461237b565b61073c565b005b61025061029e36600461224c565b610764565b6102c86102b136600461224c565b5f9081526003602052604090206002015460ff1690565b60405160ff90911681526020016101dd565b61021a6102e8366004612315565b6107ef565b6101d06102fb36600461224c565b6107fc565b61021a61030e3660046123c0565b61081b565b6101f96103213660046123f3565b6001600160a01b039283165f9081526002602090815260408083209490951682529283528381209181529152205490565b61025061036036600461224c565b610830565b61028e610373366004612347565b610890565b6101d061038636600461224c565b6108fc565b610393610907565b6040516101dd929190612431565b6102506103af36600461224c565b5f908152600960205260409020546001600160a01b031690565b6102c86103d736600461224c565b6109db565b61021a6103ea3660046124ba565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205460ff1690565b61025061042536600461224c565b5f908152600860205260409020546001600160a01b031690565b6101f961044d36600461224c565b5f9081526006602052604090205490565b6101f961046c366004612584565b6109f4565b6101d061047f36600461224c565b610f02565b61028e61049236600461237b565b610f0d565b6102c86104a536600461224c565b610f2d565b61021a6104b8366004612635565b610fb1565b6101f96104cb366004612678565b604080516001600160a01b039586166020808301919091529486168183015260ff93909316606084015293166080808301919091528351808303909101815260a0909101909252815191012090565b5f818152600360205260409020805460609190610536906126d1565b80601f0160208091040260200160405190810160405280929190818152602001828054610562906126d1565b80156105ad5780601f10610584576101008083540402835291602001916105ad565b820191905f5260205f20905b81548152906001019060200180831161059057829003601f168201915b50505050509050919050565b6001600160a01b0382165f908152602081815260408083208484529091529020545b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167fcbd92ac30000000000000000000000000000000000000000000000000000000014806105db57506105db8261101a565b5f61064333858585611153565b5060019392505050565b5f61065a3384845f6111e9565b5f61066484611332565b6040517fda1919b3000000000000000000000000000000000000000000000000000000008152336004820152602481018590529091506001600160a01b0382169063da1919b3906044015f604051808303815f87803b1580156106c5575f5ffd5b505af11580156106d7573d5f5f3e3d5ffd5b50505050336001600160a01b0316816001600160a01b0316857f193440e46486835214d2bf8e8338c225cbade15085ee620409fded080dcbf6388660405161072191815260200190565b60405180910390a49392505050565b5f6105db60048361142b565b8261074681611442565b8361075081611487565b61075c868686866111e9565b505050505050565b5f818152600860205260408120546001600160a01b03168061078857505f92915050565b806001600160a01b031663570ca7356040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e89190612722565b9392505050565b5f610643338585856114ec565b5f818152600360205260409020600101805460609190610536906126d1565b5f6108273384846115dd565b50600192915050565b5f818152600860205260408120546001600160a01b03168061085457505f92915050565b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c4573d5f5f3e3d5ffd5b61089d33838360016111e9565b6108a83383836116eb565b5f8281526008602090815260409182902054915183815233926001600160a01b03169185917fcdf3a87cc9287f132ab1e52eaa74e0a92ddd0ccd7b65122d234fd0c05ac2d96f910160405180910390a45050565b60606105db826107fc565b606080610914600461173e565b9150815167ffffffffffffffff811115610930576109306124ff565b604051908082528060200260200182016040528015610959578160200160208202803683370190505b5090505f5b82518110156109d65760085f84838151811061097c5761097c61273d565b602002602001015181526020019081526020015f205f9054906101000a90046001600160a01b03168282815181106109b6576109b661273d565b6001600160a01b039092166020928302919091019091015260010161095e565b509091565b5f8181526003602052604081206002015460ff166105db565b5f6001600160a01b038516610a6a576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600560248201527f617373657400000000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b8360ff165f03610ad6576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6465706f736974506572696f64000000000000000000000000000000000000006044820152606401610a61565b6001600160a01b038316610b46576040517feb7aad2e00000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f6f70657261746f720000000000000000000000000000000000000000000000006044820152606401610a61565b604080513360208083018290526001600160a01b03808a168486015260ff8916606085015287166080808501919091528451808503909101815260a0909301909352815191909201209150610b9a82610730565b15610bd4576040517f8ae78e4f00000000000000000000000000000000000000000000000000000000815260048101839052602401610a61565b8060095f8481526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055505f610d2084886001600160a01b03166306fdde036040518163ffffffff1660e01b81526004015f60405180830381865afa158015610c49573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610c70919081019061276a565b610c7c8960ff1661174a565b8960ff16600114610cc2576040518060400160405280600781526020017f206d6f6e74687300000000000000000000000000000000000000000000000000815250610cf9565b6040518060400160405280600681526020017f206d6f6e746800000000000000000000000000000000000000000000000000008152505b604051602001610d0c94939291906127f6565b604051602081830303815290604052611885565b90505f610da785896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015610d62573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d89919081019061276a565b610d958a60ff1661174a565b604051602001610d0c9392919061284e565b9050610ea88483838b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610deb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0f91906128bc565b308d8d8d604051602001610e929493929190606094851b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825293851b8416601482015260f89290921b7fff0000000000000000000000000000000000000000000000000000000000000016602883015290921b166029820152603d0190565b60405160208183030381529060405260016118d8565b6040805160ff891681526001600160a01b038881166020830152808b16929086169187917f044408f3917d74247b3c8a62cfd8dd4b3dff74b645689a1ffc42d2ad8b83b1a8910160405180910390a4505050949350505050565b60606105db8261051a565b82610f1781611442565b83610f2181611487565b61075c86868686611978565b5f818152600860205260408120546001600160a01b031680610f5157505f92915050565b806001600160a01b03166387df2c166040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f8d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e891906128bc565b5f336001600160a01b0386168114801590610ff157506001600160a01b038087165f9081526001602090815260408083209385168352929052205460ff16155b156110025761100286828686611a70565b61100e86868686611153565b50600195945050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806110ac57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5483ce2400000000000000000000000000000000000000000000000000000000145b806110f857507fffffffff0000000000000000000000000000000000000000000000000000000082167f71abc79500000000000000000000000000000000000000000000000000000000145b8061114457507fffffffff0000000000000000000000000000000000000000000000000000000082167fbd85b03900000000000000000000000000000000000000000000000000000000145b806105db57506105db82611b38565b6001600160a01b038416611195576040517fa43520800000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b0383166111d7576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6111e384848484611bce565b50505050565b826111f381611442565b825f0361122c576040517fb73b6f7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611277576040517fa43520800000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610a61565b6001600160a01b03851633146112935761129385338686611a70565b8115611320576112a284611332565b6040517f79cc67900000000000000000000000000000000000000000000000000000000081526001600160a01b0387811660048301526024820186905291909116906379cc6790906044015b5f604051808303815f87803b158015611305575f5ffd5b505af1158015611317573d5f5f3e3d5ffd5b5050505061132b565b61132b858585611c33565b5050505050565b5f818152600860205260408120546001600160a01b03161561136957505f908152600860205260409020546001600160a01b031690565b5f61137383611c81565b905080515f036113b2576040517ff1834b7d00000000000000000000000000000000000000000000000000000000815260048101849052602401610a61565b6113e56001600160a01b037f00000000000000000000000014aba22e70362b00deae451ae22592492f5dde081682611d7f565b5f9384526008602052604090932080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0385161790555090919050565b5f81815260018301602052604081205415156107e8565b61144b81610730565b611484576040517ff1834b7d00000000000000000000000000000000000000000000000000000000815260048101829052602401610a61565b50565b5f818152600960205260409020546001600160a01b03163381146114e8576040517f28b8ade10000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0382166024820152604401610a61565b5050565b6001600160a01b03841661152e576040517fcc766a980000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038316611570576040517f6f65f4650000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038481165f8181526002602090815260408083209488168084529482528083208784528252918290208590559051848152859392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a450505050565b6001600160a01b03831661161f576040517fcc766a980000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038216611661576040517f6f65f4650000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a3505050565b6001600160a01b03831661172d576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b6117395f848484611bce565b505050565b60605f6107e883611d8b565b6060815f0361178c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b815f5b81156117b5578061179f81612904565b91506117ae9050600a83612949565b915061178f565b5f8167ffffffffffffffff8111156117cf576117cf6124ff565b6040519080825280601f01601f1916602001820160405280156117f9576020820181803683370190505b509050815b851561187c5761180f60018261295c565b905061181c600a8761296f565b611827906030612982565b60f81b82828151811061183c5761183c61273d565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350611875600a87612949565b95506117fe565b50949350505050565b6060816040516020016118989190612995565b6040516020818303038152906040526118b0906129a0565b6040516020016118c291815260200190565b6040516020818303038152906040529050919050565b6118e360048761142b565b1561191d576040517f06afa29900000000000000000000000000000000000000000000000000000000815260048101879052602401610a61565b6119278686611de3565b6119318685611e37565b61193b8684611e82565b5f8681526007602052604090206119528382612a07565b5080156119645761196286611332565b505b61196f600487611ef3565b50505050505050565b8261198281611442565b825f036119bb576040517fb73b6f7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038516611a06576040517fb8bbd6100000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610a61565b8115611a6557611a1584611332565b6040517fda1919b30000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015260248201869052919091169063da1919b3906044016112ee565b61132b8585856116eb565b6001600160a01b038481165f9081526002602090815260408083209387168352928152828220858352905220545f1981101561132b5781811015611b00576040517f58a3fd5a0000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602481018290526044810183905260648101849052608401610a61565b6001600160a01b038086165f908152600260209081526040808320938816835292815282822086835290522082820390555050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f0f632fb30000000000000000000000000000000000000000000000000000000014806105db57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146105db565b611bda84848484611efe565b6001600160a01b038416611c0b575f8281526006602052604081208054839290611c05908490612982565b90915550505b6001600160a01b0383166111e3575f8281526006602052604090208054829003905550505050565b6001600160a01b038316611c75576040517fa43520800000000000000000000000000000000000000000000000000000000081525f6004820152602401610a61565b611739835f8484611bce565b5f81815260076020526040812080546060929190611c9e906126d1565b80601f0160208091040260200160405190810160405280929190818152602001828054611cca906126d1565b8015611d155780601f10611cec57610100808354040283529160200191611d15565b820191905f5260205f20905b815481529060010190602001808311611cf857829003601f168201915b50505050509050611d258361051a565b611d2e906129a0565b611d37846107fc565b611d40906129a0565b5f8581526003602052604090206002015460ff1683604051602001611d689493929190612ac2565b604051602081830303815290604052915050919050565b5f6107e883835f612049565b6060815f018054806020026020016040519081016040528092919081815260200182805480156105ad57602002820191905f5260205f20905b815481526020019060010190808311611dc45750505050509050919050565b5f828152600360205260409020611dfa8282612a07565b50817f6846707b16f55a3623d38bf118700af63d0784698270a53ce28b116dbaa8b79482604051611e2b9190612263565b60405180910390a25050565b5f828152600360205260409020600101611e518282612a07565b50817f8fabcb7b4fbdde605303a7339bc80fb6956cd01a42e9cdf2d15d0f2fdd3b06fa82604051611e2b9190612263565b5f8281526003602090815260409182902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8516908117909155915191825283917fc7435874568017e6134c851002a405d733521c0f4c63f9f25f3a32a4d595b7299101611e2b565b5f6107e883836120a9565b336001600160a01b03851615611fb0576001600160a01b0385165f9081526020818152604080832086845290915290205482811015611f89576040517fb1b4fec00000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602481018290526044810184905260648101859052608401610a61565b6001600160a01b0386165f9081526020818152604080832087845290915290209083900390555b6001600160a01b03841615611ff5576001600160a01b0384165f9081526020818152604080832086845290915281208054849290611fef908490612982565b90915550505b604080516001600160a01b03838116825260208201859052859281881692918916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a45050505050565b5f5f61205585856120f5565b905080516020820184f091506001600160a01b0382166120a1576040517febfef18800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b5f8181526001830160205260408120546120ee57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556105db565b505f6105db565b805160408051604380840180835282850190910183527f610000000000000000000000000000000000000000000000000000000000000060208084019182526039860160f081811b60218701527f3d81600a3d39f33d3d3d3d363d3d376100000000000000000000000000000000602387015260028801901b603386018190527f60373639366100000000000000000000000000000000000000000000000000006035870152603b8601527f013d730000000000000000000000000000000000000000000000000000000000603d860152606089901b958501959095527f5af43d3d93803e603557fd5bf3000000000000000000000000000000000000006054850152929493919286019084606187015b602082106122255783518152602093840193601f199092019101612206565b92515f1960208390036101000a011916835260f09590951b91909401525091949350505050565b5f6020828403121561225c575f5ffd5b5035919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6001600160a01b0381168114611484575f5ffd5b5f5f604083850312156122bd575f5ffd5b82356122c881612298565b946020939093013593505050565b5f602082840312156122e6575f5ffd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146107e8575f5ffd5b5f5f5f60608486031215612327575f5ffd5b833561233281612298565b95602085013595506040909401359392505050565b5f5f60408385031215612358575f5ffd5b50508035926020909101359150565b80358015158114612376575f5ffd5b919050565b5f5f5f5f6080858703121561238e575f5ffd5b843561239981612298565b935060208501359250604085013591506123b560608601612367565b905092959194509250565b5f5f604083850312156123d1575f5ffd5b82356123dc81612298565b91506123ea60208401612367565b90509250929050565b5f5f5f60608486031215612405575f5ffd5b833561241081612298565b9250602084013561242081612298565b929592945050506040919091013590565b604080825283519082018190525f9060208501906060840190835b8181101561246a57835183526020938401939092019160010161244c565b5050838103602080860191909152855180835291810192508501905f5b818110156124ae5782516001600160a01b0316845260209384019390920191600101612487565b50919695505050505050565b5f5f604083850312156124cb575f5ffd5b82356124d681612298565b915060208301356124e681612298565b809150509250929050565b60ff81168114611484575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612555576125556124ff565b604052919050565b5f67ffffffffffffffff821115612576576125766124ff565b50601f01601f191660200190565b5f5f5f5f60808587031215612597575f5ffd5b84356125a281612298565b935060208501356125b2816124f1565b925060408501356125c281612298565b9150606085013567ffffffffffffffff8111156125dd575f5ffd5b8501601f810187136125ed575f5ffd5b80356126006125fb8261255d565b61252c565b818152886020838501011115612614575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f5f5f60808587031215612648575f5ffd5b843561265381612298565b9350602085013561266381612298565b93969395505050506040820135916060013590565b5f5f5f5f6080858703121561268b575f5ffd5b843561269681612298565b935060208501356126a681612298565b925060408501356126b6816124f1565b915060608501356126c681612298565b939692955090935050565b600181811c908216806126e557607f821691505b60208210810361271c577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215612732575f5ffd5b81516107e881612298565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6020828403121561277a575f5ffd5b815167ffffffffffffffff811115612790575f5ffd5b8201601f810184136127a0575f5ffd5b80516127ae6125fb8261255d565b8181528560208385010111156127c2575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b5f81518060208401855e5f93019283525090919050565b5f61280a61280483886127df565b866127df565b7f202d200000000000000000000000000000000000000000000000000000000000815261284361283d60038301876127df565b856127df565b979650505050505050565b5f61285c61283d83876127df565b7f2d00000000000000000000000000000000000000000000000000000000000000815261288c60018201856127df565b7f6d0000000000000000000000000000000000000000000000000000000000000081526001019695505050505050565b5f602082840312156128cc575f5ffd5b81516107e8816124f1565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f5f198203612915576129156128d7565b5060010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826129575761295761291c565b500490565b818103818111156105db576105db6128d7565b5f8261297d5761297d61291c565b500690565b808201808211156105db576105db6128d7565b5f6107e882846127df565b8051602080830151919081101561271c575f1960209190910360031b1b16919050565b601f82111561173957805f5260205f20601f840160051c810160208510156129e85750805b601f840160051c820191505b8181101561132b575f81556001016129f4565b815167ffffffffffffffff811115612a2157612a216124ff565b612a3581612a2f84546126d1565b846129c3565b6020601f821160018114612a67575f8315612a505750848201515b5f19600385901b1c1916600184901b17845561132b565b5f84815260208120601f198516915b82811015612a965787850151825560209485019460019092019101612a76565b5084821015612ab357868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b8481528360208201527fff000000000000000000000000000000000000000000000000000000000000008360f81b1660408201525f612b0460418301846127df565b969550505050505056fea2646970667358221220a98b3177a4fc1b9fc6c873a5d7f9e212ec6c50466600fb264f6fad3a730f94c964736f6c634300081e0033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.