Source Code
Latest 25 from a total of 65 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit USDT | 24105403 | 75 days ago | IN | 0 ETH | 0.00038928 | ||||
| Deposit USDT | 23899597 | 104 days ago | IN | 0 ETH | 0.00002188 | ||||
| Deposit USDT | 23876681 | 107 days ago | IN | 0 ETH | 0.00025902 | ||||
| Deposit Coin | 23871359 | 108 days ago | IN | 0.38 ETH | 0.00003249 | ||||
| Deposit Coin | 23814807 | 115 days ago | IN | 0.33 ETH | 0.00032588 | ||||
| Deposit USDT | 23812138 | 116 days ago | IN | 0 ETH | 0.00036962 | ||||
| Deposit USDT | 23805336 | 117 days ago | IN | 0 ETH | 0.0003613 | ||||
| Deposit USDT | 23804889 | 117 days ago | IN | 0 ETH | 0.00036312 | ||||
| Deposit USDC | 23788742 | 119 days ago | IN | 0 ETH | 0.00002837 | ||||
| Deposit USDC | 23783467 | 120 days ago | IN | 0 ETH | 0.00003964 | ||||
| Deposit Coin | 23748938 | 125 days ago | IN | 0.31 ETH | 0.00055104 | ||||
| Deposit Coin | 23748225 | 125 days ago | IN | 0.059 ETH | 0.00072379 | ||||
| Deposit USDT | 23746936 | 125 days ago | IN | 0 ETH | 0.00021686 | ||||
| Deposit Coin | 23746885 | 125 days ago | IN | 0.007 ETH | 0.00014049 | ||||
| Deposit Coin | 23746837 | 125 days ago | IN | 0.02 ETH | 0.00017353 | ||||
| Deposit Coin | 23645668 | 139 days ago | IN | 0.3 ETH | 0.00033142 | ||||
| Deposit USDT | 23577946 | 149 days ago | IN | 0 ETH | 0.00020731 | ||||
| Deposit USDT | 23577901 | 149 days ago | IN | 0 ETH | 0.00027598 | ||||
| Deposit USDC | 23557504 | 151 days ago | IN | 0 ETH | 0.00026155 | ||||
| Deposit USDC | 23557497 | 151 days ago | IN | 0 ETH | 0.00015148 | ||||
| Deposit USDC | 23530413 | 155 days ago | IN | 0 ETH | 0.00020063 | ||||
| Deposit USDC | 23528280 | 156 days ago | IN | 0 ETH | 0.00020993 | ||||
| Deposit USDC | 23520190 | 157 days ago | IN | 0 ETH | 0.00041964 | ||||
| Deposit USDC | 23520124 | 157 days ago | IN | 0 ETH | 0.00040327 | ||||
| Set Stage | 23095810 | 216 days ago | IN | 0 ETH | 0.00011316 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 23871359 | 108 days ago | 0.00062534 ETH | ||||
| Transfer | 23871359 | 108 days ago | 0.37937465 ETH | ||||
| Transfer | 23814807 | 115 days ago | 0.00031551 ETH | ||||
| Transfer | 23814807 | 115 days ago | 0.32968448 ETH | ||||
| Transfer | 23748938 | 125 days ago | 0.00012158 ETH | ||||
| Transfer | 23748938 | 125 days ago | 0.30987841 ETH | ||||
| Transfer | 23748225 | 125 days ago | 0.00003885 ETH | ||||
| Transfer | 23748225 | 125 days ago | 0.05896114 ETH | ||||
| Transfer | 23746885 | 125 days ago | 0.00002291 ETH | ||||
| Transfer | 23746885 | 125 days ago | 0.00697708 ETH | ||||
| Transfer | 23746837 | 125 days ago | 0.00023159 ETH | ||||
| Transfer | 23746837 | 125 days ago | 0.0197684 ETH | ||||
| Transfer | 23645668 | 139 days ago | 0.00001958 ETH | ||||
| Transfer | 23645668 | 139 days ago | 0.29998041 ETH | ||||
| Transfer | 22903460 | 243 days ago | 0.00008599 ETH | ||||
| Transfer | 22903460 | 243 days ago | 0.09444 ETH | ||||
| Transfer | 22898650 | 243 days ago | 0.00021383 ETH | ||||
| Transfer | 22898650 | 243 days ago | 0.80978616 ETH | ||||
| Transfer | 22897662 | 244 days ago | 0.00000239 ETH | ||||
| Transfer | 22897662 | 244 days ago | 0.4279976 ETH | ||||
| Transfer | 22896619 | 244 days ago | 0.0001559 ETH | ||||
| Transfer | 22896619 | 244 days ago | 0.80984409 ETH | ||||
| Transfer | 22868323 | 248 days ago | 0.00024154 ETH | ||||
| Transfer | 22868323 | 248 days ago | 0.99975845 ETH | ||||
| Transfer | 22830568 | 253 days ago | 0.00012946 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EB1Presale
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2025-08-07
*/
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// File: @1inch/solidity-utils/contracts/interfaces/IDaiLikePermit.sol
pragma solidity ^0.8.0;
/**
* @title IDaiLikePermit
* @dev Interface for Dai-like permit function allowing token spending via signatures.
*/
interface IDaiLikePermit {
/**
* @notice Approves spending of tokens via off-chain signatures.
* @param holder Token holder's address.
* @param spender Spender's address.
* @param nonce Current nonce of the holder.
* @param expiry Time when the permit expires.
* @param allowed True to allow, false to disallow spending.
* @param v, r, s Signature components.
*/
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
// File: @1inch/solidity-utils/contracts/interfaces/IPermit2.sol
pragma solidity ^0.8.0;
/**
* @title IPermit2
* @dev Interface for a flexible permit system that extends ERC20 tokens to support permits in tokens lacking native permit functionality.
*/
interface IPermit2 {
/**
* @dev Struct for holding permit details.
* @param token ERC20 token address for which the permit is issued.
* @param amount The maximum amount allowed to spend.
* @param expiration Timestamp until which the permit is valid.
* @param nonce An incrementing value for each signature, unique per owner, token, and spender.
*/
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
/**
* @dev Struct for a single token allowance permit.
* @param details Permit details including token, amount, expiration, and nonce.
* @param spender Address authorized to spend the tokens.
* @param sigDeadline Deadline for the permit signature, ensuring timeliness of the permit.
*/
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
/**
* @dev Struct for packed allowance data to optimize storage.
* @param amount Amount allowed.
* @param expiration Permission expiry timestamp.
* @param nonce Unique incrementing value for tracking allowances.
*/
struct PackedAllowance {
uint160 amount;
uint48 expiration;
uint48 nonce;
}
/**
* @notice Executes a token transfer from one address to another.
* @param user The token owner's address.
* @param spender The address authorized to spend the tokens.
* @param amount The amount of tokens to transfer.
* @param token The address of the token being transferred.
*/
function transferFrom(address user, address spender, uint160 amount, address token) external;
/**
* @notice Issues a permit for spending tokens via a signed authorization.
* @param owner The token owner's address.
* @param permitSingle Struct containing the permit details.
* @param signature The signature proving the owner authorized the permit.
*/
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
/**
* @notice Retrieves the allowance details between a token owner and spender.
* @param user The token owner's address.
* @param token The token address.
* @param spender The spender's address.
* @return The packed allowance details.
*/
function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
/**
* @notice Approves the spender to use up to amount of the specified token up until the expiration
* @param token The token to approve
* @param spender The spender address to approve
* @param amount The approved amount of the token
* @param expiration The timestamp at which the approval is no longer valid
* @dev The packed allowance also holds a nonce, which will stay unchanged in approve
* @dev Setting amount to type(uint160).max sets an unlimited approval
*/
function approve(address token, address spender, uint160 amount, uint48 expiration) external;
}
// File: @1inch/solidity-utils/contracts/interfaces/IERC7597Permit.sol
pragma solidity ^0.8.0;
/**
* @title IERC7597Permit
* @dev A new extension for ERC-2612 permit, which has already been added to USDC v2.2.
*/
interface IERC7597Permit {
/**
* @notice Update allowance with a signed permit.
* @dev Signature bytes can be used for both EOA wallets and contract wallets.
* @param owner Token owner's address (Authorizer).
* @param spender Spender's address.
* @param value Amount of allowance.
* @param deadline The time at which the signature expires (unixtime).
* @param signature Unstructured bytes signature signed by an EOA wallet or a contract wallet.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes memory signature
) external;
}
// File: @1inch/solidity-utils/contracts/interfaces/IWETH.sol
pragma solidity ^0.8.0;
/**
* @title IWETH
* @dev Interface for wrapper as WETH-like token.
*/
interface IWETH is IERC20 {
/**
* @notice Emitted when Ether is deposited to get wrapper tokens.
*/
event Deposit(address indexed dst, uint256 wad);
/**
* @notice Emitted when wrapper tokens is withdrawn as Ether.
*/
event Withdrawal(address indexed src, uint256 wad);
/**
* @notice Deposit Ether to get wrapper tokens.
*/
function deposit() external payable;
/**
* @notice Withdraw wrapped tokens as Ether.
* @param amount Amount of wrapped tokens to withdraw.
*/
function withdraw(uint256 amount) external;
}
// File: @1inch/solidity-utils/contracts/libraries/RevertReasonForwarder.sol
pragma solidity ^0.8.0;
/**
* @title RevertReasonForwarder
* @notice Provides utilities for forwarding and retrieving revert reasons from failed external calls.
*/
library RevertReasonForwarder {
/**
* @dev Forwards the revert reason from the latest external call.
* This method allows propagating the revert reason of a failed external call to the caller.
*/
function reRevert() internal pure {
// bubble up revert reason from latest external call
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
/**
* @dev Retrieves the revert reason from the latest external call.
* This method enables capturing the revert reason of a failed external call for inspection or processing.
* @return reason The latest external call revert reason.
*/
function reReason() internal pure returns (bytes memory reason) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
reason := mload(0x40)
let length := returndatasize()
mstore(reason, length)
returndatacopy(add(reason, 0x20), 0, length)
mstore(0x40, add(reason, add(0x20, length)))
}
}
}
// File: @1inch/solidity-utils/contracts/libraries/SafeERC20.sol
pragma solidity ^0.8.0;
/**
* @title Implements efficient safe methods for ERC20 interface.
* @notice Compared to the standard ERC20, this implementation offers several enhancements:
* 1. more gas-efficient, providing significant savings in transaction costs.
* 2. support for different permit implementations
* 3. forceApprove functionality
* 4. support for WETH deposit and withdraw
*/
library SafeERC20 {
error SafeTransferFailed();
error SafeTransferFromFailed();
error ForceApproveFailed();
error SafeIncreaseAllowanceFailed();
error SafeDecreaseAllowanceFailed();
error SafePermitBadLength();
error Permit2TransferAmountTooHigh();
// Uniswap Permit2 address
address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
address private constant _PERMIT2_ZKSYNC = 0x0000000000225e31D15943971F47aD3022F714Fa;
bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857; // SafePermitBadLength.selector
/**
* @notice Fetches the balance of a specific ERC20 token held by an account.
* Consumes less gas then regular `ERC20.balanceOf`.
* @dev Note that the implementation does not perform dirty bits cleaning, so it is the
* responsibility of the caller to make sure that the higher 96 bits of the `account` parameter are clean.
* @param token The IERC20 token contract for which the balance will be fetched.
* @param account The address of the account whose token balance will be fetched.
* @return tokenBalance The balance of the specified ERC20 token held by the account.
*/
function safeBalanceOf(
IERC20 token,
address account
) internal view returns(uint256 tokenBalance) {
bytes4 selector = IERC20.balanceOf.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0x00, selector)
mstore(0x04, account)
let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
tokenBalance := mload(0)
if or(iszero(success), lt(returndatasize(), 0x20)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
/**
* @notice Attempts to safely transfer tokens from one address to another.
* @dev If permit2 is true, uses the Permit2 standard; otherwise uses the standard ERC20 transferFrom.
* Either requires `true` in return data, or requires target to be smart-contract and empty return data.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
* @param token The IERC20 token contract from which the tokens will be transferred.
* @param from The address from which the tokens will be transferred.
* @param to The address to which the tokens will be transferred.
* @param amount The amount of tokens to transfer.
* @param permit2 If true, uses the Permit2 standard for the transfer; otherwise uses the standard ERC20 transferFrom.
*/
function safeTransferFromUniversal(
IERC20 token,
address from,
address to,
uint256 amount,
bool permit2
) internal {
if (permit2) {
safeTransferFromPermit2(token, from, to, amount);
} else {
safeTransferFrom(token, from, to, amount);
}
}
/**
* @notice Attempts to safely transfer tokens from one address to another using the ERC20 standard.
* @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
* @param token The IERC20 token contract from which the tokens will be transferred.
* @param from The address from which the tokens will be transferred.
* @param to The address to which the tokens will be transferred.
* @param amount The amount of tokens to transfer.
*/
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
bytes4 selector = token.transferFrom.selector;
bool success;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
success := call(gas(), token, 0, data, 0x64, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
if (!success) revert SafeTransferFromFailed();
}
/**
* @notice Attempts to safely transfer tokens from one address to another using the Permit2 standard.
* @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `from` and `to` parameters are clean.
* @param token The IERC20 token contract from which the tokens will be transferred.
* @param from The address from which the tokens will be transferred.
* @param to The address to which the tokens will be transferred.
* @param amount The amount of tokens to transfer.
*/
function safeTransferFromPermit2(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
address permit2 = _getPermit2Address();
bytes4 selector = IPermit2.transferFrom.selector;
bool success;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
mstore(add(data, 0x64), token)
success := call(gas(), permit2, 0, data, 0x84, 0x0, 0x0)
if success {
success := gt(extcodesize(permit2), 0)
}
}
if (!success) revert SafeTransferFromFailed();
}
/**
* @notice Attempts to safely transfer tokens to another address.
* @dev Either requires `true` in return data, or requires target to be smart-contract and empty return data.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `to` parameter are clean.
* @param token The IERC20 token contract from which the tokens will be transferred.
* @param to The address to which the tokens will be transferred.
* @param amount The amount of tokens to transfer.
*/
function safeTransfer(
IERC20 token,
address to,
uint256 amount
) internal {
if (!_makeCall(token, token.transfer.selector, to, amount)) {
revert SafeTransferFailed();
}
}
/**
* @notice Attempts to approve a spender to spend a certain amount of tokens.
* @dev If `approve(from, to, amount)` fails, it tries to set the allowance to zero, and retries the `approve` call.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
* @param token The IERC20 token contract on which the call will be made.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function forceApprove(
IERC20 token,
address spender,
uint256 value
) internal {
if (!_makeCall(token, token.approve.selector, spender, value)) {
if (
!_makeCall(token, token.approve.selector, spender, 0) ||
!_makeCall(token, token.approve.selector, spender, value)
) {
revert ForceApproveFailed();
}
}
}
/**
* @notice Safely increases the allowance of a spender.
* @dev Increases with safe math check. Checks if the increased allowance will overflow, if yes, then it reverts the transaction.
* Then uses `forceApprove` to increase the allowance.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
* @param token The IERC20 token contract on which the call will be made.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to increase the allowance by.
*/
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
forceApprove(token, spender, allowance + value);
}
/**
* @notice Safely decreases the allowance of a spender.
* @dev Decreases with safe math check. Checks if the decreased allowance will underflow, if yes, then it reverts the transaction.
* Then uses `forceApprove` to increase the allowance.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `spender` parameter are clean.
* @param token The IERC20 token contract on which the call will be made.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to decrease the allowance by.
*/
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > allowance) revert SafeDecreaseAllowanceFailed();
forceApprove(token, spender, allowance - value);
}
/**
* @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
* Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
* @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
* @param token The IERC20 token to execute the permit function on.
* @param permit The permit data to be used in the function call.
*/
function safePermit(IERC20 token, bytes calldata permit) internal {
if (!tryPermit(token, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
}
/**
* @notice Attempts to execute the `permit` function on the provided token with custom owner and spender parameters.
* Permit type is determined automatically based on permit calldata (IERC20Permit, IDaiLikePermit, and IPermit2).
* @dev Wraps `tryPermit` function and forwards revert reason if permit fails.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
* @param token The IERC20 token to execute the permit function on.
* @param owner The owner of the tokens for which the permit is made.
* @param spender The spender allowed to spend the tokens by the permit.
* @param permit The permit data to be used in the function call.
*/
function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
}
/**
* @notice Attempts to execute the `permit` function on the provided token with the sender and contract as parameters.
* @dev Invokes `tryPermit` with sender as owner and contract as spender.
* @param token The IERC20 token to execute the permit function on.
* @param permit The permit data to be used in the function call.
* @return success Returns true if the permit function was successfully executed, false otherwise.
*/
function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
return tryPermit(token, msg.sender, address(this), permit);
}
/**
* @notice The function attempts to call the permit function on a given ERC20 token.
* @dev The function is designed to support a variety of permit functions, namely: IERC20Permit, IDaiLikePermit, IERC7597Permit and IPermit2.
* It accommodates both Compact and Full formats of these permit types.
* Please note, it is expected that the `expiration` parameter for the compact Permit2 and the `deadline` parameter
* for the compact Permit are to be incremented by one before invoking this function. This approach is motivated by
* gas efficiency considerations; as the unlimited expiration period is likely to be the most common scenario, and
* zeros are cheaper to pass in terms of gas cost. Thus, callers should increment the expiration or deadline by one
* before invocation for optimized performance.
* Note that the implementation does not perform dirty bits cleaning, so it is the responsibility of
* the caller to make sure that the higher 96 bits of the `owner` and `spender` parameters are clean.
* @param token The address of the ERC20 token on which to call the permit function.
* @param owner The owner of the tokens. This address should have signed the off-chain permit.
* @param spender The address which will be approved for transfer of tokens.
* @param permit The off-chain permit data, containing different fields depending on the type of permit function.
* @return success A boolean indicating whether the permit call was successful.
*/
function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
address permit2 = _getPermit2Address();
// load function selectors for different permit standards
bytes4 permitSelector = IERC20Permit.permit.selector;
bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
bytes4 permit2Selector = IPermit2.permit.selector;
bytes4 erc7597PermitSelector = IERC7597Permit.permit.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let ptr := mload(0x40)
// Switch case for different permit lengths, indicating different permit standards
switch permit.length
// Compact IERC20Permit
case 100 {
mstore(ptr, permitSelector) // store selector
mstore(add(ptr, 0x04), owner) // store owner
mstore(add(ptr, 0x24), spender) // store spender
// Compact IERC20Permit.permit(uint256 value, uint32 deadline, uint256 r, uint256 vs)
{ // stack too deep
let deadline := shr(224, calldataload(add(permit.offset, 0x20))) // loads permit.offset 0x20..0x23
let vs := calldataload(add(permit.offset, 0x44)) // loads permit.offset 0x44..0x63
calldatacopy(add(ptr, 0x44), permit.offset, 0x20) // store value = copy permit.offset 0x00..0x19
mstore(add(ptr, 0x64), sub(deadline, 1)) // store deadline = deadline - 1
mstore(add(ptr, 0x84), add(27, shr(255, vs))) // store v = most significant bit of vs + 27 (27 or 28)
calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20) // store r = copy permit.offset 0x24..0x43
mstore(add(ptr, 0xc4), shr(1, shl(1, vs))) // store s = vs without most significant bit
}
// IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
// Compact IDaiLikePermit
case 72 {
mstore(ptr, daiPermitSelector) // store selector
mstore(add(ptr, 0x04), owner) // store owner
mstore(add(ptr, 0x24), spender) // store spender
// Compact IDaiLikePermit.permit(uint32 nonce, uint32 expiry, uint256 r, uint256 vs)
{ // stack too deep
let expiry := shr(224, calldataload(add(permit.offset, 0x04))) // loads permit.offset 0x04..0x07
let vs := calldataload(add(permit.offset, 0x28)) // loads permit.offset 0x28..0x47
mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset))) // store nonce = copy permit.offset 0x00..0x03
mstore(add(ptr, 0x64), sub(expiry, 1)) // store expiry = expiry - 1
mstore(add(ptr, 0x84), true) // store allowed = true
mstore(add(ptr, 0xa4), add(27, shr(255, vs))) // store v = most significant bit of vs + 27 (27 or 28)
calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20) // store r = copy permit.offset 0x08..0x27
mstore(add(ptr, 0xe4), shr(1, shl(1, vs))) // store s = vs without most significant bit
}
// IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
// IERC20Permit
case 224 {
mstore(ptr, permitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
// IERC20Permit.permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
// IDaiLikePermit
case 256 {
mstore(ptr, daiPermitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
// IDaiLikePermit.permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s)
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
// Compact IPermit2
case 96 {
// Compact IPermit2.permit(uint160 amount, uint32 expiration, uint32 nonce, uint32 sigDeadline, uint256 r, uint256 vs)
mstore(ptr, permit2Selector) // store selector
mstore(add(ptr, 0x04), owner) // store owner
mstore(add(ptr, 0x24), token) // store token
calldatacopy(add(ptr, 0x50), permit.offset, 0x14) // store amount = copy permit.offset 0x00..0x13
// and(0xffffffffffff, ...) - conversion to uint48
mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1))) // store expiration = ((permit.offset 0x14..0x17 - 1) & 0xffffffffffff)
mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18)))) // store nonce = copy permit.offset 0x18..0x1b
mstore(add(ptr, 0xa4), spender) // store spender
// and(0xffffffffffff, ...) - conversion to uint48
mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1))) // store sigDeadline = ((permit.offset 0x1c..0x1f - 1) & 0xffffffffffff)
mstore(add(ptr, 0xe4), 0x100) // store offset = 256
mstore(add(ptr, 0x104), 0x40) // store length = 64
calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20) // store r = copy permit.offset 0x20..0x3f
calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20) // store vs = copy permit.offset 0x40..0x5f
// IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
success := call(gas(), permit2, 0, ptr, 0x164, 0, 0)
}
// IPermit2
case 352 {
mstore(ptr, permit2Selector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
// IPermit2.permit(address owner, PermitSingle calldata permitSingle, bytes calldata signature)
success := call(gas(), permit2, 0, ptr, 0x164, 0, 0)
}
// Dynamic length
default {
mstore(ptr, erc7597PermitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length) // copy permit calldata
// IERC7597Permit.permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature)
success := call(gas(), token, 0, ptr, add(permit.length, 4), 0, 0)
}
}
}
/**
* @dev Executes a low level call to a token contract, making it resistant to reversion and erroneous boolean returns.
* @param token The IERC20 token contract on which the call will be made.
* @param selector The function signature that is to be called on the token contract.
* @param to The address to which the token amount will be transferred.
* @param amount The token amount to be transferred.
* @return success A boolean indicating if the call was successful. Returns 'true' on success and 'false' on failure.
* In case of success but no returned data, validates that the contract code exists.
* In case of returned data, ensures that it's a boolean `true`.
*/
function _makeCall(
IERC20 token,
bytes4 selector,
address to,
uint256 amount
) private returns (bool success) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), to)
mstore(add(data, 0x24), amount)
success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
}
/**
* @notice Safely deposits a specified amount of Ether into the IWETH contract. Consumes less gas then regular `IWETH.deposit`.
* @param weth The IWETH token contract.
* @param amount The amount of Ether to deposit into the IWETH contract.
*/
function safeDeposit(IWETH weth, uint256 amount) internal {
bytes4 selector = IWETH.deposit.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0, selector)
if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
/**
* @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract. Consumes less gas then regular `IWETH.withdraw`.
* @dev Uses inline assembly to interact with the IWETH contract.
* @param weth The IWETH token contract.
* @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
*/
function safeWithdraw(IWETH weth, uint256 amount) internal {
bytes4 selector = IWETH.withdraw.selector;
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
mstore(0, selector)
mstore(4, amount)
if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
/**
* @notice Safely withdraws a specified amount of wrapped Ether from the IWETH contract to a specified recipient.
* Consumes less gas then regular `IWETH.withdraw`.
* @param weth The IWETH token contract.
* @param amount The amount of wrapped Ether to withdraw from the IWETH contract.
* @param to The recipient of the withdrawn Ether.
*/
function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
safeWithdraw(weth, amount);
if (to != address(this)) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
if iszero(call(gas(), to, amount, 0, 0, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
}
function _getPermit2Address() private view returns (address permit2) {
assembly ("memory-safe") { // solhint-disable-line no-inline-assembly
switch chainid()
case 324 { // zksync mainnet
permit2 := _PERMIT2_ZKSYNC
}
case 300 { // zksync testnet
permit2 := _PERMIT2_ZKSYNC
}
case 260 { // zksync fork network
permit2 := _PERMIT2_ZKSYNC
}
default {
permit2 := _PERMIT2
}
}
}
}
// File: @chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol
pragma solidity ^0.8.0;
// solhint-disable-next-line interface-starts-with-i
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
// File: @openzeppelin/contracts/utils/Context.sol
// 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;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
// File: @openzeppelin/contracts/access/Ownable2Step.sol
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
// File: @openzeppelin/contracts/utils/Pausable.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
// File: @openzeppelin/contracts/utils/cryptography/ECDSA.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}
// File: @openzeppelin/contracts/utils/Panic.sol
// 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)
}
}
}
// File: @openzeppelin/contracts/utils/math/SafeCast.sol
// 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))
}
}
}
// File: @openzeppelin/contracts/utils/math/Math.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @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 Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @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 {
if (b == 0) return (false, 0);
return (true, 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 {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 {
// 512-bit multiply [prod1 prod0] = 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 = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 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 prod0 / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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 {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, 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 prod1 into prod0.
prod0 |= prod1 * 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 prod1
// is no longer required.
result = prod0 * 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 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 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 1);
}
return result;
}
/**
* @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 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 1);
}
return result;
}
/**
* @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;
}
}
// File: @openzeppelin/contracts/utils/math/SignedMath.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @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, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}
// File: @openzeppelin/contracts/utils/Strings.sol
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
/**
* @dev String operations.
*/
library Strings {
using SafeCast for *;
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev The string being parsed contains characters that are not in scope of the given base.
*/
error StringsInvalidChar();
/**
* @dev The string being parsed is not a properly formatted address.
*/
error StringsInvalidAddressFormat();
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly ("memory-safe") {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
/**
* @dev Parse a decimal string and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input) internal pure returns (uint256) {
return parseUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseUint} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
uint256 result = 0;
for (uint256 i = begin; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 9) return (false, 0);
result *= 10;
result += chr;
}
return (true, result);
}
/**
* @dev Parse a decimal string and returns the value as a `int256`.
*
* Requirements:
* - The string must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input) internal pure returns (int256) {
return parseInt(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
(bool success, int256 value) = tryParseInt(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
* the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
}
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
/**
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character or if the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, int256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseIntUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseInt} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseIntUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, int256 value) {
bytes memory buffer = bytes(input);
// Check presence of a negative sign.
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
bool positiveSign = sign == bytes1("+");
bool negativeSign = sign == bytes1("-");
uint256 offset = (positiveSign || negativeSign).toUint();
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
if (absSuccess && absValue < ABS_MIN_INT256) {
return (true, negativeSign ? -int256(absValue) : int256(absValue));
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
return (true, type(int256).min);
} else return (false, 0);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input) internal pure returns (uint256) {
return parseHexUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
* invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseHexUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseHexUint} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseHexUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
// skip 0x prefix if present
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 offset = hasPrefix.toUint() * 2;
uint256 result = 0;
for (uint256 i = begin + offset; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 15) return (false, 0);
result *= 16;
unchecked {
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
// This guaratees that adding a value < 16 will not cause an overflow, hence the unchecked.
result += chr;
}
}
return (true, result);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input) internal pure returns (address) {
return parseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
(bool success, address value) = tryParseAddress(input, begin, end);
if (!success) revert StringsInvalidAddressFormat();
return value;
}
/**
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
* formatted address. See {parseAddress} requirements.
*/
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
return tryParseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
* formatted address. See {parseAddress} requirements.
*/
function tryParseAddress(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, address value) {
if (end > bytes(input).length || begin > end) return (false, address(0));
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
// check that input is the correct length
if (end - begin == expectedLength) {
// length guarantees that this does not overflow, and value is at most type(uint160).max
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
return (s, address(uint160(v)));
} else {
return (false, address(0));
}
}
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
uint8 value = uint8(chr);
// Try to parse `chr`:
// - Case 1: [0-9]
// - Case 2: [a-f]
// - Case 3: [A-F]
// - otherwise not supported
unchecked {
if (value > 47 && value < 58) value -= 48;
else if (value > 96 && value < 103) value -= 87;
else if (value > 64 && value < 71) value -= 55;
else return type(uint8).max;
}
return value;
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(buffer, add(0x20, offset)))
}
}
}
// File: @openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}
// File: @openzeppelin/contracts/utils/StorageSlot.sol
// 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
}
}
}
// File: @openzeppelin/contracts/utils/ShortStrings.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
assembly ("memory-safe") {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {toShortStringWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {toShortStringWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}
// File: @openzeppelin/contracts/interfaces/IERC5267.sol
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}
// File: @openzeppelin/contracts/utils/cryptography/EIP712.sol
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
// slither-disable-next-line constable-states
string private _nameFallback;
// slither-disable-next-line constable-states
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @inheritdoc IERC5267
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}
// File: @openzeppelin/contracts/utils/ReentrancyGuard.sol
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
// File: contracts/IPresale.sol
pragma solidity 0.8.28;
interface IPresale {
struct StageData {
uint256 amount;
uint256 cost;
}
event TokensBought(
address indexed token,
address indexed user,
address indexed referrer,
uint256 amount
);
event StageUpdated(uint256 currentStage);
event StageAdded(uint256 stageId, uint160 amount, uint256 cost);
event ReferralPoolUpdated(uint256 indexed oldAmount, uint256 indexed newAmount);
event UserBalanceUpdated(address indexed user, uint256 oldBalance, uint256 newBalance);
event ReferralBonusDistributed(uint256 totalBonuses, uint256 newTotal);
event PresaleEnded(uint256 totalTokensSold, uint256 totalSoldInUSD);
function setStage(uint256 stageIterator_) external;
function pause() external;
function unpause() external;
function depositUSDC(
uint256 amount,
uint256 minTokensOut,
address referrer,
uint256 deadline,
bytes calldata signature
) external;
function depositUSDT(
uint256 amount,
uint256 minTokensOut,
address referrer,
uint256 deadline,
bytes calldata signature
) external;
}
// File: contracts/EB1Presale.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
contract EB1Presale is IPresale, Ownable2Step, Pausable, EIP712, ReentrancyGuard {
using SafeERC20 for IERC20;
using ECDSA for bytes32;
/// @notice emitted when a referral/referee bonus is paid out
event ReferralReward(
address indexed referrer,
address indexed referee,
uint256 referrerReward,
uint256 refereeBonus
);
int32 public constant STABLETOKEN_PRICE = 1e8; // $1 in 8 decimals
uint8 public constant STABLE_TOKEN_DECIMALS = 6; // USDC/USDT decimals
uint8 public constant PRICEFEED_DECIMALS = 8; // Chainlink price feed decimals
uint8 public constant COIN_DECIMALS = 18; // ETH decimals
uint256 public referralPoolRemaining;
uint256 public totalReferralDistributed; // Track referral bonuses separately
uint8 public constant refereeRate = 3;
uint8 public constant referrerRate = 7;
mapping(address => uint256) public referralEarnings;
mapping(address => uint256) public nonces;
/// @notice EIP-712 typehash for the Allow struct
bytes32 public constant ALLOW_TYPEHASH =
keccak256(
"Allow(address buyer,uint256 amount,uint256 minTokensOut,address referrer,uint256 nonce,uint256 deadline,uint8 tokenType)"
);
AggregatorV3Interface public immutable COIN_PRICE_FEED;
AggregatorV3Interface public immutable USDC_PRICE_FEED;
AggregatorV3Interface public immutable USDT_PRICE_FEED;
IERC20 public immutable usdcToken;
IERC20 public immutable usdtToken;
address public constant protocolWallet=0xF2b433e6D72BC4f2b7afbE2b26689ce3086B23f7;
uint256 public totalTokensSold;
uint256 public totalSoldInUSD; //NOTE: Precision is 8 decimals
uint256 public stageIterator;
StageData[] public stages;
mapping(address user => uint256 balance) public balances;
address public immutable SIGNER;
uint256 public constant MIN_STABLE_PRICE = 0.95e8; // $0.95
uint256 public constant MAX_STABLE_PRICE = 1.05e8; // $1.05
constructor(
AggregatorV3Interface COIN_PRICE_FEED_,
AggregatorV3Interface USDC_PRICE_FEED_,
AggregatorV3Interface USDT_PRICE_FEED_,
IERC20 usdcToken_,
IERC20 usdtToken_,
address signer
) Ownable(msg.sender) EIP712("EB1Presale", "1") {
require(COIN_PRICE_FEED_ != AggregatorV3Interface(address(0)), "Invalid price feed");
require(USDC_PRICE_FEED_ != AggregatorV3Interface(address(0)), "Invalid USDC price feed");
require(USDT_PRICE_FEED_ != AggregatorV3Interface(address(0)), "Invalid USDT price feed");
require(usdcToken_ != IERC20(address(0)), "Invalid USDC token");
require(usdtToken_ != IERC20(address(0)), "Invalid USDT token");
require(signer != address(0), "Invalid signer");
COIN_PRICE_FEED = COIN_PRICE_FEED_;
USDC_PRICE_FEED = USDC_PRICE_FEED_;
USDT_PRICE_FEED = USDT_PRICE_FEED_;
usdcToken = usdcToken_;
usdtToken = usdtToken_;
SIGNER = signer;
// Initial two stages
stages.push(StageData(uint160(700_000), 714e5)); // 700k @ $0.714
stages.push(StageData(uint160(1_050_000), 1905e5)); // 1.05M @ $1.905
stages.push(StageData(uint160(1_400_000), 2727e5)); // 1.4M @ $2.727
stages.push(StageData(uint160(1_750_000), 3333e5)); // 1.75M @ $3.333
referralPoolRemaining = 260_000;
}
function setStage(uint256 stageIterator_) external onlyOwner {
require(stages.length >= stageIterator_, "Presale: Wrong iterator");
stageIterator = stageIterator_;
emit StageUpdated(stageIterator);
}
function addStage(uint160 amount, uint256 cost) external onlyOwner {
require(amount > 0, "Presale: amount must be >0");
require(cost > 0, "Presale: cost must be >0");
stages.push(StageData({amount: amount, cost: cost}));
emit StageAdded(stages.length - 1, amount, cost);
}
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function rescueFunds() external onlyOwner {
uint256 ethBal = address(this).balance;
if (ethBal > 0) {
(bool success, ) = payable(protocolWallet).call{value: ethBal}("");
require(success, "Rescue: ETH transfer failed");
}
uint256 usdcBal = usdcToken.balanceOf(address(this));
if (usdcBal > 0) {
usdcToken.safeTransfer(protocolWallet, usdcBal);
}
uint256 usdtBal = usdtToken.balanceOf(address(this));
if (usdtBal > 0) {
usdtToken.safeTransfer(protocolWallet, usdtBal);
}
}
function depositUSDC(
uint256 amount,
uint256 minTokensOut,
address referrer,
uint256 deadline,
bytes calldata signature
) external nonReentrant whenNotPaused {
_verifyAllowlist(
msg.sender,
amount,
minTokensOut,
referrer,
nonces[msg.sender],
deadline,
0,
signature
);
uint256 before = balances[msg.sender];
(uint256 chargeBack, uint256 spendedValue) = _depositChecksAndEffects(
usdcToken,
msg.sender,
amount,
true
);
_depositInteractions(usdcToken, amount, chargeBack, spendedValue);
uint256 bought = balances[msg.sender] - before;
// Slippage protection
require(bought >= minTokensOut, "Presale: Insufficient tokens received");
_applyReferral(msg.sender, referrer, bought);
emit TokensBought(
address(usdcToken),
msg.sender,
referrer,
spendedValue
);
}
function depositUSDT(
uint256 amount,
uint256 minTokensOut,
address referrer,
uint256 deadline,
bytes calldata signature
) external nonReentrant whenNotPaused {
_verifyAllowlist(
msg.sender,
amount,
minTokensOut,
referrer,
nonces[msg.sender],
deadline,
1,
signature
);
uint256 before = balances[msg.sender];
(uint256 chargeBack, uint256 spendedValue) = _depositChecksAndEffects(
usdtToken,
msg.sender,
amount,
true
);
_depositInteractions(usdtToken, amount, chargeBack, spendedValue);
uint256 bought = balances[msg.sender] - before;
// Slippage protection
require(bought >= minTokensOut, "Presale: Insufficient tokens received");
_applyReferral(msg.sender, referrer, bought);
emit TokensBought(
address(usdtToken),
msg.sender,
referrer,
spendedValue
);
}
function depositCoin(
uint256 minTokensOut,
address referrer,
uint256 deadline,
bytes calldata signature
) external payable nonReentrant whenNotPaused {
_verifyAllowlist(
msg.sender,
msg.value,
minTokensOut,
referrer,
nonces[msg.sender],
deadline,
2,
signature
);
uint256 before = balances[msg.sender];
(uint256 chargeBack, uint256 spendedValue) = _depositChecksAndEffects(
IERC20(address(0)),
msg.sender,
msg.value,
false
);
(bool success, ) = payable(protocolWallet).call{value: spendedValue}(
""
);
require(success, "Presale: Coin transfer failed");
if (chargeBack > 0) {
(success, ) = payable(msg.sender).call{value: chargeBack}("");
require(success, "Presale: Coin transfer failed");
}
uint256 bought = balances[msg.sender] - before;
// Slippage protection
require(bought >= minTokensOut, "Presale: Insufficient tokens received");
_applyReferral(msg.sender, referrer, bought);
emit TokensBought(address(0), msg.sender, referrer, spendedValue);
}
function _depositChecksAndEffects(
IERC20 token,
address to,
uint256 value,
bool isStableToken
) internal returns (uint256 chargeBack, uint256 spendedValue) {
require(stageIterator < stages.length, "Presale: is ended");
(uint256 tokensToTransfer, uint256 coinPrice) = _calculateAmount(
isStableToken,
value,
address(token)
);
(uint256 tokensToChargeBack, uint256 actualSpent) = _purchase(
token,
to,
coinPrice,
tokensToTransfer
);
// Calculate the total amount that should be charged back
chargeBack = tokensToChargeBack;
spendedValue = actualSpent;
// Add any remaining dust from rounding
uint256 totalCharged = spendedValue + chargeBack;
if (value > totalCharged) {
chargeBack += (value - totalCharged);
}
}
function _depositInteractions(
IERC20 token,
uint256 amount,
uint256 chargeBack,
uint256 spendedValue
) private {
token.safeTransferFrom(msg.sender, address(this), amount);
token.safeTransfer(protocolWallet, spendedValue);
if (chargeBack > 0) token.safeTransfer(msg.sender, chargeBack);
}
function _calculateAmount(
bool isStableToken,
uint256 value,
address tokenAddress
) private view returns (uint256 amount, uint256 price) {
if (isStableToken) {
// Get stablecoin price for validation (circuit breaker)
uint256 stablecoinPrice = _getStablecoinPrice(tokenAddress);
// Convert stablecoin value to USD using actual price
// value is in 6 decimals (stablecoin), stablecoinPrice is in 8 decimals
// Result should be in 8 decimals to match stage cost precision
uint256 usdValue = (value * stablecoinPrice) / (10 ** STABLE_TOKEN_DECIMALS);
// Calculate tokens based on stage cost
uint256 expectedAmount = usdValue / stages[stageIterator].cost;
return (expectedAmount, stablecoinPrice);
} else {
// For ETH, get price and convert to USD
uint256 ethPrice = _getLatestPrice();
// Convert input value to USD (8 decimals)
uint256 usdValue = (ethPrice * value) / (10 ** COIN_DECIMALS);
// Calculate tokens based on stage cost
uint256 expectedAmount = usdValue / stages[stageIterator].cost;
return (expectedAmount, ethPrice);
}
}
function _getLatestPrice() internal view returns (uint256) {
(
, // roundId - not needed for validation
int256 price,
, // startedAt - unused
uint256 updatedAt,
) = COIN_PRICE_FEED.latestRoundData();
require(price > 0, "Invalid price");
require(updatedAt > 0, "Round not complete");
require(block.timestamp - updatedAt <= 4 hours, "Stale price");
return uint256(price);
}
function _getStablecoinPrice(address tokenAddress) internal view returns (uint256) {
AggregatorV3Interface priceFeed;
// Select the appropriate price feed based on token address
if (tokenAddress == address(usdcToken)) {
priceFeed = USDC_PRICE_FEED;
} else if (tokenAddress == address(usdtToken)) {
priceFeed = USDT_PRICE_FEED;
} else {
revert("Unsupported stablecoin");
}
(
, // roundId
int256 price,
, // startedAt
uint256 updatedAt,
) = priceFeed.latestRoundData();
require(price > 0, "Invalid stablecoin price");
require(updatedAt > 0, "Round not complete");
require(block.timestamp - updatedAt <= 24 hours, "Stale stablecoin price");
uint256 stablePrice = uint256(price);
// Circuit breaker - revert if outside acceptable bounds
require(stablePrice >= MIN_STABLE_PRICE && stablePrice <= MAX_STABLE_PRICE,
"Stablecoin depeg detected");
return stablePrice;
}
function _purchase(
IERC20 token,
address to,
uint256 coinPrice,
uint256 amount
) private returns (uint256 tokensToChargeBack, uint256 spendedValue) {
StageData storage crtStage = stages[stageIterator];
if (uint(crtStage.amount) < amount) {
// Partial purchase
uint256 tokensToAllocate = crtStage.amount;
// Calculate USD value for the tokens to be allocated
uint256 usdValueForTokens = tokensToAllocate * crtStage.cost;
// Update balances and totals
balances[to] += tokensToAllocate;
totalTokensSold += tokensToAllocate;
totalSoldInUSD += usdValueForTokens;
// Calculate how much to charge back based on unused tokens
uint256 unusedTokens = amount - tokensToAllocate;
uint256 unusedUsdValue = unusedTokens * crtStage.cost;
// Convert USD values to appropriate token amounts for transfers
if (address(token) == address(0)) {
// For ETH: convert USD value to ETH amount
// usdValueForTokens is in 8 decimals, coinPrice is in 8 decimals
// Result should be in 18 decimals (ETH wei)
spendedValue = (usdValueForTokens * 1e18) / coinPrice;
tokensToChargeBack = (unusedUsdValue * 1e18) / coinPrice;
} else {
// For stablecoins: convert USD value back to stablecoin amount using actual price
// usdValueForTokens is in 8 decimals, coinPrice is in 8 decimals
// Result should be in 6 decimals (stablecoin)
spendedValue = (usdValueForTokens * (10 ** STABLE_TOKEN_DECIMALS)) / coinPrice;
tokensToChargeBack = (unusedUsdValue * (10 ** STABLE_TOKEN_DECIMALS)) / coinPrice;
}
// Move to next stage
crtStage.amount = 0;
if (stageIterator < stages.length - 1) {
stageIterator++;
emit StageUpdated(stageIterator);
} else {
// All stages exhausted - pause the contract
emit PresaleEnded(totalTokensSold, totalSoldInUSD);
_pause();
}
} else {
// Full purchase - stage has enough tokens
uint256 usdValueForTokens = amount * crtStage.cost;
// Update balances and totals
balances[to] += amount;
totalTokensSold += amount;
totalSoldInUSD += usdValueForTokens;
crtStage.amount -= uint160(amount);
// Convert USD value to appropriate token amount for transfers
if (address(token) == address(0)) {
// For ETH: convert USD value to ETH amount
// usdValueForTokens is in 8 decimals, coinPrice is in 8 decimals
// Result should be in 18 decimals (ETH wei)
spendedValue = (usdValueForTokens * 1e18) / coinPrice;
} else {
// For stablecoins: convert USD value back to stablecoin amount using actual price
// usdValueForTokens is in 8 decimals, coinPrice is in 8 decimals
// Result should be in 6 decimals (stablecoin)
spendedValue = (usdValueForTokens * (10 ** STABLE_TOKEN_DECIMALS)) / coinPrice;
}
tokensToChargeBack = 0;
}
// Check if current stage is exhausted after the purchase and advance if needed
if (stages[stageIterator].amount == 0) {
if (stageIterator < stages.length - 1) {
stageIterator++;
emit StageUpdated(stageIterator);
} else {
// All stages exhausted - pause the contract
emit PresaleEnded(totalTokensSold, totalSoldInUSD);
_pause();
}
}
}
/// @notice Verify EIP-712 signature for a purchase
function _verifyAllowlist(
address buyer,
uint256 amount,
uint256 minTokensOut,
address referrer,
uint256 nonce,
uint256 deadline,
uint8 tokenType,
bytes memory signature
) internal {
require(signature.length == 65, "Presale: invalid signature length");
require(block.timestamp <= deadline, "Presale: signature expired");
// Verify nonce
require(nonce == nonces[buyer], "Presale: invalid nonce");
// Build EIP-712 struct hash
bytes32 structHash = keccak256(
abi.encode(
ALLOW_TYPEHASH,
buyer,
amount,
minTokensOut,
referrer,
nonce,
deadline,
tokenType
)
);
// Compute digest and recover signer
bytes32 digest = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(digest, signature);
require(signer == SIGNER, "Presale: invalid signature");
// Increment nonce to prevent replay
nonces[buyer]++;
}
function _applyReferral(
address buyer,
address referrer,
uint256 tokensBought
) internal {
// Only proceed with valid referrals
if (referrer != address(0) && referrer != buyer && tokensBought > 0) {
// Check that referrer is valid (has tokens)
if (balances[referrer] <= 0) {
return; // Skip invalid referrers
}
// Calculate bonuses
uint256 buyerPurchaseBonus = tokensBought * refereeRate / 100; // 3% purchase bonus for buyer
uint256 referrerCommission = tokensBought * referrerRate / 100; // 7% commission for referrer
uint256 totalBonusNeeded = buyerPurchaseBonus + referrerCommission;
// Skip if no referral pool remaining
if (referralPoolRemaining == 0) {
return;
}
uint256 actualBuyerBonus;
uint256 actualReferrerCommission;
if (totalBonusNeeded <= referralPoolRemaining) {
actualBuyerBonus = buyerPurchaseBonus;
actualReferrerCommission = referrerCommission;
} else {
// Partial bonuses - distribute proportionally
// Maintain the 3:7 ratio between buyer bonus and referrer commission
uint256 totalRate = refereeRate + referrerRate; // 3 + 7 = 10
actualBuyerBonus = (referralPoolRemaining * refereeRate) / totalRate;
actualReferrerCommission = referralPoolRemaining - actualBuyerBonus;
}
// Update the referral pool
referralPoolRemaining -= (actualBuyerBonus + actualReferrerCommission);
// Credit purchase bonus to buyer (NOT tracked as referral earnings)
balances[buyer] += actualBuyerBonus;
// Credit commission to referrer (tracked as referral earnings)
referralEarnings[referrer] += actualReferrerCommission;
balances[referrer] += actualReferrerCommission;
// Track referral bonuses separately from actual sales
totalReferralDistributed += actualBuyerBonus + actualReferrerCommission;
// Emit events for tracking
emit ReferralReward(referrer, buyer, actualReferrerCommission, actualBuyerBonus);
emit ReferralBonusDistributed(actualBuyerBonus + actualReferrerCommission, totalReferralDistributed);
}
}
/// @notice Get total tokens distributed (purchased + referral bonuses)
function getTotalTokensDistributed() external view returns (uint256) {
return totalTokensSold + totalReferralDistributed;
}
/// @notice Get user's total balance (purchased + bonuses)
function getUserBalance(address user) external view returns (uint256) {
return balances[user];
}
/// @notice Get user's referral earnings
function getUserReferralEarnings(address user) external view returns (uint256) {
return referralEarnings[user];
}
/// @notice Get current stage information
function getCurrentStage() external view returns (uint256 stageId, uint256 amount, uint256 cost) {
require(stageIterator < stages.length, "Presale: ended");
StageData memory stage = stages[stageIterator];
return (stageIterator, stage.amount, stage.cost);
}
/// @notice Get stage information by ID
function getStage(uint256 stageId) external view returns (uint256 amount, uint256 cost) {
require(stageId < stages.length, "Presale: invalid stage");
StageData memory stage = stages[stageId];
return (stage.amount, stage.cost);
}
/// @notice Get total number of stages
function getTotalStages() external view returns (uint256) {
return stages.length;
}
/// @notice Check if presale has ended (all stages exhausted)
function isPresaleEnded() external view returns (bool) {
return paused() && stageIterator >= stages.length - 1 && stages[stageIterator].amount == 0;
}
/// @notice Calculate expected tokens for a deposit amount (for frontend use)
/// @param isStableToken true for USDC/USDT, false for ETH
/// @param depositAmount amount of tokens/ETH to deposit
/// @param tokenAddress address of the token (for stablecoins) or address(0) for ETH
/// @return expectedTokens estimated tokens to receive
/// @return actualPrice price used in calculation
function calculateExpectedTokens(
bool isStableToken,
uint256 depositAmount,
address tokenAddress
) external view returns (uint256 expectedTokens, uint256 actualPrice) {
require(stageIterator < stages.length, "Presale: ended");
return _calculateAmount(isStableToken, depositAmount, tokenAddress);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract AggregatorV3Interface","name":"COIN_PRICE_FEED_","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"USDC_PRICE_FEED_","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"USDT_PRICE_FEED_","type":"address"},{"internalType":"contract IERC20","name":"usdcToken_","type":"address"},{"internalType":"contract IERC20","name":"usdtToken_","type":"address"},{"internalType":"address","name":"signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"SafeTransferFromFailed","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalTokensSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSoldInUSD","type":"uint256"}],"name":"PresaleEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalBonuses","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTotal","type":"uint256"}],"name":"ReferralBonusDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldAmount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"ReferralPoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":true,"internalType":"address","name":"referee","type":"address"},{"indexed":false,"internalType":"uint256","name":"referrerReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refereeBonus","type":"uint256"}],"name":"ReferralReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stageId","type":"uint256"},{"indexed":false,"internalType":"uint160","name":"amount","type":"uint160"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"StageAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"currentStage","type":"uint256"}],"name":"StageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensBought","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"UserBalanceUpdated","type":"event"},{"inputs":[],"name":"ALLOW_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COIN_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COIN_PRICE_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_STABLE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_STABLE_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICEFEED_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STABLETOKEN_PRICE","outputs":[{"internalType":"int32","name":"","type":"int32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STABLE_TOKEN_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC_PRICE_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDT_PRICE_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint256","name":"cost","type":"uint256"}],"name":"addStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isStableToken","type":"bool"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"calculateExpectedTokens","outputs":[{"internalType":"uint256","name":"expectedTokens","type":"uint256"},{"internalType":"uint256","name":"actualPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minTokensOut","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"depositCoin","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minTokensOut","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"depositUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minTokensOut","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"depositUSDT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentStage","outputs":[{"internalType":"uint256","name":"stageId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stageId","type":"uint256"}],"name":"getStage","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalStages","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalTokensDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserReferralEarnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPresaleEnded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refereeRate","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referralEarnings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralPoolRemaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referrerRate","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stageIterator_","type":"uint256"}],"name":"setStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stageIterator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stages","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReferralDistributed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSoldInUSD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTokensSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdcToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdtToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610220604052348015610010575f5ffd5b5060405161648538038061648583398181016040528101906100329190610a50565b6040518060400160405280600a81526020017f45423150726573616c65000000000000000000000000000000000000000000008152506040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250335f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361010f575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016101069190610ae8565b60405180910390fd5b61011e8161077060201b60201c565b506101336002836107a660201b90919060201c565b610120818152505061014f6003826107a660201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a0818152505061018c6107f360201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1681525050505060016004819055505f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff160361023f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161023690610b5b565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036102ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102a490610bc3565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff160361031b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161031290610c2b565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610389576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161038090610c93565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036103f7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ee90610cfb565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610465576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161045c90610d63565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff166101608173ffffffffffffffffffffffffffffffffffffffff16815250508473ffffffffffffffffffffffffffffffffffffffff166101808173ffffffffffffffffffffffffffffffffffffffff16815250508373ffffffffffffffffffffffffffffffffffffffff166101a08173ffffffffffffffffffffffffffffffffffffffff16815250508273ffffffffffffffffffffffffffffffffffffffff166101c08173ffffffffffffffffffffffffffffffffffffffff16815250508173ffffffffffffffffffffffffffffffffffffffff166101e08173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff166102008173ffffffffffffffffffffffffffffffffffffffff1681525050600c6040518060400160405280620aae6073ffffffffffffffffffffffffffffffffffffffff1681526020016304417a40815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f0155602082015181600101555050600c60405180604001604052806210059073ffffffffffffffffffffffffffffffffffffffff168152602001630b5acca0815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f0155602082015181600101555050600c604051806040016040528062155cc073ffffffffffffffffffffffffffffffffffffffff1681526020016310411260815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f0155602082015181600101555050600c6040518060400160405280621ab3f073ffffffffffffffffffffffffffffffffffffffff1681526020016313ddc120815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f01556020820151816001015550506203f7a060058190555050505050505061120e565b60015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556107a38161084d60201b60201c565b50565b5f6020835110156107c7576107c08361090e60201b60201c565b90506107ed565b826107d78361097360201b60201c565b5f0190816107e59190610fbe565b5060ff5f1b90505b92915050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e0516101005146306040516020016108329594939291906110b4565b60405160208183030381529060405280519060200120905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b5f5f829050601f8151111561095a57826040517f305a27a9000000000000000000000000000000000000000000000000000000008152600401610951919061115b565b60405180910390fd5b805181610966906111a8565b5f1c175f1b915050919050565b5f819050919050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6109a982610980565b9050919050565b5f6109ba8261099f565b9050919050565b6109ca816109b0565b81146109d4575f5ffd5b50565b5f815190506109e5816109c1565b92915050565b5f6109f58261099f565b9050919050565b610a05816109eb565b8114610a0f575f5ffd5b50565b5f81519050610a20816109fc565b92915050565b610a2f8161099f565b8114610a39575f5ffd5b50565b5f81519050610a4a81610a26565b92915050565b5f5f5f5f5f5f60c08789031215610a6a57610a6961097c565b5b5f610a7789828a016109d7565b9650506020610a8889828a016109d7565b9550506040610a9989828a016109d7565b9450506060610aaa89828a01610a12565b9350506080610abb89828a01610a12565b92505060a0610acc89828a01610a3c565b9150509295509295509295565b610ae28161099f565b82525050565b5f602082019050610afb5f830184610ad9565b92915050565b5f82825260208201905092915050565b7f496e76616c6964207072696365206665656400000000000000000000000000005f82015250565b5f610b45601283610b01565b9150610b5082610b11565b602082019050919050565b5f6020820190508181035f830152610b7281610b39565b9050919050565b7f496e76616c6964205553444320707269636520666565640000000000000000005f82015250565b5f610bad601783610b01565b9150610bb882610b79565b602082019050919050565b5f6020820190508181035f830152610bda81610ba1565b9050919050565b7f496e76616c6964205553445420707269636520666565640000000000000000005f82015250565b5f610c15601783610b01565b9150610c2082610be1565b602082019050919050565b5f6020820190508181035f830152610c4281610c09565b9050919050565b7f496e76616c6964205553444320746f6b656e00000000000000000000000000005f82015250565b5f610c7d601283610b01565b9150610c8882610c49565b602082019050919050565b5f6020820190508181035f830152610caa81610c71565b9050919050565b7f496e76616c6964205553445420746f6b656e00000000000000000000000000005f82015250565b5f610ce5601283610b01565b9150610cf082610cb1565b602082019050919050565b5f6020820190508181035f830152610d1281610cd9565b9050919050565b7f496e76616c6964207369676e65720000000000000000000000000000000000005f82015250565b5f610d4d600e83610b01565b9150610d5882610d19565b602082019050919050565b5f6020820190508181035f830152610d7a81610d41565b9050919050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610dfc57607f821691505b602082108103610e0f57610e0e610db8565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302610e717fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610e36565b610e7b8683610e36565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f610ebf610eba610eb584610e93565b610e9c565b610e93565b9050919050565b5f819050919050565b610ed883610ea5565b610eec610ee482610ec6565b848454610e42565b825550505050565b5f5f905090565b610f03610ef4565b610f0e818484610ecf565b505050565b5b81811015610f3157610f265f82610efb565b600181019050610f14565b5050565b601f821115610f7657610f4781610e15565b610f5084610e27565b81016020851015610f5f578190505b610f73610f6b85610e27565b830182610f13565b50505b505050565b5f82821c905092915050565b5f610f965f1984600802610f7b565b1980831691505092915050565b5f610fae8383610f87565b9150826002028217905092915050565b610fc782610d81565b67ffffffffffffffff811115610fe057610fdf610d8b565b5b610fea8254610de5565b610ff5828285610f35565b5f60209050601f831160018114611026575f8415611014578287015190505b61101e8582610fa3565b865550611085565b601f19841661103486610e15565b5f5b8281101561105b57848901518255600182019150602085019450602081019050611036565b868310156110785784890151611074601f891682610f87565b8355505b6001600288020188555050505b505050505050565b5f819050919050565b61109f8161108d565b82525050565b6110ae81610e93565b82525050565b5f60a0820190506110c75f830188611096565b6110d46020830187611096565b6110e16040830186611096565b6110ee60608301856110a5565b6110fb6080830184610ad9565b9695505050505050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61112d82610d81565b6111378185610b01565b9350611147818560208601611105565b61115081611113565b840191505092915050565b5f6020820190508181035f8301526111738184611123565b905092915050565b5f81519050919050565b5f819050602082019050919050565b5f61119f825161108d565b80915050919050565b5f6111b28261117b565b826111bc84611185565b90506111c781611194565b92506020821015611207576112027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802610e36565b831692505b5050919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e0516102005161517a61130b5f395f81816110d301526121e401525f81816113d5015281816114e0015281816115110152818161160201528181611911015281816119cc01526131af01525f8181610c0801528181610ee901528181610f1a0152818161100b0152818161180e015281816118c9015261313401525f818161114d015261320201525f8181610c2c015261318701525f81816113b1015261341b01525f61287d01525f61284201525f61393d01525f61391c01525f6135dc01525f61363201525f61365b015261517a5ff3fe608060405260043610610292575f3560e01c80637f9aee9911610159578063ada346a1116100c0578063e30c397811610079578063e30c3978146109bb578063e6b2603b146109e5578063e737e33e146109fb578063eedbe31d14610a25578063f2fde38b14610a51578063f53b3f1c14610a7957610292565b8063ada346a11461089a578063ba680e56146108d7578063c07b528a14610901578063c23f3eb51461093d578063d434df7114610967578063df3e353b1461099157610292565b80639032c47e116101125780639032c47e146107a057806394457e13146107ca57806396554b47146107f45780639a6c59521461081e578063a98ad46c14610848578063ac64a3be1461087257610292565b80637f9aee991461069f5780638456cb59146106c9578063845ddcb2146106df57806384b0196e1461071c578063860956b61461074c5780638da5cb5b1461077657610292565b806349b6c89b116101fd57806363b20117116101b657806363b20117146105b95780636c619a08146105e3578063715018a61461060d57806379ba5097146106235780637decf27f146106395780637ecebe001461066357610292565b806349b6c89b146104ad5780634fdddc14146104d5578063582abd12146105115780635c975abb1461053b5780635dbae59f1461056557806363a059891461058f57610292565b80632f455ec71161024f5780632f455ec7146103b557806338aff6ae146103df5780633be00ab3146104095780633eb1d777146104335780633f4ba83a1461045b578063477348921461047157610292565b806306d6e63f146102965780631104f0f8146102c057806311eac855146102e857806315d992061461031257806327e235e31461033c5780632e32502014610378575b5f5ffd5b3480156102a1575f5ffd5b506102aa610a95565b6040516102b79190613b01565b60405180910390f35b3480156102cb575f5ffd5b506102e660048036038101906102e19190613b7f565b610aad565b005b3480156102f3575f5ffd5b506102fc610c06565b6040516103099190613c18565b60405180910390f35b34801561031d575f5ffd5b50610326610c2a565b6040516103339190613c51565b60405180910390f35b348015610347575f5ffd5b50610362600480360381019061035d9190613c94565b610c4e565b60405161036f9190613cce565b60405180910390f35b348015610383575f5ffd5b5061039e60048036038101906103999190613ce7565b610c63565b6040516103ac929190613d12565b60405180910390f35b3480156103c0575f5ffd5b506103c9610d00565b6040516103d69190613cce565b60405180910390f35b3480156103ea575f5ffd5b506103f3610d0c565b6040516104009190613d54565b60405180910390f35b348015610414575f5ffd5b5061041d610d11565b60405161042a9190613d54565b60405180910390f35b34801561043e575f5ffd5b5061045960048036038101906104549190613ce7565b610d16565b005b348015610466575f5ffd5b5061046f610da9565b005b34801561047c575f5ffd5b5061049760048036038101906104929190613c94565b610dbb565b6040516104a49190613cce565b60405180910390f35b3480156104b8575f5ffd5b506104d360048036038101906104ce9190613dce565b610e01565b005b3480156104e0575f5ffd5b506104fb60048036038101906104f69190613c94565b61108b565b6040516105089190613cce565b60405180910390f35b34801561051c575f5ffd5b506105256110d1565b6040516105329190613b01565b60405180910390f35b348015610546575f5ffd5b5061054f6110f5565b60405161055c9190613e7e565b60405180910390f35b348015610570575f5ffd5b5061057961110b565b6040516105869190613cce565b60405180910390f35b34801561059a575f5ffd5b506105a3611121565b6040516105b09190613eaf565b60405180910390f35b3480156105c4575f5ffd5b506105cd611145565b6040516105da9190613cce565b60405180910390f35b3480156105ee575f5ffd5b506105f761114b565b6040516106049190613c51565b60405180910390f35b348015610618575f5ffd5b5061062161116f565b005b34801561062e575f5ffd5b50610637611182565b005b348015610644575f5ffd5b5061064d611210565b60405161065a9190613e7e565b60405180910390f35b34801561066e575f5ffd5b5061068960048036038101906106849190613c94565b61126c565b6040516106969190613cce565b60405180910390f35b3480156106aa575f5ffd5b506106b3611281565b6040516106c09190613cce565b60405180910390f35b3480156106d4575f5ffd5b506106dd611287565b005b3480156106ea575f5ffd5b5061070560048036038101906107009190613ce7565b611299565b604051610713929190613d12565b60405180910390f35b348015610727575f5ffd5b506107306112c8565b6040516107439796959493929190614029565b60405180910390f35b348015610757575f5ffd5b5061076061136d565b60405161076d91906140c6565b60405180910390f35b348015610781575f5ffd5b5061078a611375565b6040516107979190613b01565b60405180910390f35b3480156107ab575f5ffd5b506107b461139c565b6040516107c19190613cce565b60405180910390f35b3480156107d5575f5ffd5b506107de6113a2565b6040516107eb9190613cce565b60405180910390f35b3480156107ff575f5ffd5b506108086113aa565b6040516108159190613d54565b60405180910390f35b348015610829575f5ffd5b506108326113af565b60405161083f9190613c51565b60405180910390f35b348015610853575f5ffd5b5061085c6113d3565b6040516108699190613c18565b60405180910390f35b34801561087d575f5ffd5b5061089860048036038101906108939190613dce565b6113f7565b005b3480156108a5575f5ffd5b506108c060048036038101906108bb9190614109565b611682565b6040516108ce929190613d12565b60405180910390f35b3480156108e2575f5ffd5b506108eb6116e4565b6040516108f89190613cce565b60405180910390f35b34801561090c575f5ffd5b5061092760048036038101906109229190613c94565b6116ea565b6040516109349190613cce565b60405180910390f35b348015610948575f5ffd5b506109516116ff565b60405161095e9190613cce565b60405180910390f35b348015610972575f5ffd5b5061097b611707565b6040516109889190613d54565b60405180910390f35b34801561099c575f5ffd5b506109a561170c565b6040516109b29190613d54565b60405180910390f35b3480156109c6575f5ffd5b506109cf611711565b6040516109dc9190613b01565b60405180910390f35b3480156109f0575f5ffd5b506109f9611739565b005b348015610a06575f5ffd5b50610a0f611a16565b604051610a1c9190613cce565b60405180910390f35b348015610a30575f5ffd5b50610a39611a1c565b604051610a4893929190614159565b60405180910390f35b348015610a5c575f5ffd5b50610a776004803603810190610a729190613c94565b611ac3565b005b610a936004803603810190610a8e919061418e565b611b6f565b005b73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f781565b610ab5611efb565b5f8273ffffffffffffffffffffffffffffffffffffffff1611610b0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b049061425c565b60405180910390fd5b5f8111610b4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b46906142c4565b60405180910390fd5b600c60405180604001604052808473ffffffffffffffffffffffffffffffffffffffff16815260200183815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f01556020820151816001015550507ffbd41442955182d1c148bcc060b4629740683ee8db610592f744d316364eb0346001600c80549050610be9919061430f565b8383604051610bfa93929190614351565b60405180910390a15050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b600d602052805f5260405f205f915090505481565b5f5f600c805490508310610cac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca3906143d0565b60405180910390fd5b5f600c8481548110610cc157610cc06143ee565b5b905f5260205f2090600202016040518060400160405290815f82015481526020016001820154815250509050805f015181602001519250925050915091565b5f600c80549050905090565b601281565b600681565b610d1e611efb565b80600c805490501015610d66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5d90614465565b60405180910390fd5b80600b819055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051610d9e9190613cce565b60405180910390a150565b610db1611efb565b610db9611f82565b565b5f600d5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b610e09611fe4565b610e1161202a565b610ea13387878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054885f89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f610f117f0000000000000000000000000000000000000000000000000000000000000000338b60016122cf565b91509150610f417f00000000000000000000000000000000000000000000000000000000000000008a8484612382565b5f83600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054610f8b919061430f565b905088811015610fd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fc7906144f3565b60405180910390fd5b610fdb338983612428565b8773ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce8560405161106f9190613cce565b60405180910390a450505050611083612796565b505050505050565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f600160149054906101000a900460ff16905090565b5f60065460095461111c9190614511565b905090565b7f2124daf46b0791b72e25c8132dd17a0080ab34f1da9587edb2683a5f2715811681565b60095481565b7f000000000000000000000000000000000000000000000000000000000000000081565b611177611efb565b6111805f6127a0565b565b5f61118b6127d0565b90508073ffffffffffffffffffffffffffffffffffffffff166111ac611711565b73ffffffffffffffffffffffffffffffffffffffff161461120457806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016111fb9190613b01565b60405180910390fd5b61120d816127a0565b50565b5f6112196110f5565b801561123857506001600c80549050611232919061430f565b600b5410155b801561126757505f600c600b5481548110611256576112556143ee565b5b905f5260205f2090600202015f0154145b905090565b6008602052805f5260405f205f915090505481565b600a5481565b61128f611efb565b6112976127d7565b565b600c81815481106112a8575f80fd5b905f5260205f2090600202015f91509050805f0154908060010154905082565b5f6060805f5f5f60606112d9612839565b6112e1612874565b46305f5f1b5f67ffffffffffffffff811115611300576112ff614544565b5b60405190808252806020026020018201604052801561132e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6305f5e10081565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60055481565b6305a995c081565b600381565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6113ff611fe4565b61140761202a565b6114983387878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205488600189898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f6115087f0000000000000000000000000000000000000000000000000000000000000000338b60016122cf565b915091506115387f00000000000000000000000000000000000000000000000000000000000000008a8484612382565b5f83600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054611582919061430f565b9050888110156115c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115be906144f3565b60405180910390fd5b6115d2338983612428565b8773ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce856040516116669190613cce565b60405180910390a45050505061167a612796565b505050505050565b5f5f600c80549050600b54106116cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c4906145bb565b60405180910390fd5b6116d88585856128af565b91509150935093915050565b600b5481565b6007602052805f5260405f205f915090505481565b6306422c4081565b600881565b600781565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611741611efb565b5f4790505f81111561180b575f73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f773ffffffffffffffffffffffffffffffffffffffff168260405161178690614606565b5f6040518083038185875af1925050503d805f81146117c0576040519150601f19603f3d011682016040523d82523d5f602084013e6117c5565b606091505b5050905080611809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161180090614664565b60405180910390fd5b505b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016118659190613b01565b602060405180830381865afa158015611880573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118a49190614696565b90505f81111561190e5761190d73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016119689190613b01565b602060405180830381865afa158015611983573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119a79190614696565b90505f811115611a1157611a1073f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b505050565b60065481565b5f5f5f600c80549050600b5410611a68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5f906145bb565b60405180910390fd5b5f600c600b5481548110611a7f57611a7e6143ee565b5b905f5260205f2090600202016040518060400160405290815f82015481526020016001820154815250509050600b54815f0151826020015193509350935050909192565b611acb611efb565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611b2a611375565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611b77611fe4565b611b7f61202a565b611c103334878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205488600289898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f611c5f5f33345f6122cf565b915091505f73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f773ffffffffffffffffffffffffffffffffffffffff1682604051611c9c90614606565b5f6040518083038185875af1925050503d805f8114611cd6576040519150601f19603f3d011682016040523d82523d5f602084013e611cdb565b606091505b5050905080611d1f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d169061470b565b60405180910390fd5b5f831115611dd1573373ffffffffffffffffffffffffffffffffffffffff1683604051611d4b90614606565b5f6040518083038185875af1925050503d805f8114611d85576040519150601f19603f3d011682016040523d82523d5f602084013e611d8a565b606091505b50508091505080611dd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dc79061470b565b60405180910390fd5b5b5f84600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054611e1b919061430f565b905089811015611e60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e57906144f3565b60405180910390fd5b611e6b338a83612428565b8873ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce86604051611edf9190613cce565b60405180910390a45050505050611ef4612796565b5050505050565b611f036127d0565b73ffffffffffffffffffffffffffffffffffffffff16611f21611375565b73ffffffffffffffffffffffffffffffffffffffff1614611f8057611f446127d0565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401611f779190613b01565b60405180910390fd5b565b611f8a6129f2565b5f600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611fcd6127d0565b604051611fda9190613b01565b60405180910390a1565b600260045403612020576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600481905550565b6120326110f5565b15612069576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60418151146120af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a690614799565b60405180910390fd5b824211156120f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e990614801565b60405180910390fd5b60085f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20548414612171576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216890614869565b60405180910390fd5b5f7f2124daf46b0791b72e25c8132dd17a0080ab34f1da9587edb2683a5f27158116898989898989896040516020016121b1989796959493929190614887565b6040516020818303038152906040528051906020012090505f6121d382612a32565b90505f6121e08285612a4b565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612270576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122679061494d565b60405180910390fd5b60085f8c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8154809291906122bd9061496b565b91905055505050505050505050505050565b5f5f600c80549050600b541061231a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612311906149fc565b60405180910390fd5b5f5f61232785878a6128af565b915091505f5f6123398a8a8587612a75565b915091508195508094505f86866123509190614511565b905080891115612374578089612366919061430f565b876123719190614511565b96505b505050505094509492505050565b6123af3330858773ffffffffffffffffffffffffffffffffffffffff16612f2a909392919063ffffffff16565b6123ee73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7828673ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5f8211156124225761242133838673ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561249057508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561249b57505f81115b15612790575f600d5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541115612791575f6064600360ff16836124f89190614a1a565b6125029190614a88565b90505f6064600760ff16846125179190614a1a565b6125219190614a88565b90505f81836125309190614511565b90505f6005540361254357505050612791565b5f5f60055483116125595784915083905061259e565b5f600760036125689190614ab8565b60ff16905080600360ff166005546125809190614a1a565b61258a9190614a88565b92508260055461259a919061430f565b9150505b80826125aa9190614511565b60055f8282546125ba919061430f565b9250508190555081600d5f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461260d9190614511565b925050819055508060075f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546126609190614511565b9250508190555080600d5f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546126b39190614511565b9250508190555080826126c69190614511565b60065f8282546126d69190614511565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fbd7e5be34537a425747cf06d84eca4d59c865e2002b7d5f36f14558bdc5ae8cd838560405161273c929190613d12565b60405180910390a37f67eb7a0c6462c89a739c533687df56df0c880a810c86597f6258a005582343fe81836127719190614511565b600654604051612782929190613d12565b60405180910390a150505050505b5b505050565b6001600481905550565b60015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556127cd81612fc2565b50565b5f33905090565b6127df61202a565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586128226127d0565b60405161282f9190613b01565b60405180910390a1565b606061286f60027f000000000000000000000000000000000000000000000000000000000000000061308390919063ffffffff16565b905090565b60606128aa60037f000000000000000000000000000000000000000000000000000000000000000061308390919063ffffffff16565b905090565b5f5f841561292c575f6128c184613130565b90505f6006600a6128d29190614c1b565b82876128de9190614a1a565b6128e89190614a88565b90505f600c600b5481548110612901576129006143ee565b5b905f5260205f209060020201600101548261291c9190614a88565b905080839450945050505061299c565b5f612935613416565b90505f6012600a6129469190614c1b565b86836129529190614a1a565b61295c9190614a88565b90505f600c600b5481548110612975576129746143ee565b5b905f5260205f20906002020160010154826129909190614a88565b90508083945094505050505b935093915050565b6129b78363a9059cbb60e01b8484613589565b6129ed576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b6129fa6110f5565b612a30576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f612a44612a3e6135d9565b8361368f565b9050919050565b5f5f5f5f612a5986866136cf565b925092509250612a698282613724565b82935050505092915050565b5f5f5f600c600b5481548110612a8e57612a8d6143ee565b5b905f5260205f209060020201905083815f01541015612cf4575f815f015490505f826001015482612abf9190614a1a565b905081600d5f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254612b0d9190614511565b925050819055508160095f828254612b259190614511565b9250508190555080600a5f828254612b3d9190614511565b925050819055505f8287612b51919061430f565b90505f846001015482612b649190614a1a565b90505f73ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1603612be05788670de0b6b3a764000084612bae9190614a1a565b612bb89190614a88565b955088670de0b6b3a764000082612bcf9190614a1a565b612bd99190614a88565b9650612c2d565b886006600a612bef9190614c1b565b84612bfa9190614a1a565b612c049190614a88565b9550886006600a612c159190614c1b565b82612c209190614a1a565b612c2a9190614a88565b96505b5f855f01819055506001600c80549050612c47919061430f565b600b541015612ca557600b5f815480929190612c629061496b565b91905055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051612c989190613cce565b60405180910390a1612ceb565b7fb4e6cb40663c1ac63bcd620dbe3d98c44526baa45e310f545f425ebaab36a293600954600a54604051612cda929190613d12565b60405180910390a1612cea6127d7565b5b50505050612e3e565b5f816001015485612d059190614a1a565b905084600d5f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254612d539190614511565b925050819055508460095f828254612d6b9190614511565b9250508190555080600a5f828254612d839190614511565b925050819055508473ffffffffffffffffffffffffffffffffffffffff16825f015f828254612db2919061430f565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1603612e125785670de0b6b3a764000082612e019190614a1a565b612e0b9190614a88565b9250612e39565b856006600a612e219190614c1b565b82612e2c9190614a1a565b612e369190614a88565b92505b5f9350505b5f600c600b5481548110612e5557612e546143ee565b5b905f5260205f2090600202015f015403612f20576001600c80549050612e7b919061430f565b600b541015612ed957600b5f815480929190612e969061496b565b91905055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051612ecc9190613cce565b60405180910390a1612f1f565b7fb4e6cb40663c1ac63bcd620dbe3d98c44526baa45e310f545f425ebaab36a293600954600a54604051612f0e929190613d12565b60405180910390a1612f1e6127d7565b5b5b5094509492505050565b5f6323b872dd60e01b90505f60405182815285600482015284602482015283604482015260205f6064835f8b5af191508115612f82573d5f8114612f795760015f5114601f3d11169250612f80565b5f883b1192505b505b5080612fba576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b606060ff5f1b831461309f5761309883613886565b905061312a565b8180546130ab90614c92565b80601f01602080910402602001604051908101604052809291908181526020018280546130d790614c92565b80156131225780601f106130f957610100808354040283529160200191613122565b820191905f5260205f20905b81548152906001019060200180831161310557829003601f168201915b505050505090505b92915050565b5f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036131ad577f00000000000000000000000000000000000000000000000000000000000000009050613264565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613228577f00000000000000000000000000000000000000000000000000000000000000009050613263565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161325a90614d0c565b60405180910390fd5b5b5f5f8273ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156132af573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d39190614d9c565b509350509250505f821361331c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161331390614e5d565b60405180910390fd5b5f811161335e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161335590614ec5565b60405180910390fd5b62015180814261336e919061430f565b11156133af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133a690614f2d565b60405180910390fd5b5f8290506305a995c081101580156133cb57506306422c408111155b61340a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161340190614f95565b60405180910390fd5b80945050505050919050565b5f5f5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613482573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134a69190614d9c565b509350509250505f82136134ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016134e690614ffd565b60405180910390fd5b5f8111613531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161352890614ec5565b60405180910390fd5b6138408142613540919061430f565b1115613581576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161357890615065565b60405180910390fd5b819250505090565b5f60405184815283600482015282602482015260205f6044835f8a5af1915081156135d0573d5f81146135c75760015f5114601f3d111692506135ce565b5f873b1192505b505b50949350505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561365457507f000000000000000000000000000000000000000000000000000000000000000046145b15613681577f0000000000000000000000000000000000000000000000000000000000000000905061368c565b6136896138f8565b90505b90565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f5f5f604184510361370f575f5f5f602087015192506040870151915060608701515f1a90506137018882858561398d565b95509550955050505061371d565b5f600285515f1b9250925092505b9250925092565b5f600381111561373757613736615083565b5b82600381111561374a57613749615083565b5b0315613882576001600381111561376457613763615083565b5b82600381111561377757613776615083565b5b036137ae576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156137c2576137c1615083565b5b8260038111156137d5576137d4615083565b5b0361381957805f1c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016138109190613cce565b60405180910390fd5b60038081111561382c5761382b615083565b5b82600381111561383f5761383e615083565b5b0361388157806040517fd78bce0c0000000000000000000000000000000000000000000000000000000081526004016138789190613eaf565b60405180910390fd5b5b5050565b60605f61389283613a74565b90505f602067ffffffffffffffff8111156138b0576138af614544565b5b6040519080825280601f01601f1916602001820160405280156138e25781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000046306040516020016139729594939291906150b0565b60405160208183030381529060405280519060200120905090565b5f5f5f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c11156139c9575f600385925092509250613a6a565b5f6001888888886040515f81526020016040526040516139ec9493929190615101565b6020604051602081039080840390855afa158015613a0c573d5f5f3e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613a5d575f60015f5f1b93509350935050613a6a565b805f5f5f1b935093509350505b9450945094915050565b5f5f60ff835f1c169050601f811115613ab9576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613aeb82613ac2565b9050919050565b613afb81613ae1565b82525050565b5f602082019050613b145f830184613af2565b92915050565b5f5ffd5b5f5ffd5b613b2b81613ac2565b8114613b35575f5ffd5b50565b5f81359050613b4681613b22565b92915050565b5f819050919050565b613b5e81613b4c565b8114613b68575f5ffd5b50565b5f81359050613b7981613b55565b92915050565b5f5f60408385031215613b9557613b94613b1a565b5b5f613ba285828601613b38565b9250506020613bb385828601613b6b565b9150509250929050565b5f819050919050565b5f613be0613bdb613bd684613ac2565b613bbd565b613ac2565b9050919050565b5f613bf182613bc6565b9050919050565b5f613c0282613be7565b9050919050565b613c1281613bf8565b82525050565b5f602082019050613c2b5f830184613c09565b92915050565b5f613c3b82613be7565b9050919050565b613c4b81613c31565b82525050565b5f602082019050613c645f830184613c42565b92915050565b613c7381613ae1565b8114613c7d575f5ffd5b50565b5f81359050613c8e81613c6a565b92915050565b5f60208284031215613ca957613ca8613b1a565b5b5f613cb684828501613c80565b91505092915050565b613cc881613b4c565b82525050565b5f602082019050613ce15f830184613cbf565b92915050565b5f60208284031215613cfc57613cfb613b1a565b5b5f613d0984828501613b6b565b91505092915050565b5f604082019050613d255f830185613cbf565b613d326020830184613cbf565b9392505050565b5f60ff82169050919050565b613d4e81613d39565b82525050565b5f602082019050613d675f830184613d45565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613d8e57613d8d613d6d565b5b8235905067ffffffffffffffff811115613dab57613daa613d71565b5b602083019150836001820283011115613dc757613dc6613d75565b5b9250929050565b5f5f5f5f5f5f60a08789031215613de857613de7613b1a565b5b5f613df589828a01613b6b565b9650506020613e0689828a01613b6b565b9550506040613e1789828a01613c80565b9450506060613e2889828a01613b6b565b935050608087013567ffffffffffffffff811115613e4957613e48613b1e565b5b613e5589828a01613d79565b92509250509295509295509295565b5f8115159050919050565b613e7881613e64565b82525050565b5f602082019050613e915f830184613e6f565b92915050565b5f819050919050565b613ea981613e97565b82525050565b5f602082019050613ec25f830184613ea0565b92915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b613efc81613ec8565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613f4482613f02565b613f4e8185613f0c565b9350613f5e818560208601613f1c565b613f6781613f2a565b840191505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b613fa481613b4c565b82525050565b5f613fb58383613f9b565b60208301905092915050565b5f602082019050919050565b5f613fd782613f72565b613fe18185613f7c565b9350613fec83613f8c565b805f5b8381101561401c5781516140038882613faa565b975061400e83613fc1565b925050600181019050613fef565b5085935050505092915050565b5f60e08201905061403c5f83018a613ef3565b818103602083015261404e8189613f3a565b905081810360408301526140628188613f3a565b90506140716060830187613cbf565b61407e6080830186613af2565b61408b60a0830185613ea0565b81810360c083015261409d8184613fcd565b905098975050505050505050565b5f8160030b9050919050565b6140c0816140ab565b82525050565b5f6020820190506140d95f8301846140b7565b92915050565b6140e881613e64565b81146140f2575f5ffd5b50565b5f81359050614103816140df565b92915050565b5f5f5f606084860312156141205761411f613b1a565b5b5f61412d868287016140f5565b935050602061413e86828701613b6b565b925050604061414f86828701613c80565b9150509250925092565b5f60608201905061416c5f830186613cbf565b6141796020830185613cbf565b6141866040830184613cbf565b949350505050565b5f5f5f5f5f608086880312156141a7576141a6613b1a565b5b5f6141b488828901613b6b565b95505060206141c588828901613c80565b94505060406141d688828901613b6b565b935050606086013567ffffffffffffffff8111156141f7576141f6613b1e565b5b61420388828901613d79565b92509250509295509295909350565b7f50726573616c653a20616d6f756e74206d757374206265203e300000000000005f82015250565b5f614246601a83613f0c565b915061425182614212565b602082019050919050565b5f6020820190508181035f8301526142738161423a565b9050919050565b7f50726573616c653a20636f7374206d757374206265203e3000000000000000005f82015250565b5f6142ae601883613f0c565b91506142b98261427a565b602082019050919050565b5f6020820190508181035f8301526142db816142a2565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61431982613b4c565b915061432483613b4c565b925082820390508181111561433c5761433b6142e2565b5b92915050565b61434b81613ac2565b82525050565b5f6060820190506143645f830186613cbf565b6143716020830185614342565b61437e6040830184613cbf565b949350505050565b7f50726573616c653a20696e76616c6964207374616765000000000000000000005f82015250565b5f6143ba601683613f0c565b91506143c582614386565b602082019050919050565b5f6020820190508181035f8301526143e7816143ae565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f50726573616c653a2057726f6e67206974657261746f720000000000000000005f82015250565b5f61444f601783613f0c565b915061445a8261441b565b602082019050919050565b5f6020820190508181035f83015261447c81614443565b9050919050565b7f50726573616c653a20496e73756666696369656e7420746f6b656e73207265635f8201527f6569766564000000000000000000000000000000000000000000000000000000602082015250565b5f6144dd602583613f0c565b91506144e882614483565b604082019050919050565b5f6020820190508181035f83015261450a816144d1565b9050919050565b5f61451b82613b4c565b915061452683613b4c565b925082820190508082111561453e5761453d6142e2565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f50726573616c653a20656e6465640000000000000000000000000000000000005f82015250565b5f6145a5600e83613f0c565b91506145b082614571565b602082019050919050565b5f6020820190508181035f8301526145d281614599565b9050919050565b5f81905092915050565b50565b5f6145f15f836145d9565b91506145fc826145e3565b5f82019050919050565b5f614610826145e6565b9150819050919050565b7f5265736375653a20455448207472616e73666572206661696c656400000000005f82015250565b5f61464e601b83613f0c565b91506146598261461a565b602082019050919050565b5f6020820190508181035f83015261467b81614642565b9050919050565b5f8151905061469081613b55565b92915050565b5f602082840312156146ab576146aa613b1a565b5b5f6146b884828501614682565b91505092915050565b7f50726573616c653a20436f696e207472616e73666572206661696c65640000005f82015250565b5f6146f5601d83613f0c565b9150614700826146c1565b602082019050919050565b5f6020820190508181035f830152614722816146e9565b9050919050565b7f50726573616c653a20696e76616c6964207369676e6174757265206c656e67745f8201527f6800000000000000000000000000000000000000000000000000000000000000602082015250565b5f614783602183613f0c565b915061478e82614729565b604082019050919050565b5f6020820190508181035f8301526147b081614777565b9050919050565b7f50726573616c653a207369676e617475726520657870697265640000000000005f82015250565b5f6147eb601a83613f0c565b91506147f6826147b7565b602082019050919050565b5f6020820190508181035f830152614818816147df565b9050919050565b7f50726573616c653a20696e76616c6964206e6f6e6365000000000000000000005f82015250565b5f614853601683613f0c565b915061485e8261481f565b602082019050919050565b5f6020820190508181035f83015261488081614847565b9050919050565b5f6101008201905061489b5f83018b613ea0565b6148a8602083018a613af2565b6148b56040830189613cbf565b6148c26060830188613cbf565b6148cf6080830187613af2565b6148dc60a0830186613cbf565b6148e960c0830185613cbf565b6148f660e0830184613d45565b9998505050505050505050565b7f50726573616c653a20696e76616c6964207369676e61747572650000000000005f82015250565b5f614937601a83613f0c565b915061494282614903565b602082019050919050565b5f6020820190508181035f8301526149648161492b565b9050919050565b5f61497582613b4c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149a7576149a66142e2565b5b600182019050919050565b7f50726573616c653a20697320656e6465640000000000000000000000000000005f82015250565b5f6149e6601183613f0c565b91506149f1826149b2565b602082019050919050565b5f6020820190508181035f830152614a13816149da565b9050919050565b5f614a2482613b4c565b9150614a2f83613b4c565b9250828202614a3d81613b4c565b91508282048414831517614a5457614a536142e2565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614a9282613b4c565b9150614a9d83613b4c565b925082614aad57614aac614a5b565b5b828204905092915050565b5f614ac282613d39565b9150614acd83613d39565b9250828201905060ff811115614ae657614ae56142e2565b5b92915050565b5f8160011c9050919050565b5f5f8291508390505b6001851115614b4157808604811115614b1d57614b1c6142e2565b5b6001851615614b2c5780820291505b8081029050614b3a85614aec565b9450614b01565b94509492505050565b5f82614b595760019050614c14565b81614b66575f9050614c14565b8160018114614b7c5760028114614b8657614bb5565b6001915050614c14565b60ff841115614b9857614b976142e2565b5b8360020a915084821115614baf57614bae6142e2565b5b50614c14565b5060208310610133831016604e8410600b8410161715614bea5782820a905083811115614be557614be46142e2565b5b614c14565b614bf78484846001614af8565b92509050818404811115614c0e57614c0d6142e2565b5b81810290505b9392505050565b5f614c2582613b4c565b9150614c3083613d39565b9250614c5d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484614b4a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614ca957607f821691505b602082108103614cbc57614cbb614c65565b5b50919050565b7f556e737570706f7274656420737461626c65636f696e000000000000000000005f82015250565b5f614cf6601683613f0c565b9150614d0182614cc2565b602082019050919050565b5f6020820190508181035f830152614d2381614cea565b9050919050565b5f69ffffffffffffffffffff82169050919050565b614d4881614d2a565b8114614d52575f5ffd5b50565b5f81519050614d6381614d3f565b92915050565b5f819050919050565b614d7b81614d69565b8114614d85575f5ffd5b50565b5f81519050614d9681614d72565b92915050565b5f5f5f5f5f60a08688031215614db557614db4613b1a565b5b5f614dc288828901614d55565b9550506020614dd388828901614d88565b9450506040614de488828901614682565b9350506060614df588828901614682565b9250506080614e0688828901614d55565b9150509295509295909350565b7f496e76616c696420737461626c65636f696e20707269636500000000000000005f82015250565b5f614e47601883613f0c565b9150614e5282614e13565b602082019050919050565b5f6020820190508181035f830152614e7481614e3b565b9050919050565b7f526f756e64206e6f7420636f6d706c65746500000000000000000000000000005f82015250565b5f614eaf601283613f0c565b9150614eba82614e7b565b602082019050919050565b5f6020820190508181035f830152614edc81614ea3565b9050919050565b7f5374616c6520737461626c65636f696e207072696365000000000000000000005f82015250565b5f614f17601683613f0c565b9150614f2282614ee3565b602082019050919050565b5f6020820190508181035f830152614f4481614f0b565b9050919050565b7f537461626c65636f696e206465706567206465746563746564000000000000005f82015250565b5f614f7f601983613f0c565b9150614f8a82614f4b565b602082019050919050565b5f6020820190508181035f830152614fac81614f73565b9050919050565b7f496e76616c6964207072696365000000000000000000000000000000000000005f82015250565b5f614fe7600d83613f0c565b9150614ff282614fb3565b602082019050919050565b5f6020820190508181035f83015261501481614fdb565b9050919050565b7f5374616c652070726963650000000000000000000000000000000000000000005f82015250565b5f61504f600b83613f0c565b915061505a8261501b565b602082019050919050565b5f6020820190508181035f83015261507c81615043565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60a0820190506150c35f830188613ea0565b6150d06020830187613ea0565b6150dd6040830186613ea0565b6150ea6060830185613cbf565b6150f76080830184613af2565b9695505050505050565b5f6080820190506151145f830187613ea0565b6151216020830186613d45565b61512e6040830185613ea0565b61513b6060830184613ea0565b9594505050505056fea264697066735822122037e1a3a162c218693e703a897e7337a0bc661dd1003e5a7738bb7a7e4084213864736f6c634300081c00330000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b84190000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f60000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000b1170023799c4adc7b6e6c6bb30cf84908ea8f44
Deployed Bytecode
0x608060405260043610610292575f3560e01c80637f9aee9911610159578063ada346a1116100c0578063e30c397811610079578063e30c3978146109bb578063e6b2603b146109e5578063e737e33e146109fb578063eedbe31d14610a25578063f2fde38b14610a51578063f53b3f1c14610a7957610292565b8063ada346a11461089a578063ba680e56146108d7578063c07b528a14610901578063c23f3eb51461093d578063d434df7114610967578063df3e353b1461099157610292565b80639032c47e116101125780639032c47e146107a057806394457e13146107ca57806396554b47146107f45780639a6c59521461081e578063a98ad46c14610848578063ac64a3be1461087257610292565b80637f9aee991461069f5780638456cb59146106c9578063845ddcb2146106df57806384b0196e1461071c578063860956b61461074c5780638da5cb5b1461077657610292565b806349b6c89b116101fd57806363b20117116101b657806363b20117146105b95780636c619a08146105e3578063715018a61461060d57806379ba5097146106235780637decf27f146106395780637ecebe001461066357610292565b806349b6c89b146104ad5780634fdddc14146104d5578063582abd12146105115780635c975abb1461053b5780635dbae59f1461056557806363a059891461058f57610292565b80632f455ec71161024f5780632f455ec7146103b557806338aff6ae146103df5780633be00ab3146104095780633eb1d777146104335780633f4ba83a1461045b578063477348921461047157610292565b806306d6e63f146102965780631104f0f8146102c057806311eac855146102e857806315d992061461031257806327e235e31461033c5780632e32502014610378575b5f5ffd5b3480156102a1575f5ffd5b506102aa610a95565b6040516102b79190613b01565b60405180910390f35b3480156102cb575f5ffd5b506102e660048036038101906102e19190613b7f565b610aad565b005b3480156102f3575f5ffd5b506102fc610c06565b6040516103099190613c18565b60405180910390f35b34801561031d575f5ffd5b50610326610c2a565b6040516103339190613c51565b60405180910390f35b348015610347575f5ffd5b50610362600480360381019061035d9190613c94565b610c4e565b60405161036f9190613cce565b60405180910390f35b348015610383575f5ffd5b5061039e60048036038101906103999190613ce7565b610c63565b6040516103ac929190613d12565b60405180910390f35b3480156103c0575f5ffd5b506103c9610d00565b6040516103d69190613cce565b60405180910390f35b3480156103ea575f5ffd5b506103f3610d0c565b6040516104009190613d54565b60405180910390f35b348015610414575f5ffd5b5061041d610d11565b60405161042a9190613d54565b60405180910390f35b34801561043e575f5ffd5b5061045960048036038101906104549190613ce7565b610d16565b005b348015610466575f5ffd5b5061046f610da9565b005b34801561047c575f5ffd5b5061049760048036038101906104929190613c94565b610dbb565b6040516104a49190613cce565b60405180910390f35b3480156104b8575f5ffd5b506104d360048036038101906104ce9190613dce565b610e01565b005b3480156104e0575f5ffd5b506104fb60048036038101906104f69190613c94565b61108b565b6040516105089190613cce565b60405180910390f35b34801561051c575f5ffd5b506105256110d1565b6040516105329190613b01565b60405180910390f35b348015610546575f5ffd5b5061054f6110f5565b60405161055c9190613e7e565b60405180910390f35b348015610570575f5ffd5b5061057961110b565b6040516105869190613cce565b60405180910390f35b34801561059a575f5ffd5b506105a3611121565b6040516105b09190613eaf565b60405180910390f35b3480156105c4575f5ffd5b506105cd611145565b6040516105da9190613cce565b60405180910390f35b3480156105ee575f5ffd5b506105f761114b565b6040516106049190613c51565b60405180910390f35b348015610618575f5ffd5b5061062161116f565b005b34801561062e575f5ffd5b50610637611182565b005b348015610644575f5ffd5b5061064d611210565b60405161065a9190613e7e565b60405180910390f35b34801561066e575f5ffd5b5061068960048036038101906106849190613c94565b61126c565b6040516106969190613cce565b60405180910390f35b3480156106aa575f5ffd5b506106b3611281565b6040516106c09190613cce565b60405180910390f35b3480156106d4575f5ffd5b506106dd611287565b005b3480156106ea575f5ffd5b5061070560048036038101906107009190613ce7565b611299565b604051610713929190613d12565b60405180910390f35b348015610727575f5ffd5b506107306112c8565b6040516107439796959493929190614029565b60405180910390f35b348015610757575f5ffd5b5061076061136d565b60405161076d91906140c6565b60405180910390f35b348015610781575f5ffd5b5061078a611375565b6040516107979190613b01565b60405180910390f35b3480156107ab575f5ffd5b506107b461139c565b6040516107c19190613cce565b60405180910390f35b3480156107d5575f5ffd5b506107de6113a2565b6040516107eb9190613cce565b60405180910390f35b3480156107ff575f5ffd5b506108086113aa565b6040516108159190613d54565b60405180910390f35b348015610829575f5ffd5b506108326113af565b60405161083f9190613c51565b60405180910390f35b348015610853575f5ffd5b5061085c6113d3565b6040516108699190613c18565b60405180910390f35b34801561087d575f5ffd5b5061089860048036038101906108939190613dce565b6113f7565b005b3480156108a5575f5ffd5b506108c060048036038101906108bb9190614109565b611682565b6040516108ce929190613d12565b60405180910390f35b3480156108e2575f5ffd5b506108eb6116e4565b6040516108f89190613cce565b60405180910390f35b34801561090c575f5ffd5b5061092760048036038101906109229190613c94565b6116ea565b6040516109349190613cce565b60405180910390f35b348015610948575f5ffd5b506109516116ff565b60405161095e9190613cce565b60405180910390f35b348015610972575f5ffd5b5061097b611707565b6040516109889190613d54565b60405180910390f35b34801561099c575f5ffd5b506109a561170c565b6040516109b29190613d54565b60405180910390f35b3480156109c6575f5ffd5b506109cf611711565b6040516109dc9190613b01565b60405180910390f35b3480156109f0575f5ffd5b506109f9611739565b005b348015610a06575f5ffd5b50610a0f611a16565b604051610a1c9190613cce565b60405180910390f35b348015610a30575f5ffd5b50610a39611a1c565b604051610a4893929190614159565b60405180910390f35b348015610a5c575f5ffd5b50610a776004803603810190610a729190613c94565b611ac3565b005b610a936004803603810190610a8e919061418e565b611b6f565b005b73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f781565b610ab5611efb565b5f8273ffffffffffffffffffffffffffffffffffffffff1611610b0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b049061425c565b60405180910390fd5b5f8111610b4f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b46906142c4565b60405180910390fd5b600c60405180604001604052808473ffffffffffffffffffffffffffffffffffffffff16815260200183815250908060018154018082558091505060019003905f5260205f2090600202015f909190919091505f820151815f01556020820151816001015550507ffbd41442955182d1c148bcc060b4629740683ee8db610592f744d316364eb0346001600c80549050610be9919061430f565b8383604051610bfa93929190614351565b60405180910390a15050565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b7f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f681565b600d602052805f5260405f205f915090505481565b5f5f600c805490508310610cac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca3906143d0565b60405180910390fd5b5f600c8481548110610cc157610cc06143ee565b5b905f5260205f2090600202016040518060400160405290815f82015481526020016001820154815250509050805f015181602001519250925050915091565b5f600c80549050905090565b601281565b600681565b610d1e611efb565b80600c805490501015610d66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5d90614465565b60405180910390fd5b80600b819055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051610d9e9190613cce565b60405180910390a150565b610db1611efb565b610db9611f82565b565b5f600d5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b610e09611fe4565b610e1161202a565b610ea13387878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054885f89898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f610f117f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48338b60016122cf565b91509150610f417f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488a8484612382565b5f83600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054610f8b919061430f565b905088811015610fd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fc7906144f3565b60405180910390fd5b610fdb338983612428565b8773ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce8560405161106f9190613cce565b60405180910390a450505050611083612796565b505050505050565b5f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b7f000000000000000000000000b1170023799c4adc7b6e6c6bb30cf84908ea8f4481565b5f600160149054906101000a900460ff16905090565b5f60065460095461111c9190614511565b905090565b7f2124daf46b0791b72e25c8132dd17a0080ab34f1da9587edb2683a5f2715811681565b60095481565b7f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d81565b611177611efb565b6111805f6127a0565b565b5f61118b6127d0565b90508073ffffffffffffffffffffffffffffffffffffffff166111ac611711565b73ffffffffffffffffffffffffffffffffffffffff161461120457806040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016111fb9190613b01565b60405180910390fd5b61120d816127a0565b50565b5f6112196110f5565b801561123857506001600c80549050611232919061430f565b600b5410155b801561126757505f600c600b5481548110611256576112556143ee565b5b905f5260205f2090600202015f0154145b905090565b6008602052805f5260405f205f915090505481565b600a5481565b61128f611efb565b6112976127d7565b565b600c81815481106112a8575f80fd5b905f5260205f2090600202015f91509050805f0154908060010154905082565b5f6060805f5f5f60606112d9612839565b6112e1612874565b46305f5f1b5f67ffffffffffffffff811115611300576112ff614544565b5b60405190808252806020026020018201604052801561132e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6305f5e10081565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60055481565b6305a995c081565b600381565b7f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841981565b7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781565b6113ff611fe4565b61140761202a565b6114983387878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205488600189898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f6115087f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7338b60016122cf565b915091506115387f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec78a8484612382565b5f83600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054611582919061430f565b9050888110156115c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115be906144f3565b60405180910390fd5b6115d2338983612428565b8773ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce856040516116669190613cce565b60405180910390a45050505061167a612796565b505050505050565b5f5f600c80549050600b54106116cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c4906145bb565b60405180910390fd5b6116d88585856128af565b91509150935093915050565b600b5481565b6007602052805f5260405f205f915090505481565b6306422c4081565b600881565b600781565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611741611efb565b5f4790505f81111561180b575f73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f773ffffffffffffffffffffffffffffffffffffffff168260405161178690614606565b5f6040518083038185875af1925050503d805f81146117c0576040519150601f19603f3d011682016040523d82523d5f602084013e6117c5565b606091505b5050905080611809576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161180090614664565b60405180910390fd5b505b5f7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016118659190613b01565b602060405180830381865afa158015611880573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118a49190614696565b90505f81111561190e5761190d73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7827f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b5f7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016119689190613b01565b602060405180830381865afa158015611983573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119a79190614696565b90505f811115611a1157611a1073f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7827f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b505050565b60065481565b5f5f5f600c80549050600b5410611a68576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a5f906145bb565b60405180910390fd5b5f600c600b5481548110611a7f57611a7e6143ee565b5b905f5260205f2090600202016040518060400160405290815f82015481526020016001820154815250509050600b54815f0151826020015193509350935050909192565b611acb611efb565b8060015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16611b2a611375565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b611b77611fe4565b611b7f61202a565b611c103334878760085f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205488600289898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061206b565b5f600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f5f611c5f5f33345f6122cf565b915091505f73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f773ffffffffffffffffffffffffffffffffffffffff1682604051611c9c90614606565b5f6040518083038185875af1925050503d805f8114611cd6576040519150601f19603f3d011682016040523d82523d5f602084013e611cdb565b606091505b5050905080611d1f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d169061470b565b60405180910390fd5b5f831115611dd1573373ffffffffffffffffffffffffffffffffffffffff1683604051611d4b90614606565b5f6040518083038185875af1925050503d805f8114611d85576040519150601f19603f3d011682016040523d82523d5f602084013e611d8a565b606091505b50508091505080611dd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611dc79061470b565b60405180910390fd5b5b5f84600d5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054611e1b919061430f565b905089811015611e60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e57906144f3565b60405180910390fd5b611e6b338a83612428565b8873ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167f3bf78ceb2bec33367593d193d62ee0bab304fd3356e414656d746684d8c8d9ce86604051611edf9190613cce565b60405180910390a45050505050611ef4612796565b5050505050565b611f036127d0565b73ffffffffffffffffffffffffffffffffffffffff16611f21611375565b73ffffffffffffffffffffffffffffffffffffffff1614611f8057611f446127d0565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401611f779190613b01565b60405180910390fd5b565b611f8a6129f2565b5f600160146101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa611fcd6127d0565b604051611fda9190613b01565b60405180910390a1565b600260045403612020576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002600481905550565b6120326110f5565b15612069576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60418151146120af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a690614799565b60405180910390fd5b824211156120f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e990614801565b60405180910390fd5b60085f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20548414612171576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216890614869565b60405180910390fd5b5f7f2124daf46b0791b72e25c8132dd17a0080ab34f1da9587edb2683a5f27158116898989898989896040516020016121b1989796959493929190614887565b6040516020818303038152906040528051906020012090505f6121d382612a32565b90505f6121e08285612a4b565b90507f000000000000000000000000b1170023799c4adc7b6e6c6bb30cf84908ea8f4473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614612270576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122679061494d565b60405180910390fd5b60085f8c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8154809291906122bd9061496b565b91905055505050505050505050505050565b5f5f600c80549050600b541061231a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612311906149fc565b60405180910390fd5b5f5f61232785878a6128af565b915091505f5f6123398a8a8587612a75565b915091508195508094505f86866123509190614511565b905080891115612374578089612366919061430f565b876123719190614511565b96505b505050505094509492505050565b6123af3330858773ffffffffffffffffffffffffffffffffffffffff16612f2a909392919063ffffffff16565b6123ee73f2b433e6d72bc4f2b7afbe2b26689ce3086b23f7828673ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5f8211156124225761242133838673ffffffffffffffffffffffffffffffffffffffff166129a49092919063ffffffff16565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561249057508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561249b57505f81115b15612790575f600d5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541115612791575f6064600360ff16836124f89190614a1a565b6125029190614a88565b90505f6064600760ff16846125179190614a1a565b6125219190614a88565b90505f81836125309190614511565b90505f6005540361254357505050612791565b5f5f60055483116125595784915083905061259e565b5f600760036125689190614ab8565b60ff16905080600360ff166005546125809190614a1a565b61258a9190614a88565b92508260055461259a919061430f565b9150505b80826125aa9190614511565b60055f8282546125ba919061430f565b9250508190555081600d5f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461260d9190614511565b925050819055508060075f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546126609190614511565b9250508190555080600d5f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546126b39190614511565b9250508190555080826126c69190614511565b60065f8282546126d69190614511565b925050819055508773ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fbd7e5be34537a425747cf06d84eca4d59c865e2002b7d5f36f14558bdc5ae8cd838560405161273c929190613d12565b60405180910390a37f67eb7a0c6462c89a739c533687df56df0c880a810c86597f6258a005582343fe81836127719190614511565b600654604051612782929190613d12565b60405180910390a150505050505b5b505050565b6001600481905550565b60015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556127cd81612fc2565b50565b5f33905090565b6127df61202a565b60018060146101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586128226127d0565b60405161282f9190613b01565b60405180910390a1565b606061286f60027f45423150726573616c650000000000000000000000000000000000000000000a61308390919063ffffffff16565b905090565b60606128aa60037f310000000000000000000000000000000000000000000000000000000000000161308390919063ffffffff16565b905090565b5f5f841561292c575f6128c184613130565b90505f6006600a6128d29190614c1b565b82876128de9190614a1a565b6128e89190614a88565b90505f600c600b5481548110612901576129006143ee565b5b905f5260205f209060020201600101548261291c9190614a88565b905080839450945050505061299c565b5f612935613416565b90505f6012600a6129469190614c1b565b86836129529190614a1a565b61295c9190614a88565b90505f600c600b5481548110612975576129746143ee565b5b905f5260205f20906002020160010154826129909190614a88565b90508083945094505050505b935093915050565b6129b78363a9059cbb60e01b8484613589565b6129ed576040517ffb7f507900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b6129fa6110f5565b612a30576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f612a44612a3e6135d9565b8361368f565b9050919050565b5f5f5f5f612a5986866136cf565b925092509250612a698282613724565b82935050505092915050565b5f5f5f600c600b5481548110612a8e57612a8d6143ee565b5b905f5260205f209060020201905083815f01541015612cf4575f815f015490505f826001015482612abf9190614a1a565b905081600d5f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254612b0d9190614511565b925050819055508160095f828254612b259190614511565b9250508190555080600a5f828254612b3d9190614511565b925050819055505f8287612b51919061430f565b90505f846001015482612b649190614a1a565b90505f73ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1603612be05788670de0b6b3a764000084612bae9190614a1a565b612bb89190614a88565b955088670de0b6b3a764000082612bcf9190614a1a565b612bd99190614a88565b9650612c2d565b886006600a612bef9190614c1b565b84612bfa9190614a1a565b612c049190614a88565b9550886006600a612c159190614c1b565b82612c209190614a1a565b612c2a9190614a88565b96505b5f855f01819055506001600c80549050612c47919061430f565b600b541015612ca557600b5f815480929190612c629061496b565b91905055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051612c989190613cce565b60405180910390a1612ceb565b7fb4e6cb40663c1ac63bcd620dbe3d98c44526baa45e310f545f425ebaab36a293600954600a54604051612cda929190613d12565b60405180910390a1612cea6127d7565b5b50505050612e3e565b5f816001015485612d059190614a1a565b905084600d5f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254612d539190614511565b925050819055508460095f828254612d6b9190614511565b9250508190555080600a5f828254612d839190614511565b925050819055508473ffffffffffffffffffffffffffffffffffffffff16825f015f828254612db2919061430f565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1603612e125785670de0b6b3a764000082612e019190614a1a565b612e0b9190614a88565b9250612e39565b856006600a612e219190614c1b565b82612e2c9190614a1a565b612e369190614a88565b92505b5f9350505b5f600c600b5481548110612e5557612e546143ee565b5b905f5260205f2090600202015f015403612f20576001600c80549050612e7b919061430f565b600b541015612ed957600b5f815480929190612e969061496b565b91905055507f34cf54504fd39ab670a54acbb37f686c5bd25e6eedfa39889cba899d360bc7d9600b54604051612ecc9190613cce565b60405180910390a1612f1f565b7fb4e6cb40663c1ac63bcd620dbe3d98c44526baa45e310f545f425ebaab36a293600954600a54604051612f0e929190613d12565b60405180910390a1612f1e6127d7565b5b5b5094509492505050565b5f6323b872dd60e01b90505f60405182815285600482015284602482015283604482015260205f6064835f8b5af191508115612f82573d5f8114612f795760015f5114601f3d11169250612f80565b5f883b1192505b505b5080612fba576040517ff405907100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050815f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b606060ff5f1b831461309f5761309883613886565b905061312a565b8180546130ab90614c92565b80601f01602080910402602001604051908101604052809291908181526020018280546130d790614c92565b80156131225780601f106130f957610100808354040283529160200191613122565b820191905f5260205f20905b81548152906001019060200180831161310557829003601f168201915b505050505090505b92915050565b5f5f7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036131ad577f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f69050613264565b7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603613228577f0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d9050613263565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161325a90614d0c565b60405180910390fd5b5b5f5f8273ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156132af573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d39190614d9c565b509350509250505f821361331c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161331390614e5d565b60405180910390fd5b5f811161335e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161335590614ec5565b60405180910390fd5b62015180814261336e919061430f565b11156133af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016133a690614f2d565b60405180910390fd5b5f8290506305a995c081101580156133cb57506306422c408111155b61340a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161340190614f95565b60405180910390fd5b80945050505050919050565b5f5f5f7f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613482573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134a69190614d9c565b509350509250505f82136134ef576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016134e690614ffd565b60405180910390fd5b5f8111613531576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161352890614ec5565b60405180910390fd5b6138408142613540919061430f565b1115613581576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161357890615065565b60405180910390fd5b819250505090565b5f60405184815283600482015282602482015260205f6044835f8a5af1915081156135d0573d5f81146135c75760015f5114601f3d111692506135ce565b5f873b1192505b505b50949350505050565b5f7f0000000000000000000000007ee71bc4b3bd272729103bce3c87ceb79bfef2e073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561365457507f000000000000000000000000000000000000000000000000000000000000000146145b15613681577f2be0b406b255da70c7fa3ff178cee090d8b3cb758171eb1d214e1e9e18e5e4bd905061368c565b6136896138f8565b90505b90565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f5f5f604184510361370f575f5f5f602087015192506040870151915060608701515f1a90506137018882858561398d565b95509550955050505061371d565b5f600285515f1b9250925092505b9250925092565b5f600381111561373757613736615083565b5b82600381111561374a57613749615083565b5b0315613882576001600381111561376457613763615083565b5b82600381111561377757613776615083565b5b036137ae576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156137c2576137c1615083565b5b8260038111156137d5576137d4615083565b5b0361381957805f1c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016138109190613cce565b60405180910390fd5b60038081111561382c5761382b615083565b5b82600381111561383f5761383e615083565b5b0361388157806040517fd78bce0c0000000000000000000000000000000000000000000000000000000081526004016138789190613eaf565b60405180910390fd5b5b5050565b60605f61389283613a74565b90505f602067ffffffffffffffff8111156138b0576138af614544565b5b6040519080825280601f01601f1916602001820160405280156138e25781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7fdf149958eeb9c4ea9a58b4e6512fb3e78569ca0297cddd7fb1a92b8c6282ad047fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc646306040516020016139729594939291906150b0565b60405160208183030381529060405280519060200120905090565b5f5f5f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c11156139c9575f600385925092509250613a6a565b5f6001888888886040515f81526020016040526040516139ec9493929190615101565b6020604051602081039080840390855afa158015613a0c573d5f5f3e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613a5d575f60015f5f1b93509350935050613a6a565b805f5f5f1b935093509350505b9450945094915050565b5f5f60ff835f1c169050601f811115613ab9576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613aeb82613ac2565b9050919050565b613afb81613ae1565b82525050565b5f602082019050613b145f830184613af2565b92915050565b5f5ffd5b5f5ffd5b613b2b81613ac2565b8114613b35575f5ffd5b50565b5f81359050613b4681613b22565b92915050565b5f819050919050565b613b5e81613b4c565b8114613b68575f5ffd5b50565b5f81359050613b7981613b55565b92915050565b5f5f60408385031215613b9557613b94613b1a565b5b5f613ba285828601613b38565b9250506020613bb385828601613b6b565b9150509250929050565b5f819050919050565b5f613be0613bdb613bd684613ac2565b613bbd565b613ac2565b9050919050565b5f613bf182613bc6565b9050919050565b5f613c0282613be7565b9050919050565b613c1281613bf8565b82525050565b5f602082019050613c2b5f830184613c09565b92915050565b5f613c3b82613be7565b9050919050565b613c4b81613c31565b82525050565b5f602082019050613c645f830184613c42565b92915050565b613c7381613ae1565b8114613c7d575f5ffd5b50565b5f81359050613c8e81613c6a565b92915050565b5f60208284031215613ca957613ca8613b1a565b5b5f613cb684828501613c80565b91505092915050565b613cc881613b4c565b82525050565b5f602082019050613ce15f830184613cbf565b92915050565b5f60208284031215613cfc57613cfb613b1a565b5b5f613d0984828501613b6b565b91505092915050565b5f604082019050613d255f830185613cbf565b613d326020830184613cbf565b9392505050565b5f60ff82169050919050565b613d4e81613d39565b82525050565b5f602082019050613d675f830184613d45565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613d8e57613d8d613d6d565b5b8235905067ffffffffffffffff811115613dab57613daa613d71565b5b602083019150836001820283011115613dc757613dc6613d75565b5b9250929050565b5f5f5f5f5f5f60a08789031215613de857613de7613b1a565b5b5f613df589828a01613b6b565b9650506020613e0689828a01613b6b565b9550506040613e1789828a01613c80565b9450506060613e2889828a01613b6b565b935050608087013567ffffffffffffffff811115613e4957613e48613b1e565b5b613e5589828a01613d79565b92509250509295509295509295565b5f8115159050919050565b613e7881613e64565b82525050565b5f602082019050613e915f830184613e6f565b92915050565b5f819050919050565b613ea981613e97565b82525050565b5f602082019050613ec25f830184613ea0565b92915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b613efc81613ec8565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613f4482613f02565b613f4e8185613f0c565b9350613f5e818560208601613f1c565b613f6781613f2a565b840191505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b613fa481613b4c565b82525050565b5f613fb58383613f9b565b60208301905092915050565b5f602082019050919050565b5f613fd782613f72565b613fe18185613f7c565b9350613fec83613f8c565b805f5b8381101561401c5781516140038882613faa565b975061400e83613fc1565b925050600181019050613fef565b5085935050505092915050565b5f60e08201905061403c5f83018a613ef3565b818103602083015261404e8189613f3a565b905081810360408301526140628188613f3a565b90506140716060830187613cbf565b61407e6080830186613af2565b61408b60a0830185613ea0565b81810360c083015261409d8184613fcd565b905098975050505050505050565b5f8160030b9050919050565b6140c0816140ab565b82525050565b5f6020820190506140d95f8301846140b7565b92915050565b6140e881613e64565b81146140f2575f5ffd5b50565b5f81359050614103816140df565b92915050565b5f5f5f606084860312156141205761411f613b1a565b5b5f61412d868287016140f5565b935050602061413e86828701613b6b565b925050604061414f86828701613c80565b9150509250925092565b5f60608201905061416c5f830186613cbf565b6141796020830185613cbf565b6141866040830184613cbf565b949350505050565b5f5f5f5f5f608086880312156141a7576141a6613b1a565b5b5f6141b488828901613b6b565b95505060206141c588828901613c80565b94505060406141d688828901613b6b565b935050606086013567ffffffffffffffff8111156141f7576141f6613b1e565b5b61420388828901613d79565b92509250509295509295909350565b7f50726573616c653a20616d6f756e74206d757374206265203e300000000000005f82015250565b5f614246601a83613f0c565b915061425182614212565b602082019050919050565b5f6020820190508181035f8301526142738161423a565b9050919050565b7f50726573616c653a20636f7374206d757374206265203e3000000000000000005f82015250565b5f6142ae601883613f0c565b91506142b98261427a565b602082019050919050565b5f6020820190508181035f8301526142db816142a2565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61431982613b4c565b915061432483613b4c565b925082820390508181111561433c5761433b6142e2565b5b92915050565b61434b81613ac2565b82525050565b5f6060820190506143645f830186613cbf565b6143716020830185614342565b61437e6040830184613cbf565b949350505050565b7f50726573616c653a20696e76616c6964207374616765000000000000000000005f82015250565b5f6143ba601683613f0c565b91506143c582614386565b602082019050919050565b5f6020820190508181035f8301526143e7816143ae565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f50726573616c653a2057726f6e67206974657261746f720000000000000000005f82015250565b5f61444f601783613f0c565b915061445a8261441b565b602082019050919050565b5f6020820190508181035f83015261447c81614443565b9050919050565b7f50726573616c653a20496e73756666696369656e7420746f6b656e73207265635f8201527f6569766564000000000000000000000000000000000000000000000000000000602082015250565b5f6144dd602583613f0c565b91506144e882614483565b604082019050919050565b5f6020820190508181035f83015261450a816144d1565b9050919050565b5f61451b82613b4c565b915061452683613b4c565b925082820190508082111561453e5761453d6142e2565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f50726573616c653a20656e6465640000000000000000000000000000000000005f82015250565b5f6145a5600e83613f0c565b91506145b082614571565b602082019050919050565b5f6020820190508181035f8301526145d281614599565b9050919050565b5f81905092915050565b50565b5f6145f15f836145d9565b91506145fc826145e3565b5f82019050919050565b5f614610826145e6565b9150819050919050565b7f5265736375653a20455448207472616e73666572206661696c656400000000005f82015250565b5f61464e601b83613f0c565b91506146598261461a565b602082019050919050565b5f6020820190508181035f83015261467b81614642565b9050919050565b5f8151905061469081613b55565b92915050565b5f602082840312156146ab576146aa613b1a565b5b5f6146b884828501614682565b91505092915050565b7f50726573616c653a20436f696e207472616e73666572206661696c65640000005f82015250565b5f6146f5601d83613f0c565b9150614700826146c1565b602082019050919050565b5f6020820190508181035f830152614722816146e9565b9050919050565b7f50726573616c653a20696e76616c6964207369676e6174757265206c656e67745f8201527f6800000000000000000000000000000000000000000000000000000000000000602082015250565b5f614783602183613f0c565b915061478e82614729565b604082019050919050565b5f6020820190508181035f8301526147b081614777565b9050919050565b7f50726573616c653a207369676e617475726520657870697265640000000000005f82015250565b5f6147eb601a83613f0c565b91506147f6826147b7565b602082019050919050565b5f6020820190508181035f830152614818816147df565b9050919050565b7f50726573616c653a20696e76616c6964206e6f6e6365000000000000000000005f82015250565b5f614853601683613f0c565b915061485e8261481f565b602082019050919050565b5f6020820190508181035f83015261488081614847565b9050919050565b5f6101008201905061489b5f83018b613ea0565b6148a8602083018a613af2565b6148b56040830189613cbf565b6148c26060830188613cbf565b6148cf6080830187613af2565b6148dc60a0830186613cbf565b6148e960c0830185613cbf565b6148f660e0830184613d45565b9998505050505050505050565b7f50726573616c653a20696e76616c6964207369676e61747572650000000000005f82015250565b5f614937601a83613f0c565b915061494282614903565b602082019050919050565b5f6020820190508181035f8301526149648161492b565b9050919050565b5f61497582613b4c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149a7576149a66142e2565b5b600182019050919050565b7f50726573616c653a20697320656e6465640000000000000000000000000000005f82015250565b5f6149e6601183613f0c565b91506149f1826149b2565b602082019050919050565b5f6020820190508181035f830152614a13816149da565b9050919050565b5f614a2482613b4c565b9150614a2f83613b4c565b9250828202614a3d81613b4c565b91508282048414831517614a5457614a536142e2565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614a9282613b4c565b9150614a9d83613b4c565b925082614aad57614aac614a5b565b5b828204905092915050565b5f614ac282613d39565b9150614acd83613d39565b9250828201905060ff811115614ae657614ae56142e2565b5b92915050565b5f8160011c9050919050565b5f5f8291508390505b6001851115614b4157808604811115614b1d57614b1c6142e2565b5b6001851615614b2c5780820291505b8081029050614b3a85614aec565b9450614b01565b94509492505050565b5f82614b595760019050614c14565b81614b66575f9050614c14565b8160018114614b7c5760028114614b8657614bb5565b6001915050614c14565b60ff841115614b9857614b976142e2565b5b8360020a915084821115614baf57614bae6142e2565b5b50614c14565b5060208310610133831016604e8410600b8410161715614bea5782820a905083811115614be557614be46142e2565b5b614c14565b614bf78484846001614af8565b92509050818404811115614c0e57614c0d6142e2565b5b81810290505b9392505050565b5f614c2582613b4c565b9150614c3083613d39565b9250614c5d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484614b4a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680614ca957607f821691505b602082108103614cbc57614cbb614c65565b5b50919050565b7f556e737570706f7274656420737461626c65636f696e000000000000000000005f82015250565b5f614cf6601683613f0c565b9150614d0182614cc2565b602082019050919050565b5f6020820190508181035f830152614d2381614cea565b9050919050565b5f69ffffffffffffffffffff82169050919050565b614d4881614d2a565b8114614d52575f5ffd5b50565b5f81519050614d6381614d3f565b92915050565b5f819050919050565b614d7b81614d69565b8114614d85575f5ffd5b50565b5f81519050614d9681614d72565b92915050565b5f5f5f5f5f60a08688031215614db557614db4613b1a565b5b5f614dc288828901614d55565b9550506020614dd388828901614d88565b9450506040614de488828901614682565b9350506060614df588828901614682565b9250506080614e0688828901614d55565b9150509295509295909350565b7f496e76616c696420737461626c65636f696e20707269636500000000000000005f82015250565b5f614e47601883613f0c565b9150614e5282614e13565b602082019050919050565b5f6020820190508181035f830152614e7481614e3b565b9050919050565b7f526f756e64206e6f7420636f6d706c65746500000000000000000000000000005f82015250565b5f614eaf601283613f0c565b9150614eba82614e7b565b602082019050919050565b5f6020820190508181035f830152614edc81614ea3565b9050919050565b7f5374616c6520737461626c65636f696e207072696365000000000000000000005f82015250565b5f614f17601683613f0c565b9150614f2282614ee3565b602082019050919050565b5f6020820190508181035f830152614f4481614f0b565b9050919050565b7f537461626c65636f696e206465706567206465746563746564000000000000005f82015250565b5f614f7f601983613f0c565b9150614f8a82614f4b565b602082019050919050565b5f6020820190508181035f830152614fac81614f73565b9050919050565b7f496e76616c6964207072696365000000000000000000000000000000000000005f82015250565b5f614fe7600d83613f0c565b9150614ff282614fb3565b602082019050919050565b5f6020820190508181035f83015261501481614fdb565b9050919050565b7f5374616c652070726963650000000000000000000000000000000000000000005f82015250565b5f61504f600b83613f0c565b915061505a8261501b565b602082019050919050565b5f6020820190508181035f83015261507c81615043565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60a0820190506150c35f830188613ea0565b6150d06020830187613ea0565b6150dd6040830186613ea0565b6150ea6060830185613cbf565b6150f76080830184613af2565b9695505050505050565b5f6080820190506151145f830187613ea0565b6151216020830186613d45565b61512e6040830185613ea0565b61513b6060830184613ea0565b9594505050505056fea264697066735822122037e1a3a162c218693e703a897e7337a0bc661dd1003e5a7738bb7a7e4084213864736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b84190000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f60000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000b1170023799c4adc7b6e6c6bb30cf84908ea8f44
-----Decoded View---------------
Arg [0] : COIN_PRICE_FEED_ (address): 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
Arg [1] : USDC_PRICE_FEED_ (address): 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
Arg [2] : USDT_PRICE_FEED_ (address): 0x3E7d1eAB13ad0104d2750B8863b489D65364e32D
Arg [3] : usdcToken_ (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [4] : usdtToken_ (address): 0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [5] : signer (address): 0xb1170023799C4AdC7B6E6c6bB30CF84908ea8F44
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
Arg [1] : 0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
Arg [2] : 0000000000000000000000003e7d1eab13ad0104d2750b8863b489d65364e32d
Arg [3] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [4] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [5] : 000000000000000000000000b1170023799c4adc7b6e6c6bb30cf84908ea8f44
Deployed Bytecode Sourcemap
171778:23237:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;173327:81;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;175498:315;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;173245:33;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173121:54;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173593:56;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;193579:260;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;193891:97;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172399:40;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172239:47;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;175259:231;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;175892:67;;;;;;;;;;;;;:::i;:::-;;192892:110;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;176587:1149;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;193056:127;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173658:31;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;50759:86;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;192683:137;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172844:207;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173417:30;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173182:54;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;45620:103;;;;;;;;;;;;;:::i;:::-;;48748:235;;;;;;;;;;;;;:::i;:::-;;194063:164;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172739:41;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173454:29;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;175821:63;;;;;;;;;;;;;:::i;:::-;;173559:25;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;165363:580;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;172167:45;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;44945:87;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172464:36;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173698:49;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172590:37;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173060:54;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173285:33;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;177744:1169;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;194649:363;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;173524:28;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172681:51;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;173763:49;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172315:44;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;172634:38;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;47709:101;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;175967:612;;;;;;;;;;;;;:::i;:::-;;172507:39;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;193238:288;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;48136:181;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;178921:1356;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;173327:81;173366:42;173327:81;:::o;175498:315::-;44831:13;:11;:13::i;:::-;175593:1:::1;175584:6;:10;;;175576:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;175651:1;175644:4;:8;175636:45;;;;;;;;;;;;:::i;:::-;;;;;;;;;175694:6;175706:39;;;;;;;;175725:6;175706:39;;;;;;175739:4;175706:39;;::::0;175694:52:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;175762:43;175789:1;175773:6;:13;;;;:17;;;;:::i;:::-;175792:6;175800:4;175762:43;;;;;;;;:::i;:::-;;;;;;;;175498:315:::0;;:::o;173245:33::-;;;:::o;173121:54::-;;;:::o;173593:56::-;;;;;;;;;;;;;;;;;:::o;193579:260::-;193637:14;193653:12;193696:6;:13;;;;193686:7;:23;193678:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;193747:22;193772:6;193779:7;193772:15;;;;;;;;:::i;:::-;;;;;;;;;;;;193747:40;;;;;;;;;;;;;;;;;;;;;;;;;;;193806:5;:12;;;193820:5;:10;;;193798:33;;;;;193579:260;;;:::o;193891:97::-;193940:7;193967:6;:13;;;;193960:20;;193891:97;:::o;172399:40::-;172437:2;172399:40;:::o;172239:47::-;172285:1;172239:47;:::o;175259:231::-;44831:13;:11;:13::i;:::-;175356:14:::1;175339:6;:13;;;;:31;;175331:67;;;;;;;;;;;;:::i;:::-;;;;;;;;;175425:14;175409:13;:30;;;;175455:27;175468:13;;175455:27;;;;;;:::i;:::-;;;;;;;;175259:231:::0;:::o;175892:67::-;44831:13;:11;:13::i;:::-;175941:10:::1;:8;:10::i;:::-;175892:67::o:0;192892:110::-;192953:7;192980:8;:14;192989:4;192980:14;;;;;;;;;;;;;;;;192973:21;;192892:110;;;:::o;176587:1149::-;169468:21;:19;:21::i;:::-;50364:19:::1;:17;:19::i;:::-;176807:219:::2;176838:10;176863:6;176884:12;176911:8;176934:6;:18;176941:10;176934:18;;;;;;;;;;;;;;;;176967:8;176990:1;177006:9;;176807:219;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:219::i;:::-;177039:14;177056:8;:20;177065:10;177056:20;;;;;;;;;;;;;;;;177039:37;;177088:18;177108:20;177132:124;177171:9;177195:10;177220:6;177241:4;177132:24;:124::i;:::-;177087:169;;;;177267:65;177288:9;177299:6;177307:10;177319:12;177267:20;:65::i;:::-;177343:14;177383:6;177360:8;:20;177369:10;177360:20;;;;;;;;;;;;;;;;:29;;;;:::i;:::-;177343:46;;177460:12;177450:6;:22;;177442:72;;;;;;;;;;;;:::i;:::-;;;;;;;;;177535:44;177550:10;177562:8;177572:6;177535:14;:44::i;:::-;177682:8;177597:131;;177657:10;177597:131;;177632:9;177597:131;;;177705:12;177597:131;;;;;;:::i;:::-;;;;;;;;176796:940;;;;169512:20:::0;:18;:20::i;:::-;176587:1149;;;;;;:::o;193056:127::-;193126:7;193153:16;:22;193170:4;193153:22;;;;;;;;;;;;;;;;193146:29;;193056:127;;;:::o;173658:31::-;;;:::o;50759:86::-;50806:4;50830:7;;;;;;;;;;;50823:14;;50759:86;:::o;192683:137::-;192743:7;192788:24;;192770:15;;:42;;;;:::i;:::-;192763:49;;192683:137;:::o;172844:207::-;172894:157;172844:207;:::o;173417:30::-;;;;:::o;173182:54::-;;;:::o;45620:103::-;44831:13;:11;:13::i;:::-;45685:30:::1;45712:1;45685:18;:30::i;:::-;45620:103::o:0;48748:235::-;48801:14;48818:12;:10;:12::i;:::-;48801:29;;48863:6;48845:24;;:14;:12;:14::i;:::-;:24;;;48841:98;;48920:6;48893:34;;;;;;;;;;;:::i;:::-;;;;;;;;48841:98;48949:26;48968:6;48949:18;:26::i;:::-;48790:193;48748:235::o;194063:164::-;194112:4;194136:8;:6;:8::i;:::-;:46;;;;;194181:1;194165:6;:13;;;;:17;;;;:::i;:::-;194148:13;;:34;;194136:46;:83;;;;;194218:1;194186:6;194193:13;;194186:21;;;;;;;;:::i;:::-;;;;;;;;;;;;:28;;;:33;194136:83;194129:90;;194063:164;:::o;172739:41::-;;;;;;;;;;;;;;;;;:::o;173454:29::-;;;;:::o;175821:63::-;44831:13;:11;:13::i;:::-;175868:8:::1;:6;:8::i;:::-;175821:63::o:0;173559:25::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;165363:580::-;165466:13;165494:18;165527:21;165563:15;165593:25;165633:12;165660:27;165768:13;:11;:13::i;:::-;165796:16;:14;:16::i;:::-;165827:13;165863:4;165891:1;165883:10;;165922:1;165908:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;165715:220;;;;;;;;;;;;;;;;;;;;;165363:580;;;;;;;:::o;172167:45::-;172209:3;172167:45;:::o;44945:87::-;44991:7;45018:6;;;;;;;;;;;45011:13;;44945:87;:::o;172464:36::-;;;;:::o;173698:49::-;173741:6;173698:49;:::o;172590:37::-;172626:1;172590:37;:::o;173060:54::-;;;:::o;173285:33::-;;;:::o;177744:1169::-;169468:21;:19;:21::i;:::-;50364:19:::1;:17;:19::i;:::-;177964:219:::2;177995:10;178020:6;178041:12;178068:8;178091:6;:18;178098:10;178091:18;;;;;;;;;;;;;;;;178124:8;178147:1;178163:9;;177964:219;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:219::i;:::-;178204:14;178221:8;:20;178230:10;178221:20;;;;;;;;;;;;;;;;178204:37;;178263:18;178283:20;178307:124;178346:9;178370:10;178395:6;178416:4;178307:24;:124::i;:::-;178262:169;;;;178444:65;178465:9;178476:6;178484:10;178496:12;178444:20;:65::i;:::-;178520:14;178560:6;178537:8;:20;178546:10;178537:20;;;;;;;;;;;;;;;;:29;;;;:::i;:::-;178520:46;;178637:12;178627:6;:22;;178619:72;;;;;;;;;;;;:::i;:::-;;;;;;;;;178712:44;178727:10;178739:8;178749:6;178712:14;:44::i;:::-;178859:8;178774:131;;178834:10;178774:131;;178809:9;178774:131;;;178882:12;178774:131;;;;;;:::i;:::-;;;;;;;;177953:960;;;;169512:20:::0;:18;:20::i;:::-;177744:1169;;;;;;:::o;194649:363::-;194804:22;194828:19;194884:6;:13;;;;194868;;:29;194860:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;194944:60;194961:13;194976;194991:12;194944:16;:60::i;:::-;194937:67;;;;194649:363;;;;;;:::o;173524:28::-;;;;:::o;172681:51::-;;;;;;;;;;;;;;;;;:::o;173763:49::-;173806:6;173763:49;:::o;172315:44::-;172358:1;172315:44;:::o;172634:38::-;172671:1;172634:38;:::o;47709:101::-;47762:7;47789:13;;;;;;;;;;;47782:20;;47709:101;:::o;175967:612::-;44831:13;:11;:13::i;:::-;176020:14:::1;176037:21;176020:38;;176082:1;176073:6;:10;176069:171;;;176101:12;173366:42;176119:28;;176155:6;176119:47;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;176100:66;;;176189:7;176181:47;;;;;;;;;;;;:::i;:::-;;;;;;;;;176085:155;176069:171;176252:15;176270:9;:19;;;176298:4;176270:34;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;176252:52;;176329:1;176319:7;:11;176315:91;;;176347:47;173366:42;176386:7;176347:9;:22;;;;:47;;;;;:::i;:::-;176315:91;176418:15;176436:9;:19;;;176464:4;176436:34;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;176418:52;;176495:1;176485:7;:11;176481:91;;;176513:47;173366:42;176552:7;176513:9;:22;;;;:47;;;;;:::i;:::-;176481:91;176009:570;;;175967:612::o:0;172507:39::-;;;;:::o;193238:288::-;193288:15;193305:14;193321:12;193370:6;:13;;;;193354;;:29;193346:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;193413:22;193438:6;193445:13;;193438:21;;;;;;;;:::i;:::-;;;;;;;;;;;;193413:46;;;;;;;;;;;;;;;;;;;;;;;;;;;193478:13;;193493:5;:12;;;193507:5;:10;;;193470:48;;;;;;;193238:288;;;:::o;48136:181::-;44831:13;:11;:13::i;:::-;48242:8:::1;48226:13;;:24;;;;;;;;;;;;;;;;;;48300:8;48266:43;;48291:7;:5;:7::i;:::-;48266:43;;;;;;;;;;;;48136:181:::0;:::o;178921:1356::-;169468:21;:19;:21::i;:::-;50364:19:::1;:17;:19::i;:::-;179124:222:::2;179155:10;179180:9;179204:12;179231:8;179254:6;:18;179261:10;179254:18;;;;;;;;;;;;;;;;179287:8;179310:1;179326:9;;179124:222;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:16;:222::i;:::-;179359:14;179376:8;:20;179385:10;179376:20;;;;;;;;;;;;;;;;179359:37;;179408:18;179428:20;179452:137;179506:1;179524:10;179549:9;179573:5;179452:24;:137::i;:::-;179407:182;;;;179603:12;173366:42;179621:28;;179657:12;179621:77;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;179602:96;;;179717:7;179709:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;179788:1;179775:10;:14;179771:172;;;179828:10;179820:24;;179852:10;179820:47;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;179806:61;;;;;179890:7;179882:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;179771:172;179955:14;179995:6;179972:8;:20;179981:10;179972:20;;;;;;;;;;;;;;;;:29;;;;:::i;:::-;179955:46;;180072:12;180062:6;:22;;180054:72;;;;;;;;;;;;:::i;:::-;;;;;;;;;180147:44;180162:10;180174:8;180184:6;180147:14;:44::i;:::-;180246:8;180209:60;;180234:10;180209:60;;180230:1;180209:60;;;180256:12;180209:60;;;;;;:::i;:::-;;;;;;;;179113:1164;;;;;169512:20:::0;:18;:20::i;:::-;178921:1356;;;;;:::o;45110:166::-;45181:12;:10;:12::i;:::-;45170:23;;:7;:5;:7::i;:::-;:23;;;45166:103;;45244:12;:10;:12::i;:::-;45217:40;;;;;;;;;;;:::i;:::-;;;;;;;;45166:103;45110:166::o;51660:120::-;50623:16;:14;:16::i;:::-;51729:5:::1;51719:7;;:15;;;;;;;;;;;;;;;;;;51750:22;51759:12;:10;:12::i;:::-;51750:22;;;;;;:::i;:::-;;;;;;;;51660:120::o:0;169548:315::-;168846:1;169677:7;;:18;169673:88;;169719:30;;;;;;;;;;;;;;169673:88;168846:1;169838:7;:17;;;;169548:315::o;50918:132::-;50984:8;:6;:8::i;:::-;50980:63;;;51016:15;;;;;;;;;;;;;;50980:63;50918:132::o;188857:1173::-;189155:2;189135:9;:16;:22;189127:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;189233:8;189214:15;:27;;189206:66;;;;;;;;;;;;:::i;:::-;;;;;;;;;189327:6;:13;189334:5;189327:13;;;;;;;;;;;;;;;;189318:5;:22;189310:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;189418:18;172894:157;189525:5;189549:6;189574:12;189605:8;189632:5;189656:8;189683:9;189463:244;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;189439:279;;;;;;189418:300;;189777:14;189794:28;189811:10;189794:16;:28::i;:::-;189777:45;;189833:14;189850:32;189864:6;189872:9;189850:13;:32::i;:::-;189833:49;;189911:6;189901:16;;:6;:16;;;189893:55;;;;;;;;;;;;:::i;:::-;;;;;;;;;190007:6;:13;190014:5;190007:13;;;;;;;;;;;;;;;;:15;;;;;;;;;:::i;:::-;;;;;;189116:914;;;188857:1173;;;;;;;;:::o;180285:989::-;180441:18;180461:20;180518:6;:13;;;;180502;;:29;180494:59;;;;;;;;;;;;:::i;:::-;;;;;;;;;180567:24;180593:17;180614:104;180645:13;180673:5;180701;180614:16;:104::i;:::-;180566:152;;;;180730:26;180758:19;180781:112;180805:5;180825:2;180842:9;180866:16;180781:9;:112::i;:::-;180729:164;;;;180994:18;180981:31;;181038:11;181023:26;;181119:20;181157:10;181142:12;:25;;;;:::i;:::-;181119:48;;181190:12;181182:5;:20;181178:89;;;181242:12;181234:5;:20;;;;:::i;:::-;181219:36;;;;;:::i;:::-;;;181178:89;180483:791;;;;;180285:989;;;;;;;:::o;181282:361::-;181446:57;181469:10;181489:4;181496:6;181446:5;:22;;;;:57;;;;;;:::i;:::-;181514:48;173366:42;181549:12;181514:5;:18;;;;:48;;;;;:::i;:::-;181590:1;181577:10;:14;181573:62;;;181593:42;181612:10;181624;181593:5;:18;;;;:42;;;;;:::i;:::-;181573:62;181282:361;;;;:::o;190038:2560::-;190241:1;190221:22;;:8;:22;;;;:43;;;;;190259:5;190247:17;;:8;:17;;;;190221:43;:63;;;;;190283:1;190268:12;:16;190221:63;190217:2374;;;190385:1;190363:8;:18;190372:8;190363:18;;;;;;;;;;;;;;;;:23;190359:96;190407:7;190359:96;190517:26;190575:3;172626:1;190546:26;;:12;:26;;;;:::i;:::-;:32;;;;:::i;:::-;190517:61;;190626:26;190685:3;172671:1;190655:27;;:12;:27;;;;:::i;:::-;:33;;;;:::i;:::-;190626:62;;190733:24;190781:18;190760;:39;;;;:::i;:::-;190733:66;;190896:1;190871:21;;:26;190867:73;;190918:7;;;;;190867:73;190956:24;190995:32;191068:21;;191048:16;:41;191044:608;;191129:18;191110:37;;191193:18;191166:45;;191044:608;;;191403:17;172671:1;172626;191423:26;;;;:::i;:::-;191403:46;;;;191541:9;172626:1;191502:35;;:21;;:35;;;;:::i;:::-;191501:49;;;;:::i;:::-;191482:68;;191620:16;191596:21;;:40;;;;:::i;:::-;191569:67;;191233:419;191044:608;191754:24;191735:16;:43;;;;:::i;:::-;191709:21;;:70;;;;;;;:::i;:::-;;;;;;;;191909:16;191890:8;:15;191899:5;191890:15;;;;;;;;;;;;;;;;:35;;;;;;;:::i;:::-;;;;;;;;192061:24;192031:16;:26;192048:8;192031:26;;;;;;;;;;;;;;;;:54;;;;;;;:::i;:::-;;;;;;;;192122:24;192100:8;:18;192109:8;192100:18;;;;;;;;;;;;;;;;:46;;;;;;;:::i;:::-;;;;;;;;192290:24;192271:16;:43;;;;:::i;:::-;192243:24;;:71;;;;;;;:::i;:::-;;;;;;;;192414:5;192389:75;;192404:8;192389:75;;;192421:24;192447:16;192389:75;;;;;;;:::i;:::-;;;;;;;;192484:95;192528:24;192509:16;:43;;;;:::i;:::-;192554:24;;192484:95;;;;;;;:::i;:::-;;;;;;;;190286:2305;;;;;190217:2374;190038:2560;;;;:::o;169871:212::-;168803:1;170054:7;:21;;;;169871:212::o;48507:156::-;48597:13;;48590:20;;;;;;;;;;;48621:34;48646:8;48621:24;:34::i;:::-;48507:156;:::o;42954:98::-;43007:7;43034:10;43027:17;;42954:98;:::o;51401:118::-;50364:19;:17;:19::i;:::-;51471:4:::1;51461:7:::0;::::1;:14;;;;;;;;;;;;;;;;;;51491:20;51498:12;:10;:12::i;:::-;51491:20;;;;;;:::i;:::-;;;;;;;;51401:118::o:0;166272:128::-;166318:13;166351:41;166378:13;166351:5;:26;;:41;;;;:::i;:::-;166344:48;;166272:128;:::o;166735:137::-;166784:13;166817:47;166847:16;166817:8;:29;;:47;;;;:::i;:::-;166810:54;;166735:137;:::o;181651:1386::-;181790:14;181806:13;181836;181832:1198;;;181936:23;181962:33;181982:12;181962:19;:33::i;:::-;181936:59;;182254:16;172285:1;182302:2;:27;;;;:::i;:::-;182282:15;182274:5;:23;;;;:::i;:::-;182273:57;;;;:::i;:::-;182254:76;;182412:22;182448:6;182455:13;;182448:21;;;;;;;;:::i;:::-;;;;;;;;;;;;:26;;;182437:8;:37;;;;:::i;:::-;182412:62;;182511:14;182527:15;182503:40;;;;;;;;;181832:1198;182630:16;182649:17;:15;:17::i;:::-;182630:36;;182751:16;172437:2;182792;:19;;;;:::i;:::-;182782:5;182771:8;:16;;;;:::i;:::-;182770:42;;;;:::i;:::-;182751:61;;182894:22;182930:6;182937:13;;182930:21;;;;;;;;:::i;:::-;;;;;;;;;;;;:26;;;182919:8;:37;;;;:::i;:::-;182894:62;;182993:14;183009:8;182985:33;;;;;;;181651:1386;;;;;;;:::o;22026:239::-;22149:53;22159:5;22166:23;;;22191:2;22195:6;22149:9;:53::i;:::-;22144:114;;22226:20;;;;;;;;;;;;;;22144:114;22026:239;;;:::o;51127:130::-;51191:8;:6;:8::i;:::-;51186:64;;51223:15;;;;;;;;;;;;;;51186:64;51127:130::o;165130:178::-;165207:7;165234:66;165267:20;:18;:20::i;:::-;165289:10;165234:32;:66::i;:::-;165227:73;;165130:178;;;:::o;55625:259::-;55703:7;55724:17;55743:18;55763:16;55783:27;55794:4;55800:9;55783:10;:27::i;:::-;55723:87;;;;;;55821:28;55833:5;55840:8;55821:11;:28::i;:::-;55867:9;55860:16;;;;;55625:259;;;;:::o;184696:4096::-;184836:26;184864:20;184897:26;184926:6;184933:13;;184926:21;;;;;;;;:::i;:::-;;;;;;;;;;;;184897:50;;184988:6;184969:8;:15;;;184964:30;184960:3331;;;185044:24;185071:8;:15;;;185044:42;;185182:25;185229:8;:13;;;185210:16;:32;;;;:::i;:::-;185182:60;;185330:16;185314:8;:12;185323:2;185314:12;;;;;;;;;;;;;;;;:32;;;;;;;:::i;:::-;;;;;;;;185380:16;185361:15;;:35;;;;;;;:::i;:::-;;;;;;;;185429:17;185411:14;;:35;;;;;;;:::i;:::-;;;;;;;;185548:20;185580:16;185571:6;:25;;;;:::i;:::-;185548:48;;185611:22;185651:8;:13;;;185636:12;:28;;;;:::i;:::-;185611:53;;185801:1;185775:28;;185783:5;185775:28;;;185771:869;;186074:9;186066:4;186046:17;:24;;;;:::i;:::-;186045:38;;;;:::i;:::-;186030:53;;186149:9;186141:4;186124:14;:21;;;;:::i;:::-;186123:35;;;;:::i;:::-;186102:56;;185771:869;;;186515:9;172285:1;186483:2;:27;;;;:::i;:::-;186462:17;:49;;;;:::i;:::-;186461:63;;;;:::i;:::-;186446:78;;186615:9;172285:1;186583:2;:27;;;;:::i;:::-;186565:14;:46;;;;:::i;:::-;186564:60;;;;:::i;:::-;186543:81;;185771:869;186721:1;186703:8;:15;;:19;;;;186773:1;186757:6;:13;;;;:17;;;;:::i;:::-;186741:13;;:33;186737:320;;;186795:13;;:15;;;;;;;;;:::i;:::-;;;;;;186834:27;186847:13;;186834:27;;;;;;:::i;:::-;;;;;;;;186737:320;;;186969:45;186982:15;;186999:14;;186969:45;;;;;;;:::i;:::-;;;;;;;;187033:8;:6;:8::i;:::-;186737:320;184996:2072;;;;184960:3331;;;187145:25;187182:8;:13;;;187173:6;:22;;;;:::i;:::-;187145:50;;187283:6;187267:8;:12;187276:2;187267:12;;;;;;;;;;;;;;;;:22;;;;;;;:::i;:::-;;;;;;;;187323:6;187304:15;;:25;;;;;;;:::i;:::-;;;;;;;;187362:17;187344:14;;:35;;;;;;;:::i;:::-;;;;;;;;187421:6;187394:34;;:8;:15;;;:34;;;;;;;:::i;:::-;;;;;;;;187563:1;187537:28;;187545:5;187537:28;;;187533:696;;187838:9;187830:4;187810:17;:24;;;;:::i;:::-;187809:38;;;;:::i;:::-;187794:53;;187533:696;;;188204:9;172285:1;188172:2;:27;;;;:::i;:::-;188151:17;:49;;;;:::i;:::-;188150:63;;;;:::i;:::-;188135:78;;187533:696;188278:1;188257:22;;187074:1217;184960:3331;188436:1;188404:6;188411:13;;188404:21;;;;;;;;:::i;:::-;;;;;;;;;;;;:28;;;:33;188400:385;;188490:1;188474:6;:13;;;;:17;;;;:::i;:::-;188458:13;;:33;188454:320;;;188512:13;;:15;;;;;;;;;:::i;:::-;;;;;;188551:27;188564:13;;188551:27;;;;;;:::i;:::-;;;;;;;;188454:320;;;188686:45;188699:15;;188716:14;;188686:45;;;;;;;:::i;:::-;;;;;;;;188750:8;:6;:8::i;:::-;188454:320;188400:385;184886:3906;184696:4096;;;;;;;:::o;18784:950::-;18929:15;18947:27;;;18929:45;;18985:12;19109:4;19103:11;19143:8;19137:4;19130:22;19190:4;19183;19177;19173:15;19166:29;19233:2;19226:4;19220;19216:15;19209:27;19274:6;19267:4;19261;19257:15;19250:31;19345:4;19340:3;19334:4;19328;19325:1;19318:5;19311;19306:44;19295:55;;19367:7;19364:296;;;19401:16;19440:1;19435:85;;;;19623:1;19619;19613:8;19610:15;19605:2;19587:16;19584:24;19580:46;19569:57;;19394:251;;19435:85;19499:1;19491:5;19479:18;19476:25;19465:36;;19394:251;;19364:296;19033:638;19686:7;19681:45;;19702:24;;;;;;;;;;;;;;19681:45;18918:816;;18784:950;;;;:::o;46258:191::-;46332:16;46351:6;;;;;;;;;;;46332:25;;46377:8;46368:6;;:17;;;;;;;;;;;;;;;;;;46432:8;46401:40;;46422:8;46401:40;;;;;;;;;;;;46321:128;46258:191;:::o;158388:273::-;158482:13;156352:66;158541:17;;158531:5;158512:46;158508:146;;158582:15;158591:5;158582:8;:15::i;:::-;158575:22;;;;158508:146;158637:5;158630:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;158388:273;;;;;:::o;183541:1147::-;183615:7;183635:31;183784:9;183760:34;;:12;:34;;;183756:259;;183823:15;183811:27;;183756:259;;;183884:9;183860:34;;:12;:34;;;183856:159;;183923:15;183911:27;;183856:159;;;183971:32;;;;;;;;;;:::i;:::-;;;;;;;;183856:159;183756:259;184069:12;184125:17;184157:9;:25;;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;184027:157;;;;;;;184213:1;184205:5;:9;184197:46;;;;;;;;;;;;:::i;:::-;;;;;;;;;184274:1;184262:9;:13;184254:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;184348:8;184335:9;184317:15;:27;;;;:::i;:::-;:39;;184309:74;;;;;;;;;;;;:::i;:::-;;;;;;;;;184396:19;184426:5;184396:36;;173741:6;184527:11;:31;;:66;;;;;173806:6;184562:11;:31;;184527:66;184519:122;;;;;;;;;;;;:::i;:::-;;;;;;;;;184669:11;184662:18;;;;;;183541:1147;;;:::o;183045:488::-;183095:7;183185:12;183250:17;183282:15;:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;183115:200;;;;;;;183344:1;183336:5;:9;183328:35;;;;;;;;;;;;:::i;:::-;;;;;;;;;183394:1;183382:9;:13;183374:44;;;;;;;;;;;;:::i;:::-;;;;;;;;;183468:7;183455:9;183437:15;:27;;;;:::i;:::-;:38;;183429:62;;;;;;;;;;;;:::i;:::-;;;;;;;;;183519:5;183504:21;;;;183045:488;:::o;37639:790::-;37777:12;37903:4;37897:11;37937:8;37931:4;37924:22;37984:2;37977:4;37971;37967:15;37960:27;38025:6;38018:4;38012;38008:15;38001:31;38096:4;38091:3;38085:4;38079;38076:1;38069:5;38062;38057:44;38046:55;;38118:7;38115:296;;;38152:16;38191:1;38186:85;;;;38374:1;38370;38364:8;38361:15;38356:2;38338:16;38335:24;38331:46;38320:57;;38145:251;;38186:85;38250:1;38242:5;38230:18;38227:25;38216:36;;38145:251;;38115:296;37827:595;37639:790;;;;;;:::o;164031:268::-;164084:7;164125:11;164108:28;;164116:4;164108:28;;;:63;;;;;164157:14;164140:13;:31;164108:63;164104:188;;;164195:22;164188:29;;;;164104:188;164257:23;:21;:23::i;:::-;164250:30;;164031:268;;:::o;150198:382::-;150291:14;150375:4;150369:11;150406:10;150401:3;150394:23;150454:15;150447:4;150442:3;150438:14;150431:39;150507:10;150500:4;150495:3;150491:14;150484:34;150557:4;150552:3;150542:20;150532:30;;150343:230;150198:382;;;;:::o;54005:797::-;54111:17;54130:16;54148:14;54199:2;54179:9;:16;:22;54175:620;;54218:9;54242;54266:7;54491:4;54480:9;54476:20;54470:27;54465:32;;54541:4;54530:9;54526:20;54520:27;54515:32;;54599:4;54588:9;54584:20;54578:27;54575:1;54570:36;54565:41;;54642:25;54653:4;54659:1;54662;54665;54642:10;:25::i;:::-;54635:32;;;;;;;;;;;54175:620;54716:1;54720:35;54765:9;:16;54757:25;;54700:83;;;;;;54005:797;;;;;;:::o;59269:542::-;59365:20;59356:29;;;;;;;;:::i;:::-;;:5;:29;;;;;;;;:::i;:::-;;;59352:452;59402:7;59352:452;59463:29;59454:38;;;;;;;;:::i;:::-;;:5;:38;;;;;;;;:::i;:::-;;;59450:354;;59516:23;;;;;;;;;;;;;;59450:354;59570:35;59561:44;;;;;;;;:::i;:::-;;:5;:44;;;;;;;;:::i;:::-;;;59557:247;;59665:8;59657:17;;59629:46;;;;;;;;;;;:::i;:::-;;;;;;;;59557:247;59706:30;59697:39;;;;;;;;:::i;:::-;;:5;:39;;;;;;;;:::i;:::-;;;59693:111;;59783:8;59760:32;;;;;;;;;;;:::i;:::-;;;;;;;;59693:111;59269:542;;;:::o;157061:387::-;157120:13;157146:11;157160:16;157171:4;157160:10;:16::i;:::-;157146:30;;157266:17;157297:2;157286:14;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;157266:34;;157363:3;157358;157351:16;157404:4;157397;157392:3;157388:14;157381:28;157437:3;157430:10;;;;157061:387;;;:::o;164307:181::-;164362:7;162121:95;164421:11;164434:14;164450:13;164473:4;164399:80;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;164389:91;;;;;;164382:98;;164307:181;:::o;57151:1577::-;57282:17;57301:16;57319:14;58246:66;58241:1;58233:10;;:79;58229:166;;;58345:1;58349:30;58381:1;58329:54;;;;;;;;58229:166;58492:14;58509:24;58519:4;58525:1;58528;58531;58509:24;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58492:41;;58566:1;58548:20;;:6;:20;;;58544:115;;58601:1;58605:29;58644:1;58636:10;;58585:62;;;;;;;;;58544:115;58679:6;58687:20;58717:1;58709:10;;58671:49;;;;;;;57151:1577;;;;;;;;;:::o;157525:251::-;157586:7;157606:14;157659:4;157650;157623:33;;:40;157606:57;;157687:2;157678:6;:11;157674:71;;;157713:20;;;;;;;;;;;;;;157674:71;157762:6;157755:13;;;157525:251;;;:::o;7:126:1:-;44:7;84:42;77:5;73:54;62:65;;7:126;;;:::o;139:96::-;176:7;205:24;223:5;205:24;:::i;:::-;194:35;;139:96;;;:::o;241:118::-;328:24;346:5;328:24;:::i;:::-;323:3;316:37;241:118;;:::o;365:222::-;458:4;496:2;485:9;481:18;473:26;;509:71;577:1;566:9;562:17;553:6;509:71;:::i;:::-;365:222;;;;:::o;674:117::-;783:1;780;773:12;797:117;906:1;903;896:12;920:122;993:24;1011:5;993:24;:::i;:::-;986:5;983:35;973:63;;1032:1;1029;1022:12;973:63;920:122;:::o;1048:139::-;1094:5;1132:6;1119:20;1110:29;;1148:33;1175:5;1148:33;:::i;:::-;1048:139;;;;:::o;1193:77::-;1230:7;1259:5;1248:16;;1193:77;;;:::o;1276:122::-;1349:24;1367:5;1349:24;:::i;:::-;1342:5;1339:35;1329:63;;1388:1;1385;1378:12;1329:63;1276:122;:::o;1404:139::-;1450:5;1488:6;1475:20;1466:29;;1504:33;1531:5;1504:33;:::i;:::-;1404:139;;;;:::o;1549:474::-;1617:6;1625;1674:2;1662:9;1653:7;1649:23;1645:32;1642:119;;;1680:79;;:::i;:::-;1642:119;1800:1;1825:53;1870:7;1861:6;1850:9;1846:22;1825:53;:::i;:::-;1815:63;;1771:117;1927:2;1953:53;1998:7;1989:6;1978:9;1974:22;1953:53;:::i;:::-;1943:63;;1898:118;1549:474;;;;;:::o;2029:60::-;2057:3;2078:5;2071:12;;2029:60;;;:::o;2095:142::-;2145:9;2178:53;2196:34;2205:24;2223:5;2205:24;:::i;:::-;2196:34;:::i;:::-;2178:53;:::i;:::-;2165:66;;2095:142;;;:::o;2243:126::-;2293:9;2326:37;2357:5;2326:37;:::i;:::-;2313:50;;2243:126;;;:::o;2375:139::-;2438:9;2471:37;2502:5;2471:37;:::i;:::-;2458:50;;2375:139;;;:::o;2520:157::-;2620:50;2664:5;2620:50;:::i;:::-;2615:3;2608:63;2520:157;;:::o;2683:248::-;2789:4;2827:2;2816:9;2812:18;2804:26;;2840:84;2921:1;2910:9;2906:17;2897:6;2840:84;:::i;:::-;2683:248;;;;:::o;2937:155::-;3016:9;3049:37;3080:5;3049:37;:::i;:::-;3036:50;;2937:155;;;:::o;3098:189::-;3214:66;3274:5;3214:66;:::i;:::-;3209:3;3202:79;3098:189;;:::o;3293:280::-;3415:4;3453:2;3442:9;3438:18;3430:26;;3466:100;3563:1;3552:9;3548:17;3539:6;3466:100;:::i;:::-;3293:280;;;;:::o;3579:122::-;3652:24;3670:5;3652:24;:::i;:::-;3645:5;3642:35;3632:63;;3691:1;3688;3681:12;3632:63;3579:122;:::o;3707:139::-;3753:5;3791:6;3778:20;3769:29;;3807:33;3834:5;3807:33;:::i;:::-;3707:139;;;;:::o;3852:329::-;3911:6;3960:2;3948:9;3939:7;3935:23;3931:32;3928:119;;;3966:79;;:::i;:::-;3928:119;4086:1;4111:53;4156:7;4147:6;4136:9;4132:22;4111:53;:::i;:::-;4101:63;;4057:117;3852:329;;;;:::o;4187:118::-;4274:24;4292:5;4274:24;:::i;:::-;4269:3;4262:37;4187:118;;:::o;4311:222::-;4404:4;4442:2;4431:9;4427:18;4419:26;;4455:71;4523:1;4512:9;4508:17;4499:6;4455:71;:::i;:::-;4311:222;;;;:::o;4539:329::-;4598:6;4647:2;4635:9;4626:7;4622:23;4618:32;4615:119;;;4653:79;;:::i;:::-;4615:119;4773:1;4798:53;4843:7;4834:6;4823:9;4819:22;4798:53;:::i;:::-;4788:63;;4744:117;4539:329;;;;:::o;4874:332::-;4995:4;5033:2;5022:9;5018:18;5010:26;;5046:71;5114:1;5103:9;5099:17;5090:6;5046:71;:::i;:::-;5127:72;5195:2;5184:9;5180:18;5171:6;5127:72;:::i;:::-;4874:332;;;;;:::o;5212:86::-;5247:7;5287:4;5280:5;5276:16;5265:27;;5212:86;;;:::o;5304:112::-;5387:22;5403:5;5387:22;:::i;:::-;5382:3;5375:35;5304:112;;:::o;5422:214::-;5511:4;5549:2;5538:9;5534:18;5526:26;;5562:67;5626:1;5615:9;5611:17;5602:6;5562:67;:::i;:::-;5422:214;;;;:::o;5642:117::-;5751:1;5748;5741:12;5765:117;5874:1;5871;5864:12;5888:117;5997:1;5994;5987:12;6024:552;6081:8;6091:6;6141:3;6134:4;6126:6;6122:17;6118:27;6108:122;;6149:79;;:::i;:::-;6108:122;6262:6;6249:20;6239:30;;6292:18;6284:6;6281:30;6278:117;;;6314:79;;:::i;:::-;6278:117;6428:4;6420:6;6416:17;6404:29;;6482:3;6474:4;6466:6;6462:17;6452:8;6448:32;6445:41;6442:128;;;6489:79;;:::i;:::-;6442:128;6024:552;;;;;:::o;6582:1109::-;6688:6;6696;6704;6712;6720;6728;6777:3;6765:9;6756:7;6752:23;6748:33;6745:120;;;6784:79;;:::i;:::-;6745:120;6904:1;6929:53;6974:7;6965:6;6954:9;6950:22;6929:53;:::i;:::-;6919:63;;6875:117;7031:2;7057:53;7102:7;7093:6;7082:9;7078:22;7057:53;:::i;:::-;7047:63;;7002:118;7159:2;7185:53;7230:7;7221:6;7210:9;7206:22;7185:53;:::i;:::-;7175:63;;7130:118;7287:2;7313:53;7358:7;7349:6;7338:9;7334:22;7313:53;:::i;:::-;7303:63;;7258:118;7443:3;7432:9;7428:19;7415:33;7475:18;7467:6;7464:30;7461:117;;;7497:79;;:::i;:::-;7461:117;7610:64;7666:7;7657:6;7646:9;7642:22;7610:64;:::i;:::-;7592:82;;;;7386:298;6582:1109;;;;;;;;:::o;7697:90::-;7731:7;7774:5;7767:13;7760:21;7749:32;;7697:90;;;:::o;7793:109::-;7874:21;7889:5;7874:21;:::i;:::-;7869:3;7862:34;7793:109;;:::o;7908:210::-;7995:4;8033:2;8022:9;8018:18;8010:26;;8046:65;8108:1;8097:9;8093:17;8084:6;8046:65;:::i;:::-;7908:210;;;;:::o;8124:77::-;8161:7;8190:5;8179:16;;8124:77;;;:::o;8207:118::-;8294:24;8312:5;8294:24;:::i;:::-;8289:3;8282:37;8207:118;;:::o;8331:222::-;8424:4;8462:2;8451:9;8447:18;8439:26;;8475:71;8543:1;8532:9;8528:17;8519:6;8475:71;:::i;:::-;8331:222;;;;:::o;8559:149::-;8595:7;8635:66;8628:5;8624:78;8613:89;;8559:149;;;:::o;8714:115::-;8799:23;8816:5;8799:23;:::i;:::-;8794:3;8787:36;8714:115;;:::o;8835:99::-;8887:6;8921:5;8915:12;8905:22;;8835:99;;;:::o;8940:169::-;9024:11;9058:6;9053:3;9046:19;9098:4;9093:3;9089:14;9074:29;;8940:169;;;;:::o;9115:139::-;9204:6;9199:3;9194;9188:23;9245:1;9236:6;9231:3;9227:16;9220:27;9115:139;;;:::o;9260:102::-;9301:6;9352:2;9348:7;9343:2;9336:5;9332:14;9328:28;9318:38;;9260:102;;;:::o;9368:377::-;9456:3;9484:39;9517:5;9484:39;:::i;:::-;9539:71;9603:6;9598:3;9539:71;:::i;:::-;9532:78;;9619:65;9677:6;9672:3;9665:4;9658:5;9654:16;9619:65;:::i;:::-;9709:29;9731:6;9709:29;:::i;:::-;9704:3;9700:39;9693:46;;9460:285;9368:377;;;;:::o;9751:114::-;9818:6;9852:5;9846:12;9836:22;;9751:114;;;:::o;9871:184::-;9970:11;10004:6;9999:3;9992:19;10044:4;10039:3;10035:14;10020:29;;9871:184;;;;:::o;10061:132::-;10128:4;10151:3;10143:11;;10181:4;10176:3;10172:14;10164:22;;10061:132;;;:::o;10199:108::-;10276:24;10294:5;10276:24;:::i;:::-;10271:3;10264:37;10199:108;;:::o;10313:179::-;10382:10;10403:46;10445:3;10437:6;10403:46;:::i;:::-;10481:4;10476:3;10472:14;10458:28;;10313:179;;;;:::o;10498:113::-;10568:4;10600;10595:3;10591:14;10583:22;;10498:113;;;:::o;10647:732::-;10766:3;10795:54;10843:5;10795:54;:::i;:::-;10865:86;10944:6;10939:3;10865:86;:::i;:::-;10858:93;;10975:56;11025:5;10975:56;:::i;:::-;11054:7;11085:1;11070:284;11095:6;11092:1;11089:13;11070:284;;;11171:6;11165:13;11198:63;11257:3;11242:13;11198:63;:::i;:::-;11191:70;;11284:60;11337:6;11284:60;:::i;:::-;11274:70;;11130:224;11117:1;11114;11110:9;11105:14;;11070:284;;;11074:14;11370:3;11363:10;;10771:608;;;10647:732;;;;:::o;11385:1215::-;11734:4;11772:3;11761:9;11757:19;11749:27;;11786:69;11852:1;11841:9;11837:17;11828:6;11786:69;:::i;:::-;11902:9;11896:4;11892:20;11887:2;11876:9;11872:18;11865:48;11930:78;12003:4;11994:6;11930:78;:::i;:::-;11922:86;;12055:9;12049:4;12045:20;12040:2;12029:9;12025:18;12018:48;12083:78;12156:4;12147:6;12083:78;:::i;:::-;12075:86;;12171:72;12239:2;12228:9;12224:18;12215:6;12171:72;:::i;:::-;12253:73;12321:3;12310:9;12306:19;12297:6;12253:73;:::i;:::-;12336;12404:3;12393:9;12389:19;12380:6;12336:73;:::i;:::-;12457:9;12451:4;12447:20;12441:3;12430:9;12426:19;12419:49;12485:108;12588:4;12579:6;12485:108;:::i;:::-;12477:116;;11385:1215;;;;;;;;;;:::o;12606:90::-;12641:7;12684:5;12681:1;12670:20;12659:31;;12606:90;;;:::o;12702:112::-;12785:22;12801:5;12785:22;:::i;:::-;12780:3;12773:35;12702:112;;:::o;12820:214::-;12909:4;12947:2;12936:9;12932:18;12924:26;;12960:67;13024:1;13013:9;13009:17;13000:6;12960:67;:::i;:::-;12820:214;;;;:::o;13040:116::-;13110:21;13125:5;13110:21;:::i;:::-;13103:5;13100:32;13090:60;;13146:1;13143;13136:12;13090:60;13040:116;:::o;13162:133::-;13205:5;13243:6;13230:20;13221:29;;13259:30;13283:5;13259:30;:::i;:::-;13162:133;;;;:::o;13301:613::-;13375:6;13383;13391;13440:2;13428:9;13419:7;13415:23;13411:32;13408:119;;;13446:79;;:::i;:::-;13408:119;13566:1;13591:50;13633:7;13624:6;13613:9;13609:22;13591:50;:::i;:::-;13581:60;;13537:114;13690:2;13716:53;13761:7;13752:6;13741:9;13737:22;13716:53;:::i;:::-;13706:63;;13661:118;13818:2;13844:53;13889:7;13880:6;13869:9;13865:22;13844:53;:::i;:::-;13834:63;;13789:118;13301:613;;;;;:::o;13920:442::-;14069:4;14107:2;14096:9;14092:18;14084:26;;14120:71;14188:1;14177:9;14173:17;14164:6;14120:71;:::i;:::-;14201:72;14269:2;14258:9;14254:18;14245:6;14201:72;:::i;:::-;14283;14351:2;14340:9;14336:18;14327:6;14283:72;:::i;:::-;13920:442;;;;;;:::o;14368:963::-;14465:6;14473;14481;14489;14497;14546:3;14534:9;14525:7;14521:23;14517:33;14514:120;;;14553:79;;:::i;:::-;14514:120;14673:1;14698:53;14743:7;14734:6;14723:9;14719:22;14698:53;:::i;:::-;14688:63;;14644:117;14800:2;14826:53;14871:7;14862:6;14851:9;14847:22;14826:53;:::i;:::-;14816:63;;14771:118;14928:2;14954:53;14999:7;14990:6;14979:9;14975:22;14954:53;:::i;:::-;14944:63;;14899:118;15084:2;15073:9;15069:18;15056:32;15115:18;15107:6;15104:30;15101:117;;;15137:79;;:::i;:::-;15101:117;15250:64;15306:7;15297:6;15286:9;15282:22;15250:64;:::i;:::-;15232:82;;;;15027:297;14368:963;;;;;;;;:::o;15337:176::-;15477:28;15473:1;15465:6;15461:14;15454:52;15337:176;:::o;15519:366::-;15661:3;15682:67;15746:2;15741:3;15682:67;:::i;:::-;15675:74;;15758:93;15847:3;15758:93;:::i;:::-;15876:2;15871:3;15867:12;15860:19;;15519:366;;;:::o;15891:419::-;16057:4;16095:2;16084:9;16080:18;16072:26;;16144:9;16138:4;16134:20;16130:1;16119:9;16115:17;16108:47;16172:131;16298:4;16172:131;:::i;:::-;16164:139;;15891:419;;;:::o;16316:174::-;16456:26;16452:1;16444:6;16440:14;16433:50;16316:174;:::o;16496:366::-;16638:3;16659:67;16723:2;16718:3;16659:67;:::i;:::-;16652:74;;16735:93;16824:3;16735:93;:::i;:::-;16853:2;16848:3;16844:12;16837:19;;16496:366;;;:::o;16868:419::-;17034:4;17072:2;17061:9;17057:18;17049:26;;17121:9;17115:4;17111:20;17107:1;17096:9;17092:17;17085:47;17149:131;17275:4;17149:131;:::i;:::-;17141:139;;16868:419;;;:::o;17293:180::-;17341:77;17338:1;17331:88;17438:4;17435:1;17428:15;17462:4;17459:1;17452:15;17479:194;17519:4;17539:20;17557:1;17539:20;:::i;:::-;17534:25;;17573:20;17591:1;17573:20;:::i;:::-;17568:25;;17617:1;17614;17610:9;17602:17;;17641:1;17635:4;17632:11;17629:37;;;17646:18;;:::i;:::-;17629:37;17479:194;;;;:::o;17679:118::-;17766:24;17784:5;17766:24;:::i;:::-;17761:3;17754:37;17679:118;;:::o;17803:442::-;17952:4;17990:2;17979:9;17975:18;17967:26;;18003:71;18071:1;18060:9;18056:17;18047:6;18003:71;:::i;:::-;18084:72;18152:2;18141:9;18137:18;18128:6;18084:72;:::i;:::-;18166;18234:2;18223:9;18219:18;18210:6;18166:72;:::i;:::-;17803:442;;;;;;:::o;18251:172::-;18391:24;18387:1;18379:6;18375:14;18368:48;18251:172;:::o;18429:366::-;18571:3;18592:67;18656:2;18651:3;18592:67;:::i;:::-;18585:74;;18668:93;18757:3;18668:93;:::i;:::-;18786:2;18781:3;18777:12;18770:19;;18429:366;;;:::o;18801:419::-;18967:4;19005:2;18994:9;18990:18;18982:26;;19054:9;19048:4;19044:20;19040:1;19029:9;19025:17;19018:47;19082:131;19208:4;19082:131;:::i;:::-;19074:139;;18801:419;;;:::o;19226:180::-;19274:77;19271:1;19264:88;19371:4;19368:1;19361:15;19395:4;19392:1;19385:15;19412:173;19552:25;19548:1;19540:6;19536:14;19529:49;19412:173;:::o;19591:366::-;19733:3;19754:67;19818:2;19813:3;19754:67;:::i;:::-;19747:74;;19830:93;19919:3;19830:93;:::i;:::-;19948:2;19943:3;19939:12;19932:19;;19591:366;;;:::o;19963:419::-;20129:4;20167:2;20156:9;20152:18;20144:26;;20216:9;20210:4;20206:20;20202:1;20191:9;20187:17;20180:47;20244:131;20370:4;20244:131;:::i;:::-;20236:139;;19963:419;;;:::o;20388:224::-;20528:34;20524:1;20516:6;20512:14;20505:58;20597:7;20592:2;20584:6;20580:15;20573:32;20388:224;:::o;20618:366::-;20760:3;20781:67;20845:2;20840:3;20781:67;:::i;:::-;20774:74;;20857:93;20946:3;20857:93;:::i;:::-;20975:2;20970:3;20966:12;20959:19;;20618:366;;;:::o;20990:419::-;21156:4;21194:2;21183:9;21179:18;21171:26;;21243:9;21237:4;21233:20;21229:1;21218:9;21214:17;21207:47;21271:131;21397:4;21271:131;:::i;:::-;21263:139;;20990:419;;;:::o;21415:191::-;21455:3;21474:20;21492:1;21474:20;:::i;:::-;21469:25;;21508:20;21526:1;21508:20;:::i;:::-;21503:25;;21551:1;21548;21544:9;21537:16;;21572:3;21569:1;21566:10;21563:36;;;21579:18;;:::i;:::-;21563:36;21415:191;;;;:::o;21612:180::-;21660:77;21657:1;21650:88;21757:4;21754:1;21747:15;21781:4;21778:1;21771:15;21798:164;21938:16;21934:1;21926:6;21922:14;21915:40;21798:164;:::o;21968:366::-;22110:3;22131:67;22195:2;22190:3;22131:67;:::i;:::-;22124:74;;22207:93;22296:3;22207:93;:::i;:::-;22325:2;22320:3;22316:12;22309:19;;21968:366;;;:::o;22340:419::-;22506:4;22544:2;22533:9;22529:18;22521:26;;22593:9;22587:4;22583:20;22579:1;22568:9;22564:17;22557:47;22621:131;22747:4;22621:131;:::i;:::-;22613:139;;22340:419;;;:::o;22765:147::-;22866:11;22903:3;22888:18;;22765:147;;;;:::o;22918:114::-;;:::o;23038:398::-;23197:3;23218:83;23299:1;23294:3;23218:83;:::i;:::-;23211:90;;23310:93;23399:3;23310:93;:::i;:::-;23428:1;23423:3;23419:11;23412:18;;23038:398;;;:::o;23442:379::-;23626:3;23648:147;23791:3;23648:147;:::i;:::-;23641:154;;23812:3;23805:10;;23442:379;;;:::o;23827:177::-;23967:29;23963:1;23955:6;23951:14;23944:53;23827:177;:::o;24010:366::-;24152:3;24173:67;24237:2;24232:3;24173:67;:::i;:::-;24166:74;;24249:93;24338:3;24249:93;:::i;:::-;24367:2;24362:3;24358:12;24351:19;;24010:366;;;:::o;24382:419::-;24548:4;24586:2;24575:9;24571:18;24563:26;;24635:9;24629:4;24625:20;24621:1;24610:9;24606:17;24599:47;24663:131;24789:4;24663:131;:::i;:::-;24655:139;;24382:419;;;:::o;24807:143::-;24864:5;24895:6;24889:13;24880:22;;24911:33;24938:5;24911:33;:::i;:::-;24807:143;;;;:::o;24956:351::-;25026:6;25075:2;25063:9;25054:7;25050:23;25046:32;25043:119;;;25081:79;;:::i;:::-;25043:119;25201:1;25226:64;25282:7;25273:6;25262:9;25258:22;25226:64;:::i;:::-;25216:74;;25172:128;24956:351;;;;:::o;25313:179::-;25453:31;25449:1;25441:6;25437:14;25430:55;25313:179;:::o;25498:366::-;25640:3;25661:67;25725:2;25720:3;25661:67;:::i;:::-;25654:74;;25737:93;25826:3;25737:93;:::i;:::-;25855:2;25850:3;25846:12;25839:19;;25498:366;;;:::o;25870:419::-;26036:4;26074:2;26063:9;26059:18;26051:26;;26123:9;26117:4;26113:20;26109:1;26098:9;26094:17;26087:47;26151:131;26277:4;26151:131;:::i;:::-;26143:139;;25870:419;;;:::o;26295:220::-;26435:34;26431:1;26423:6;26419:14;26412:58;26504:3;26499:2;26491:6;26487:15;26480:28;26295:220;:::o;26521:366::-;26663:3;26684:67;26748:2;26743:3;26684:67;:::i;:::-;26677:74;;26760:93;26849:3;26760:93;:::i;:::-;26878:2;26873:3;26869:12;26862:19;;26521:366;;;:::o;26893:419::-;27059:4;27097:2;27086:9;27082:18;27074:26;;27146:9;27140:4;27136:20;27132:1;27121:9;27117:17;27110:47;27174:131;27300:4;27174:131;:::i;:::-;27166:139;;26893:419;;;:::o;27318:176::-;27458:28;27454:1;27446:6;27442:14;27435:52;27318:176;:::o;27500:366::-;27642:3;27663:67;27727:2;27722:3;27663:67;:::i;:::-;27656:74;;27739:93;27828:3;27739:93;:::i;:::-;27857:2;27852:3;27848:12;27841:19;;27500:366;;;:::o;27872:419::-;28038:4;28076:2;28065:9;28061:18;28053:26;;28125:9;28119:4;28115:20;28111:1;28100:9;28096:17;28089:47;28153:131;28279:4;28153:131;:::i;:::-;28145:139;;27872:419;;;:::o;28297:172::-;28437:24;28433:1;28425:6;28421:14;28414:48;28297:172;:::o;28475:366::-;28617:3;28638:67;28702:2;28697:3;28638:67;:::i;:::-;28631:74;;28714:93;28803:3;28714:93;:::i;:::-;28832:2;28827:3;28823:12;28816:19;;28475:366;;;:::o;28847:419::-;29013:4;29051:2;29040:9;29036:18;29028:26;;29100:9;29094:4;29090:20;29086:1;29075:9;29071:17;29064:47;29128:131;29254:4;29128:131;:::i;:::-;29120:139;;28847:419;;;:::o;29272:989::-;29557:4;29595:3;29584:9;29580:19;29572:27;;29609:71;29677:1;29666:9;29662:17;29653:6;29609:71;:::i;:::-;29690:72;29758:2;29747:9;29743:18;29734:6;29690:72;:::i;:::-;29772;29840:2;29829:9;29825:18;29816:6;29772:72;:::i;:::-;29854;29922:2;29911:9;29907:18;29898:6;29854:72;:::i;:::-;29936:73;30004:3;29993:9;29989:19;29980:6;29936:73;:::i;:::-;30019;30087:3;30076:9;30072:19;30063:6;30019:73;:::i;:::-;30102;30170:3;30159:9;30155:19;30146:6;30102:73;:::i;:::-;30185:69;30249:3;30238:9;30234:19;30225:6;30185:69;:::i;:::-;29272:989;;;;;;;;;;;:::o;30267:176::-;30407:28;30403:1;30395:6;30391:14;30384:52;30267:176;:::o;30449:366::-;30591:3;30612:67;30676:2;30671:3;30612:67;:::i;:::-;30605:74;;30688:93;30777:3;30688:93;:::i;:::-;30806:2;30801:3;30797:12;30790:19;;30449:366;;;:::o;30821:419::-;30987:4;31025:2;31014:9;31010:18;31002:26;;31074:9;31068:4;31064:20;31060:1;31049:9;31045:17;31038:47;31102:131;31228:4;31102:131;:::i;:::-;31094:139;;30821:419;;;:::o;31246:233::-;31285:3;31308:24;31326:5;31308:24;:::i;:::-;31299:33;;31354:66;31347:5;31344:77;31341:103;;31424:18;;:::i;:::-;31341:103;31471:1;31464:5;31460:13;31453:20;;31246:233;;;:::o;31485:167::-;31625:19;31621:1;31613:6;31609:14;31602:43;31485:167;:::o;31658:366::-;31800:3;31821:67;31885:2;31880:3;31821:67;:::i;:::-;31814:74;;31897:93;31986:3;31897:93;:::i;:::-;32015:2;32010:3;32006:12;31999:19;;31658:366;;;:::o;32030:419::-;32196:4;32234:2;32223:9;32219:18;32211:26;;32283:9;32277:4;32273:20;32269:1;32258:9;32254:17;32247:47;32311:131;32437:4;32311:131;:::i;:::-;32303:139;;32030:419;;;:::o;32455:410::-;32495:7;32518:20;32536:1;32518:20;:::i;:::-;32513:25;;32552:20;32570:1;32552:20;:::i;:::-;32547:25;;32607:1;32604;32600:9;32629:30;32647:11;32629:30;:::i;:::-;32618:41;;32808:1;32799:7;32795:15;32792:1;32789:22;32769:1;32762:9;32742:83;32719:139;;32838:18;;:::i;:::-;32719:139;32503:362;32455:410;;;;:::o;32871:180::-;32919:77;32916:1;32909:88;33016:4;33013:1;33006:15;33040:4;33037:1;33030:15;33057:185;33097:1;33114:20;33132:1;33114:20;:::i;:::-;33109:25;;33148:20;33166:1;33148:20;:::i;:::-;33143:25;;33187:1;33177:35;;33192:18;;:::i;:::-;33177:35;33234:1;33231;33227:9;33222:14;;33057:185;;;;:::o;33248:188::-;33286:3;33305:18;33321:1;33305:18;:::i;:::-;33300:23;;33337:18;33353:1;33337:18;:::i;:::-;33332:23;;33378:1;33375;33371:9;33364:16;;33401:4;33396:3;33393:13;33390:39;;;33409:18;;:::i;:::-;33390:39;33248:188;;;;:::o;33442:102::-;33484:8;33531:5;33528:1;33524:13;33503:34;;33442:102;;;:::o;33550:848::-;33611:5;33618:4;33642:6;33633:15;;33666:5;33657:14;;33680:712;33701:1;33691:8;33688:15;33680:712;;;33796:4;33791:3;33787:14;33781:4;33778:24;33775:50;;;33805:18;;:::i;:::-;33775:50;33855:1;33845:8;33841:16;33838:451;;;34270:4;34263:5;34259:16;34250:25;;33838:451;34320:4;34314;34310:15;34302:23;;34350:32;34373:8;34350:32;:::i;:::-;34338:44;;33680:712;;;33550:848;;;;;;;:::o;34404:1073::-;34458:5;34649:8;34639:40;;34670:1;34661:10;;34672:5;;34639:40;34698:4;34688:36;;34715:1;34706:10;;34717:5;;34688:36;34784:4;34832:1;34827:27;;;;34868:1;34863:191;;;;34777:277;;34827:27;34845:1;34836:10;;34847:5;;;34863:191;34908:3;34898:8;34895:17;34892:43;;;34915:18;;:::i;:::-;34892:43;34964:8;34961:1;34957:16;34948:25;;34999:3;34992:5;34989:14;34986:40;;;35006:18;;:::i;:::-;34986:40;35039:5;;;34777:277;;35163:2;35153:8;35150:16;35144:3;35138:4;35135:13;35131:36;35113:2;35103:8;35100:16;35095:2;35089:4;35086:12;35082:35;35066:111;35063:246;;;35219:8;35213:4;35209:19;35200:28;;35254:3;35247:5;35244:14;35241:40;;;35261:18;;:::i;:::-;35241:40;35294:5;;35063:246;35334:42;35372:3;35362:8;35356:4;35353:1;35334:42;:::i;:::-;35319:57;;;;35408:4;35403:3;35399:14;35392:5;35389:25;35386:51;;;35417:18;;:::i;:::-;35386:51;35466:4;35459:5;35455:16;35446:25;;34404:1073;;;;;;:::o;35483:281::-;35541:5;35565:23;35583:4;35565:23;:::i;:::-;35557:31;;35609:25;35625:8;35609:25;:::i;:::-;35597:37;;35653:104;35690:66;35680:8;35674:4;35653:104;:::i;:::-;35644:113;;35483:281;;;;:::o;35770:180::-;35818:77;35815:1;35808:88;35915:4;35912:1;35905:15;35939:4;35936:1;35929:15;35956:320;36000:6;36037:1;36031:4;36027:12;36017:22;;36084:1;36078:4;36074:12;36105:18;36095:81;;36161:4;36153:6;36149:17;36139:27;;36095:81;36223:2;36215:6;36212:14;36192:18;36189:38;36186:84;;36242:18;;:::i;:::-;36186:84;36007:269;35956:320;;;:::o;36282:172::-;36422:24;36418:1;36410:6;36406:14;36399:48;36282:172;:::o;36460:366::-;36602:3;36623:67;36687:2;36682:3;36623:67;:::i;:::-;36616:74;;36699:93;36788:3;36699:93;:::i;:::-;36817:2;36812:3;36808:12;36801:19;;36460:366;;;:::o;36832:419::-;36998:4;37036:2;37025:9;37021:18;37013:26;;37085:9;37079:4;37075:20;37071:1;37060:9;37056:17;37049:47;37113:131;37239:4;37113:131;:::i;:::-;37105:139;;36832:419;;;:::o;37257:105::-;37293:7;37333:22;37326:5;37322:34;37311:45;;37257:105;;;:::o;37368:120::-;37440:23;37457:5;37440:23;:::i;:::-;37433:5;37430:34;37420:62;;37478:1;37475;37468:12;37420:62;37368:120;:::o;37494:141::-;37550:5;37581:6;37575:13;37566:22;;37597:32;37623:5;37597:32;:::i;:::-;37494:141;;;;:::o;37641:76::-;37677:7;37706:5;37695:16;;37641:76;;;:::o;37723:120::-;37795:23;37812:5;37795:23;:::i;:::-;37788:5;37785:34;37775:62;;37833:1;37830;37823:12;37775:62;37723:120;:::o;37849:141::-;37905:5;37936:6;37930:13;37921:22;;37952:32;37978:5;37952:32;:::i;:::-;37849:141;;;;:::o;37996:971::-;38099:6;38107;38115;38123;38131;38180:3;38168:9;38159:7;38155:23;38151:33;38148:120;;;38187:79;;:::i;:::-;38148:120;38307:1;38332:63;38387:7;38378:6;38367:9;38363:22;38332:63;:::i;:::-;38322:73;;38278:127;38444:2;38470:63;38525:7;38516:6;38505:9;38501:22;38470:63;:::i;:::-;38460:73;;38415:128;38582:2;38608:64;38664:7;38655:6;38644:9;38640:22;38608:64;:::i;:::-;38598:74;;38553:129;38721:2;38747:64;38803:7;38794:6;38783:9;38779:22;38747:64;:::i;:::-;38737:74;;38692:129;38860:3;38887:63;38942:7;38933:6;38922:9;38918:22;38887:63;:::i;:::-;38877:73;;38831:129;37996:971;;;;;;;;:::o;38973:174::-;39113:26;39109:1;39101:6;39097:14;39090:50;38973:174;:::o;39153:366::-;39295:3;39316:67;39380:2;39375:3;39316:67;:::i;:::-;39309:74;;39392:93;39481:3;39392:93;:::i;:::-;39510:2;39505:3;39501:12;39494:19;;39153:366;;;:::o;39525:419::-;39691:4;39729:2;39718:9;39714:18;39706:26;;39778:9;39772:4;39768:20;39764:1;39753:9;39749:17;39742:47;39806:131;39932:4;39806:131;:::i;:::-;39798:139;;39525:419;;;:::o;39950:168::-;40090:20;40086:1;40078:6;40074:14;40067:44;39950:168;:::o;40124:366::-;40266:3;40287:67;40351:2;40346:3;40287:67;:::i;:::-;40280:74;;40363:93;40452:3;40363:93;:::i;:::-;40481:2;40476:3;40472:12;40465:19;;40124:366;;;:::o;40496:419::-;40662:4;40700:2;40689:9;40685:18;40677:26;;40749:9;40743:4;40739:20;40735:1;40724:9;40720:17;40713:47;40777:131;40903:4;40777:131;:::i;:::-;40769:139;;40496:419;;;:::o;40921:172::-;41061:24;41057:1;41049:6;41045:14;41038:48;40921:172;:::o;41099:366::-;41241:3;41262:67;41326:2;41321:3;41262:67;:::i;:::-;41255:74;;41338:93;41427:3;41338:93;:::i;:::-;41456:2;41451:3;41447:12;41440:19;;41099:366;;;:::o;41471:419::-;41637:4;41675:2;41664:9;41660:18;41652:26;;41724:9;41718:4;41714:20;41710:1;41699:9;41695:17;41688:47;41752:131;41878:4;41752:131;:::i;:::-;41744:139;;41471:419;;;:::o;41896:175::-;42036:27;42032:1;42024:6;42020:14;42013:51;41896:175;:::o;42077:366::-;42219:3;42240:67;42304:2;42299:3;42240:67;:::i;:::-;42233:74;;42316:93;42405:3;42316:93;:::i;:::-;42434:2;42429:3;42425:12;42418:19;;42077:366;;;:::o;42449:419::-;42615:4;42653:2;42642:9;42638:18;42630:26;;42702:9;42696:4;42692:20;42688:1;42677:9;42673:17;42666:47;42730:131;42856:4;42730:131;:::i;:::-;42722:139;;42449:419;;;:::o;42874:163::-;43014:15;43010:1;43002:6;42998:14;42991:39;42874:163;:::o;43043:366::-;43185:3;43206:67;43270:2;43265:3;43206:67;:::i;:::-;43199:74;;43282:93;43371:3;43282:93;:::i;:::-;43400:2;43395:3;43391:12;43384:19;;43043:366;;;:::o;43415:419::-;43581:4;43619:2;43608:9;43604:18;43596:26;;43668:9;43662:4;43658:20;43654:1;43643:9;43639:17;43632:47;43696:131;43822:4;43696:131;:::i;:::-;43688:139;;43415:419;;;:::o;43840:161::-;43980:13;43976:1;43968:6;43964:14;43957:37;43840:161;:::o;44007:366::-;44149:3;44170:67;44234:2;44229:3;44170:67;:::i;:::-;44163:74;;44246:93;44335:3;44246:93;:::i;:::-;44364:2;44359:3;44355:12;44348:19;;44007:366;;;:::o;44379:419::-;44545:4;44583:2;44572:9;44568:18;44560:26;;44632:9;44626:4;44622:20;44618:1;44607:9;44603:17;44596:47;44660:131;44786:4;44660:131;:::i;:::-;44652:139;;44379:419;;;:::o;44804:180::-;44852:77;44849:1;44842:88;44949:4;44946:1;44939:15;44973:4;44970:1;44963:15;44990:664;45195:4;45233:3;45222:9;45218:19;45210:27;;45247:71;45315:1;45304:9;45300:17;45291:6;45247:71;:::i;:::-;45328:72;45396:2;45385:9;45381:18;45372:6;45328:72;:::i;:::-;45410;45478:2;45467:9;45463:18;45454:6;45410:72;:::i;:::-;45492;45560:2;45549:9;45545:18;45536:6;45492:72;:::i;:::-;45574:73;45642:3;45631:9;45627:19;45618:6;45574:73;:::i;:::-;44990:664;;;;;;;;:::o;45660:545::-;45833:4;45871:3;45860:9;45856:19;45848:27;;45885:71;45953:1;45942:9;45938:17;45929:6;45885:71;:::i;:::-;45966:68;46030:2;46019:9;46015:18;46006:6;45966:68;:::i;:::-;46044:72;46112:2;46101:9;46097:18;46088:6;46044:72;:::i;:::-;46126;46194:2;46183:9;46179:18;46170:6;46126:72;:::i;:::-;45660:545;;;;;;;:::o
Swarm Source
ipfs://37e1a3a162c218693e703a897e7337a0bc661dd1003e5a7738bb7a7e40842138
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.