Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 6 from a total of 6 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw All | 20318232 | 483 days ago | IN | 0 ETH | 0.00056784 | ||||
| Deposit | 20314011 | 483 days ago | IN | 0 ETH | 0.0028963 | ||||
| Deposit | 20313913 | 483 days ago | IN | 0 ETH | 0.00296229 | ||||
| Deposit | 20313544 | 483 days ago | IN | 0 ETH | 0.00259028 | ||||
| Deposit | 20311936 | 484 days ago | IN | 0 ETH | 0.00046405 | ||||
| Deposit | 20311708 | 484 days ago | IN | 0 ETH | 0.00060296 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Sale
Compiler Version
v0.8.20+commit.a1b79de6
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: None
// Developed by Liteflow.com
pragma solidity 0.8.20;
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol';
import '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import '@openzeppelin/contracts/utils/ReentrancyGuard.sol';
/**
* @notice Sale Contract
*/
contract Sale is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20Metadata;
/**
* Events
*/
/**
* @notice Deposit event
*/
event Deposit(
address indexed account,
uint256 amount,
uint8 tierLevel,
uint256 fees
);
/**
* @notice Refund event
*/
event Refund(
address indexed account,
uint256 winningAmount,
uint256 loosingAmount
);
/**
* @notice Claim event
*/
event Claim(
address indexed account,
uint256 claimedAmountInToken,
uint256 refundedAmountInCurrency
);
/**
* Errors
*/
/**
* @notice Thrown when sale is full
*/
error HardCapReached();
/**
* @notice Thrown when the deposit period is closed
*/
error DepositClosed();
/**
* @notice Thrown when the refund period is closed
*/
error RefundClosed();
/**
* @notice Thrown when the claim period is closed
*/
error ClaimClosed();
/**
* @notice Thrown when the signature is invalid
*/
error InvalidSignature();
/**
* @notice Thrown when the tier limit is reached
*/
error TierLimitReached();
/**
* @notice Thrown when the amount to transfer is zero
*/
error NothingToTransfer();
/**
* @notice Thrown when the user has already claimed
*/
error AlreadyClaimed();
/**
* @notice Thrown when the user has been already refunded
*/
error AlreadyRefunded();
/**
* @notice Thrown when the dates are invalid
*/
error InvalidDates();
/**
* @notice Thrown when the amount does not respect the deposit increment
*/
error InvalidIncrement();
/**
* @notice Thrown when the winning and loosing amounts are not equal to the deposit amount
*/
error InvalidAmounts();
/**
* @notice Thrown when the total winning amount is reached
*/
error TotalWinningAmountReached();
/**
* @notice Thrown when owner want to withdraw but the claim or refund periods are still open
*/
error WithdrawClosed();
/**
* @notice Thrown when the owner try to change the claim or refund config but it is already set
*/
error ConfigAlreadySet();
/**
* @notice Thrown when the config is not set but required
*/
error ConfigNotSet();
/**
* @notice Thrown when the owner try to withdraw winning amount and fees but it was already done
*/
error AlreadyWithdrawnWinningAmountAndFees();
/**
* Authorizer configuration
*/
/**
* @notice The authorizer wallet
*/
address public authorizer;
/**
* Deposit configuration
*/
/**
* @notice The token to use to participate in the sale
*/
IERC20Metadata public immutable currencyToken;
/**
* @notice The maximum total amount of token to purchase. In currency token.
*/
uint256 public immutable hardCap;
/**
* @notice The limit of each tier. In currency token.
*/
uint256[] private tiersLimit;
/**
* @notice The fees of each tier. In basis point.
*/
uint16[] private tiersFeesBasisPoint;
/**
* @notice The start date of the deposit period
*/
uint32 public immutable depositStartDate;
/**
* @notice The end date of the deposit period
*/
uint32 public immutable depositEndDate;
/**
* @notice The increment in which the deposit amount can be specify. In currency token.
*/
uint256 public immutable depositIncrement;
/**
* Claim configuration
*/
/**
* @notice The token to claim
* @dev If set to the zero address, the claim is not activated yet.
*/
IERC20Metadata public token;
/**
* @notice The numerator price of the token in currency token.
*/
uint256 public tokenPriceNumerator;
/**
* @notice The denominator price of the token in currency token.
*/
uint256 public tokenPriceDenominator;
/**
* @notice The start date of the claim period
* @dev If set to 0, the claim is not activated yet.
*/
uint32 public claimStartDate;
/**
* @notice The end date of the claim period
*/
uint32 public claimEndDate;
/**
* @notice The vesting end date of the claim period. All token are claimable at this date.
*/
uint32 public claimVestingEndDate;
/**
* @notice The vesting cliff in basis point of token claimable at the claim start date. The rest will be unlocked linearly until the claimVestingEndDate.
*/
uint16 public claimVestingCliffBasisPoint;
/**
* @notice The total amount of currency tokens that can be claim for tokens.
*/
uint256 public totalWinningAmount;
/**
* Refund configuration
*/
/**
* @notice The start date of the refund period
* @dev If set to 0, the refund is not activated yet.
*/
uint32 public refundStartDate;
/**
* @notice The end date of the refund period
*/
uint32 public refundEndDate;
/**
* State managed by the contract
*/
/**
* @notice The total amount of currency tokens deposited.
* @dev Managed by the contract
*/
uint256 public totalDepositedAmount;
/**
* @notice The total amount of currency tokens claimed.
* @dev Managed by the contract
*/
uint256 public totalClaimedAmount;
/**
* @notice The total winning amount of currency tokens refunded.
* @dev Managed by the contract
*/
uint256 public totalRefundedWinningAmount;
/**
* @notice The total loosing amount of currency tokens refunded.
* @dev Managed by the contract
*/
uint256 public totalRefundedLoosingAmount;
/**
* @notice The total fees of currency tokens deposited.
* @dev Managed by the contract
*/
uint256 public totalFees;
/**
* @notice The deposited amount for each user.
* @dev Managed by the contract
*/
mapping(address account => uint256 amount) private deposits;
/**
* @notice Track claimed amount for each user.
* @dev Managed by the contract
*/
mapping(address account => uint256 amount) private claims;
/**
* @notice Track refunded amount for each user.
* @dev Managed by the contract
*/
mapping(address account => uint256 amount) private refunds;
/**
* @notice Track if the winning amount and fees are already withdrawn
* @dev Managed by the contract
*/
bool public alreadyWithdrawnWinningAmountAndFees;
/**
* @dev Constructor
*/
constructor(
address initialOwner_,
address authorizer_,
IERC20Metadata currencyToken_,
uint256 hardCap_,
uint32 depositStartDate_,
uint32 depositEndDate_,
uint256 depositIncrement_,
uint256[] memory tiersLimit_,
uint16[] memory tiersFeesBasisPoint_
) Ownable(initialOwner_) {
authorizer = authorizer_;
currencyToken = currencyToken_;
hardCap = hardCap_;
depositStartDate = depositStartDate_;
depositEndDate = depositEndDate_;
depositIncrement = depositIncrement_;
tiersLimit = tiersLimit_;
tiersFeesBasisPoint = tiersFeesBasisPoint_;
// check the dates
if (depositStartDate == 0) revert InvalidDates();
if (depositEndDate == 0) revert InvalidDates();
if (depositStartDate >= depositEndDate) revert InvalidDates();
// check zero values
if (authorizer == address(0)) revert InvalidSignature();
if (depositIncrement == 0) revert InvalidIncrement();
// check hardCap is multiple of deposit increment
if (hardCap % depositIncrement != 0) revert InvalidIncrement();
// check currency token implements balanceOf function
currencyToken.balanceOf(address(this));
}
/**
* @notice Participate in the sale
*/
function deposit(
uint256 amount_,
uint8 tierLevel_,
bytes memory signature_,
uint32 signatureExpiration_
) external nonReentrant {
// check if the sale is open
if (
block.timestamp < depositStartDate ||
block.timestamp > depositEndDate
) revert DepositClosed();
// check if signature is expired
if (block.timestamp > signatureExpiration_) revert InvalidSignature();
// check signature is signed by authorizer
if (
!SignatureChecker.isValidSignatureNow(
authorizer,
MessageHashUtils.toEthSignedMessageHash(
keccak256(
abi.encodePacked(
block.chainid,
address(this),
'deposit',
msg.sender,
tierLevel_,
amount_,
signatureExpiration_
)
)
),
signature_
)
) revert InvalidSignature();
// calculate the fees
uint256 _fees = (amount_ * tiersFeesBasisPoint[tierLevel_]) / 10_000;
// update the total fees
totalFees = totalFees + _fees;
// save balance before transfer
uint256 _contractBalance = currencyToken.balanceOf(address(this));
// transfer amount with fees
currencyToken.safeTransferFrom(
msg.sender,
address(this),
amount_ + _fees
);
// calculate actual amount transferred
uint256 _transferredAmount = currencyToken.balanceOf(address(this)) -
_contractBalance -
_fees;
// check amount is not 0
if (_transferredAmount == 0) revert NothingToTransfer();
// check amount is multiple of deposit increment
if (_transferredAmount % depositIncrement != 0)
revert InvalidIncrement();
// update total deposited amount
totalDepositedAmount = totalDepositedAmount + _transferredAmount;
// check if the hard cap is reached
if (hardCap > 0 && totalDepositedAmount > hardCap)
revert HardCapReached();
// calculate new balance
uint256 _balance = deposits[msg.sender] + _transferredAmount;
// check if the tier limit is reached
if (_balance > tiersLimit[tierLevel_]) revert TierLimitReached();
// update balance
deposits[msg.sender] = _balance;
// emit event
emit Deposit(msg.sender, _transferredAmount, tierLevel_, _fees);
}
/**
* @notice Claim the tokens and refund the currency token.
*/
function claim(
uint256 winningAmount_,
uint256 loosingAmount_,
bytes memory signature_,
uint32 signatureExpiration_
) external {
// check if the claim is open
if (block.timestamp < claimStartDate || block.timestamp > claimEndDate)
revert ClaimClosed();
// check if signature is expired
if (block.timestamp > signatureExpiration_) revert InvalidSignature();
// check signature is signed by authorizer
if (
!SignatureChecker.isValidSignatureNow(
authorizer,
MessageHashUtils.toEthSignedMessageHash(
keccak256(
abi.encodePacked(
block.chainid,
address(this),
'claim',
msg.sender,
winningAmount_,
loosingAmount_,
signatureExpiration_
)
)
),
signature_
)
) revert InvalidSignature();
// check winningAmount is multiple of deposit increment
if (winningAmount_ % depositIncrement != 0) revert InvalidIncrement();
// check loosingAmount is multiple of deposit increment
if (loosingAmount_ % depositIncrement != 0) revert InvalidIncrement();
// get deposited amount
uint256 _depositedAmount = deposits[msg.sender];
// get claimed amount
uint256 _claimedAmount = claims[msg.sender];
// get refunded amount
uint256 _refundedAmount = refunds[msg.sender];
// check if already fully refunded
if (_refundedAmount > loosingAmount_) revert AlreadyRefunded();
// check deposit is not 0
if (_depositedAmount == 0) revert NothingToTransfer();
// check sum of winning and loosing amount is not more than the user's deposit
if (winningAmount_ + loosingAmount_ > _depositedAmount)
revert InvalidAmounts();
// get claimable amount
uint256 _claimableAmount = claimableAmountOf(
msg.sender,
winningAmount_
);
// skip update if nothing to claim
if (_claimableAmount > 0) {
// update user claimed amount
claims[msg.sender] = _claimedAmount + _claimableAmount;
// update total claimed amount
totalClaimedAmount = totalClaimedAmount + _claimableAmount;
// check if the total claimed amount is not higher than the total winning amount
if (totalClaimedAmount > totalWinningAmount)
revert TotalWinningAmountReached();
}
// calculate the remaining amount to refund
uint256 _refundableAmount = loosingAmount_ - _refundedAmount;
// skip update if nothing to refund
if (_refundableAmount > 0) {
// update user claimed amount
refunds[msg.sender] = _refundedAmount + _refundableAmount;
// update total refunded loosing amount
totalRefundedLoosingAmount =
totalRefundedLoosingAmount +
_refundableAmount;
}
// check if there is something to transfer
if (_claimableAmount == 0 && _refundableAmount == 0)
revert NothingToTransfer();
// calculate the claimable amount in token
uint256 _claimableAmountInToken = _claimableAmount > 0
? (_claimableAmount *
10 ** token.decimals() *
tokenPriceDenominator) / tokenPriceNumerator
: 0;
// transfer claimable token
if (_claimableAmountInToken > 0)
token.safeTransfer(msg.sender, _claimableAmountInToken);
// transfer refund currency
if (_refundableAmount > 0)
currencyToken.safeTransfer(msg.sender, _refundableAmount);
// emit event
emit Claim(msg.sender, _claimableAmountInToken, _refundableAmount);
}
/**
* @notice Refund all your deposit
*/
function refund(
uint256 winningAmount_,
uint256 loosingAmount_,
bytes memory signature_,
uint32 signatureExpiration_
) external {
// check if the refund is open
if (
block.timestamp < refundStartDate || block.timestamp > refundEndDate
) revert RefundClosed();
// check if signature is expired
if (block.timestamp > signatureExpiration_) revert InvalidSignature();
// check signature is signed by authorizer
if (
!SignatureChecker.isValidSignatureNow(
authorizer,
MessageHashUtils.toEthSignedMessageHash(
keccak256(
abi.encodePacked(
block.chainid,
address(this),
'refund',
msg.sender,
winningAmount_,
loosingAmount_,
signatureExpiration_
)
)
),
signature_
)
) revert InvalidSignature();
// check winningAmount is multiple of deposit increment
if (winningAmount_ % depositIncrement != 0) revert InvalidIncrement();
// check loosingAmount is multiple of deposit increment
if (loosingAmount_ % depositIncrement != 0) revert InvalidIncrement();
// check if already claimed
if (claims[msg.sender] > 0) revert AlreadyClaimed();
// check if already refunded
if (refunds[msg.sender] > 0) revert AlreadyRefunded();
// get deposited amount
uint256 _depositedAmount = deposits[msg.sender];
// check deposit is not 0
if (_depositedAmount == 0) revert NothingToTransfer();
// check winning amount and loosing amount are equal to the user's deposit
if (winningAmount_ + loosingAmount_ != _depositedAmount)
revert InvalidAmounts();
// mark the user as refunded
refunds[msg.sender] = _depositedAmount;
// update total refunded winning amounts
totalRefundedWinningAmount =
totalRefundedWinningAmount +
winningAmount_;
// update total refunded loosing amounts
totalRefundedLoosingAmount =
totalRefundedLoosingAmount +
loosingAmount_;
// transfer currency token back to user
currencyToken.safeTransfer(msg.sender, _depositedAmount);
// emit event
emit Refund(msg.sender, winningAmount_, loosingAmount_);
}
/**
* @notice Get the deposited amount of a user
*/
function depositedAmountOf(
address account_
) external view returns (uint256) {
return deposits[account_];
}
/**
* @notice Get the claimed amount of a user
*/
function claimedAmountOf(address account_) external view returns (uint256) {
return claims[account_];
}
/**
* @notice Get the refunded amount of a user
*/
function refundedAmountOf(
address account_
) external view returns (uint256) {
return refunds[account_];
}
/**
* @notice Get the limit of a tier
*/
function getTiersLimit() external view returns (uint256[] memory) {
return tiersLimit;
}
/**
* @notice Get the fees of a tier
*/
function getTiersFeesBasisPoint() external view returns (uint16[] memory) {
return tiersFeesBasisPoint;
}
/**
* @notice Get the claimable amount of a user. This take into account the vesting.
*/
function claimableAmountOf(
address account_,
uint256 winningAmount_
) public view returns (uint256) {
// check if claim period has started
if (block.timestamp < claimStartDate) return 0;
// return remaining amount if vesting is over
if (block.timestamp >= claimVestingEndDate)
return winningAmount_ - claims[account_];
// calculate vested amount using a linear vesting schedule
return
(((winningAmount_ * claimVestingCliffBasisPoint) / 10_000) + // cliff
(((winningAmount_ * (10_000 - claimVestingCliffBasisPoint)) /
10_000) * (block.timestamp - claimStartDate)) / // rest linearly unlocked
(claimVestingEndDate - claimStartDate)) - claims[account_];
}
/**
* @notice Set the claim and refund configuration. Only the owner can call this function
*/
function setClaimConfig(
IERC20Metadata token_,
uint256 tokenPriceNumerator_,
uint256 tokenPriceDenominator_,
uint32 claimStartDate_,
uint32 claimEndDate_,
uint32 claimVestingEndDate_,
uint16 claimVestingCliffBasisPoint_,
uint256 totalWinningAmount_
) external onlyOwner {
// check if config is already set
if (token != IERC20Metadata(address(0))) revert ConfigAlreadySet();
// set
token = token_;
tokenPriceNumerator = tokenPriceNumerator_;
tokenPriceDenominator = tokenPriceDenominator_;
claimStartDate = claimStartDate_;
claimEndDate = claimEndDate_;
claimVestingEndDate = claimVestingEndDate_;
claimVestingCliffBasisPoint = claimVestingCliffBasisPoint_;
totalWinningAmount = totalWinningAmount_;
// check the dates
if (claimStartDate == 0) revert InvalidDates();
if (claimEndDate == 0) revert InvalidDates();
if (claimStartDate >= claimEndDate) revert InvalidDates();
if (depositEndDate >= claimStartDate) revert InvalidDates();
if (claimVestingEndDate < claimStartDate) revert InvalidDates();
if (claimVestingEndDate > claimEndDate) revert InvalidDates();
// check amounts
if (tokenPriceNumerator == 0) revert InvalidAmounts();
if (tokenPriceDenominator == 0) revert InvalidAmounts();
if (totalWinningAmount == 0) revert InvalidAmounts();
// check basis point is between 0 and 10,000
if (claimVestingCliffBasisPoint > 10_000) revert InvalidAmounts();
// check token implements decimals and balanceOf function
token.decimals();
token.balanceOf(address(this));
}
/**
* @notice Set the claim and refund configuration. Only the owner can call this function
*/
function setRefundConfig(
uint32 refundStartDate_,
uint32 refundEndDate_
) external onlyOwner {
// check if config is already set
if (refundStartDate != 0) revert ConfigAlreadySet();
// set
refundStartDate = refundStartDate_;
refundEndDate = refundEndDate_;
// check the dates
if (refundStartDate == 0) revert InvalidDates();
if (refundEndDate == 0) revert InvalidDates();
if (refundStartDate >= refundEndDate) revert InvalidDates();
if (depositEndDate >= refundStartDate) revert InvalidDates();
}
/**
* @notice Withdraw winning amount with fees from the contract after the deposit and refund periods are closed. Only the owner can call this function
*/
function withdrawWinningAmountWithFees(address to_) external onlyOwner {
// check this function was not already executed
if (alreadyWithdrawnWinningAmountAndFees)
revert AlreadyWithdrawnWinningAmountAndFees();
alreadyWithdrawnWinningAmountAndFees = true;
// check the deposit period is closed
if (block.timestamp <= depositEndDate) revert WithdrawClosed();
// check the refund period is closed
if (refundEndDate > 0 && block.timestamp <= refundEndDate)
revert WithdrawClosed();
// cap the total winning amount in case the sale is not full
uint256 _cappedTotalWinningAmount = totalDepositedAmount <
totalWinningAmount
? totalDepositedAmount
: totalWinningAmount;
// calculate withdrawable winning amount
uint256 _withdrawableWinningAmount = _cappedTotalWinningAmount +
totalFees -
totalRefundedWinningAmount;
// check there is something to transfer
if (_withdrawableWinningAmount == 0) revert NothingToTransfer();
// transfer currency
currencyToken.safeTransfer(to_, _withdrawableWinningAmount);
}
/**
* @notice Withdraw excess token. Only the owner can call this function
*/
function withdrawExcessToken(address to_) external onlyOwner {
// check config is set
if (token == IERC20Metadata(address(0))) revert ConfigNotSet();
// cap the total winning amount in case the sale is not full
uint256 _cappedTotalWinningAmount = totalDepositedAmount <
totalWinningAmount
? totalDepositedAmount
: totalWinningAmount;
// get token balance
uint256 _tokenBalance = token.balanceOf(address(this));
// reduce token balance if both tokens are the same
if (token == currencyToken) {
// calculate the reserved balance
uint256 _reservedBalance = totalDepositedAmount -
_cappedTotalWinningAmount -
totalRefundedLoosingAmount;
// increase reserved balance with amount that can be withdrawn by function withdrawWinningAmountWithFees
if (!alreadyWithdrawnWinningAmountAndFees) {
// calculate withdrawable winning amount, same as function withdrawWinningAmountWithFees
uint256 _withdrawableWinningAmount = _cappedTotalWinningAmount +
totalFees -
totalRefundedWinningAmount;
// add the amount that can be withdrawn by function withdrawWinningAmountWithFees
_reservedBalance =
_reservedBalance +
_withdrawableWinningAmount;
}
// remove reserved balance from token balance
// _tokenBalance is always greater than or equal to _reservedBalance
_tokenBalance = _tokenBalance - _reservedBalance;
}
// calculate the claimable amount
uint256 _claimableAmount = _cappedTotalWinningAmount -
totalClaimedAmount -
totalRefundedWinningAmount;
// convert claimable amount in token
uint256 _claimableAmountInToken = (_claimableAmount *
10 ** token.decimals() *
tokenPriceDenominator) / tokenPriceNumerator;
// check token balance is not less than the claimable amount
if (_tokenBalance <= _claimableAmountInToken)
revert NothingToTransfer();
// transfer token
token.safeTransfer(to_, _tokenBalance - _claimableAmountInToken);
}
/**
* @notice Withdraw all token from the contract after the deposit, claim and refund periods are closed. Only the owner can call this function
*/
function withdrawAll(address to_) external onlyOwner {
// check the deposit period is closed
if (block.timestamp <= depositEndDate) revert WithdrawClosed();
// check the claim period is closed
if (claimEndDate > 0 && block.timestamp <= claimEndDate)
revert WithdrawClosed();
// check the refund period is closed
if (refundEndDate > 0 && block.timestamp <= refundEndDate)
revert WithdrawClosed();
// get currency balance
uint256 _currencyBalance = currencyToken.balanceOf(address(this));
// get token balance
uint256 _tokenBalance = token != IERC20Metadata(address(0)) &&
token != currencyToken
? token.balanceOf(address(this))
: 0;
// check there is something to transfer
if (_currencyBalance == 0 && _tokenBalance == 0)
revert NothingToTransfer();
// transfer currency
if (_currencyBalance > 0)
currencyToken.safeTransfer(to_, _currencyBalance);
// transfer token
if (_tokenBalance > 0) token.safeTransfer(to_, _tokenBalance);
}
/**
* @notice Set the authorizer wallet, can only be called by the owner
*/
function setAuthorizer(address authorizer_) external onlyOwner {
authorizer = authorizer_;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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, RecoverError, bytes32) {
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.
/// @solidity memory-safe-assembly
assembly {
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[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
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, RecoverError, bytes32) {
// 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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @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[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-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) {
/// @solidity memory-safe-assembly
assembly {
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 EIP-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 EIP-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 (EIP-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) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.20;
import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Safe Wallet (previously Gnosis Safe).
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
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 overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
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 division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev 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^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + 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^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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^256 / 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^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// 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^256. Since the preconditions guarantee that the outcome is
// less than 2^256, 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;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @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;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @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;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return 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 {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
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 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;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
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 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));
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialOwner_","type":"address"},{"internalType":"address","name":"authorizer_","type":"address"},{"internalType":"contract IERC20Metadata","name":"currencyToken_","type":"address"},{"internalType":"uint256","name":"hardCap_","type":"uint256"},{"internalType":"uint32","name":"depositStartDate_","type":"uint32"},{"internalType":"uint32","name":"depositEndDate_","type":"uint32"},{"internalType":"uint256","name":"depositIncrement_","type":"uint256"},{"internalType":"uint256[]","name":"tiersLimit_","type":"uint256[]"},{"internalType":"uint16[]","name":"tiersFeesBasisPoint_","type":"uint16[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"AlreadyRefunded","type":"error"},{"inputs":[],"name":"AlreadyWithdrawnWinningAmountAndFees","type":"error"},{"inputs":[],"name":"ClaimClosed","type":"error"},{"inputs":[],"name":"ConfigAlreadySet","type":"error"},{"inputs":[],"name":"ConfigNotSet","type":"error"},{"inputs":[],"name":"DepositClosed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"HardCapReached","type":"error"},{"inputs":[],"name":"InvalidAmounts","type":"error"},{"inputs":[],"name":"InvalidDates","type":"error"},{"inputs":[],"name":"InvalidIncrement","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NothingToTransfer","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":"RefundClosed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TierLimitReached","type":"error"},{"inputs":[],"name":"TotalWinningAmountReached","type":"error"},{"inputs":[],"name":"WithdrawClosed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimedAmountInToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refundedAmountInCurrency","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"tierLevel","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"}],"name":"Deposit","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":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"winningAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loosingAmount","type":"uint256"}],"name":"Refund","type":"event"},{"inputs":[],"name":"alreadyWithdrawnWinningAmountAndFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorizer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"winningAmount_","type":"uint256"},{"internalType":"uint256","name":"loosingAmount_","type":"uint256"},{"internalType":"bytes","name":"signature_","type":"bytes"},{"internalType":"uint32","name":"signatureExpiration_","type":"uint32"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimEndDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimStartDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimVestingCliffBasisPoint","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimVestingEndDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256","name":"winningAmount_","type":"uint256"}],"name":"claimableAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"}],"name":"claimedAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currencyToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint8","name":"tierLevel_","type":"uint8"},{"internalType":"bytes","name":"signature_","type":"bytes"},{"internalType":"uint32","name":"signatureExpiration_","type":"uint32"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositEndDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositIncrement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositStartDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"}],"name":"depositedAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTiersFeesBasisPoint","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTiersLimit","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hardCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"winningAmount_","type":"uint256"},{"internalType":"uint256","name":"loosingAmount_","type":"uint256"},{"internalType":"bytes","name":"signature_","type":"bytes"},{"internalType":"uint32","name":"signatureExpiration_","type":"uint32"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refundEndDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refundStartDate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"}],"name":"refundedAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer_","type":"address"}],"name":"setAuthorizer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","name":"token_","type":"address"},{"internalType":"uint256","name":"tokenPriceNumerator_","type":"uint256"},{"internalType":"uint256","name":"tokenPriceDenominator_","type":"uint256"},{"internalType":"uint32","name":"claimStartDate_","type":"uint32"},{"internalType":"uint32","name":"claimEndDate_","type":"uint32"},{"internalType":"uint32","name":"claimVestingEndDate_","type":"uint32"},{"internalType":"uint16","name":"claimVestingCliffBasisPoint_","type":"uint16"},{"internalType":"uint256","name":"totalWinningAmount_","type":"uint256"}],"name":"setClaimConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"refundStartDate_","type":"uint32"},{"internalType":"uint32","name":"refundEndDate_","type":"uint32"}],"name":"setRefundConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPriceDenominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPriceNumerator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalClaimedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDepositedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefundedLoosingAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefundedWinningAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalWinningAmount","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":[{"internalType":"address","name":"to_","type":"address"}],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"}],"name":"withdrawExcessToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"}],"name":"withdrawWinningAmountWithFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101206040523480156200001257600080fd5b506040516200325838038062003258833981016040819052620000359162000559565b886001600160a01b0381166200006557604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000708162000266565b5060018055600280546001600160a01b0319166001600160a01b038a811691909117909155871660805260a086905263ffffffff85811660c052841660e0526101008390528151620000ca906003906020850190620002b6565b508051620000e090600490602084019062000306565b5060c05163ffffffff166000036200010b5760405163364dd21b60e21b815260040160405180910390fd5b60e05163ffffffff16600003620001355760405163364dd21b60e21b815260040160405180910390fd5b60e05163ffffffff1660c05163ffffffff1610620001665760405163364dd21b60e21b815260040160405180910390fd5b6002546001600160a01b03166200019057604051638baa579f60e01b815260040160405180910390fd5b61010051600003620001b557604051635899c0df60e11b815260040160405180910390fd5b6101005160a051620001c891906200063a565b15620001e757604051635899c0df60e11b815260040160405180910390fd5b6080516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801562000230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200025691906200065d565b5050505050505050505062000677565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054828255906000526020600020908101928215620002f4579160200282015b82811115620002f4578251825591602001919060010190620002d7565b5062000302929150620003ac565b5090565b82805482825590600052602060002090600f01601090048101928215620002f45791602002820160005b838211156200037257835183826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030262000330565b8015620003a25782816101000a81549061ffff021916905560020160208160010104928301926001030262000372565b5050620003029291505b5b80821115620003025760008155600101620003ad565b6001600160a01b0381168114620003d957600080fd5b50565b8051620003e981620003c3565b919050565b805163ffffffff81168114620003e957600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562000444576200044462000403565b604052919050565b60006001600160401b0382111562000468576200046862000403565b5060051b60200190565b600082601f8301126200048457600080fd5b815160206200049d62000497836200044c565b62000419565b82815260059290921b84018101918181019086841115620004bd57600080fd5b8286015b84811015620004da5780518352918301918301620004c1565b509695505050505050565b600082601f830112620004f757600080fd5b815160206200050a62000497836200044c565b82815260059290921b840181019181810190868411156200052a57600080fd5b8286015b84811015620004da57805161ffff811681146200054b5760008081fd5b83529183019183016200052e565b60008060008060008060008060006101208a8c0312156200057957600080fd5b89516200058681620003c3565b60208b01519099506200059981620003c3565b9750620005a960408b01620003dc565b965060608a01519550620005c060808b01620003ee565b9450620005d060a08b01620003ee565b60c08b015160e08c015191955093506001600160401b0380821115620005f557600080fd5b620006038d838e0162000472565b93506101008c01519150808211156200061b57600080fd5b506200062a8c828d01620004e5565b9150509295985092959850929598565b6000826200065857634e487b7160e01b600052601260045260246000fd5b500690565b6000602082840312156200067057600080fd5b5051919050565b60805160a05160c05160e05161010051612afb6200075d6000396000818161035d015281816109b601528181610cc801528181610d1001528181611b190152611b6101526000818161045c0152818161065c0152818161115e0152818161155d015281816119ce0152611d510152600081816105d7015261062d01526000818161057401528181610a0c0152610a3601526000818161038d01528181610835015281816108c30152818161090f01528181610f970152818161164f0152818161174701528181611c9b01528181611e4301528181611ed60152611fbb0152612afb6000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c80639661cb0d1161013b578063e9fdfd9f116100b8578063fa09e6301161007c578063fa09e6301461055c578063fb86a4041461056f578063fc0c546a14610596578063fc294b75146105a9578063ff6bca69146105d257600080fd5b8063e9fdfd9f146104f4578063f0d93c6614610504578063f2fde38b14610517578063f3437ff51461052a578063f8d60d431461053357600080fd5b8063ce6b3467116100ff578063ce6b346714610487578063d09edf311461049a578063d72637c8146104ad578063dfb34abb146104c4578063e6c01fbf146104e157600080fd5b80639661cb0d14610432578063a8602acb1461043b578063c7cc1a691461044e578063cac246ef14610457578063cd0038f11461047e57600080fd5b80635f03b6b2116101c9578063739455431161018d57806373945543146103cf5780637bb899a3146103e257806382f46db9146103f55780638da5cb5b1461040a578063947721dd1461041b57600080fd5b80635f03b6b21461034857806361c0d14814610358578063649b4b131461037f5780636b2fa37414610388578063715018a6146103c757600080fd5b806317009a5e1161021057806317009a5e146102e6578063172958941461030e5780632e51cf98146103175780633986e8501461032c5780635c3281261461033f57600080fd5b80630485978f1461024d578063058a628f14610289578063068eb22f1461029e578063114dae53146102ca57806313114a9d146102dd575b600080fd5b61027661025b366004612509565b6001600160a01b031660009081526011602052604090205490565b6040519081526020015b60405180910390f35b61029c610297366004612509565b6105f9565b005b6008546102b590600160201b900463ffffffff1681565b60405163ffffffff9091168152602001610280565b61029c6102d83660046125f1565b610623565b610276600f5481565b6008546102fb90600160601b900461ffff1681565b60405161ffff9091168152602001610280565b610276600b5481565b61031f610b42565b604051610280919061265b565b61029c61033a3660046126a3565b610bc2565b61027660095481565b6008546102b59063ffffffff1681565b6102767f000000000000000000000000000000000000000000000000000000000000000081565b61027660065481565b6103af7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610280565b61029c611005565b61029c6103dd3660046126de565b611019565b6102766103f036600461276d565b611393565b6103fd6114c6565b6040516102809190612799565b6000546001600160a01b03166103af565b600a546102b590600160201b900463ffffffff1681565b610276600c5481565b61029c610449366004612509565b61151d565b610276600e5481565b6102b57f000000000000000000000000000000000000000000000000000000000000000081565b610276600d5481565b61029c610495366004612509565b61167b565b6002546103af906001600160a01b031681565b6008546102b590600160401b900463ffffffff1681565b6013546104d19060ff1681565b6040519015158152602001610280565b61029c6104ef3660046127d1565b6118e5565b600a546102b59063ffffffff1681565b61029c6105123660046126a3565b611a12565b61029c610525366004612509565b611d04565b61027660075481565b610276610541366004612509565b6001600160a01b031660009081526010602052604090205490565b61029c61056a366004612509565b611d47565b6102767f000000000000000000000000000000000000000000000000000000000000000081565b6005546103af906001600160a01b031681565b6102766105b7366004612509565b6001600160a01b031660009081526012602052604090205490565b6102b57f000000000000000000000000000000000000000000000000000000000000000081565b610601611fff565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61062b61202c565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff1642108061068457507f000000000000000000000000000000000000000000000000000000000000000063ffffffff1642115b156106a25760405163e00c8ecd60e01b815260040160405180910390fd5b8063ffffffff164211156106c957604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b8216938301939093526619195c1bdcda5d60ca1b60548301523390921b909116605b8201526001600160f81b031960f886901b16606f820152607081018690526001600160e01b031960e084901b16609082015261079e916001600160a01b031690610798906094015b604051602081830303815290604052805190602001207f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b84612056565b6107bb57604051638baa579f60e01b815260040160405180910390fd5b600061271060048560ff16815481106107d6576107d6612804565b6000918252602090912060108204015461080091600f166002026101000a900461ffff1687612830565b61080a919061285d565b905080600f5461081a9190612871565b600f556040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a89190612884565b90506108eb33306108b9858a612871565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169291906120ba565b6040516370a0823160e01b8152306004820152600090839083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610956573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097a9190612884565b610984919061289d565b61098e919061289d565b9050806000036109b157604051633a267e8960e11b815260040160405180910390fd5b6109db7f0000000000000000000000000000000000000000000000000000000000000000826128b0565b156109f957604051635899c0df60e11b815260040160405180910390fd5b80600b54610a079190612871565b600b557f000000000000000000000000000000000000000000000000000000000000000015801590610a5a57507f0000000000000000000000000000000000000000000000000000000000000000600b54115b15610a7857604051634bc461a160e11b815260040160405180910390fd5b33600090815260106020526040812054610a93908390612871565b905060038760ff1681548110610aab57610aab612804565b9060005260206000200154811115610ad6576040516330e57efd60e21b815260040160405180910390fd5b33600081815260106020908152604091829020849055815185815260ff8b16918101919091529081018690527f999cbaf5148925f92ba8d941276e0a13cadad3823058b47817fb1a10875310579060600160405180910390a250505050610b3c60018055565b50505050565b60606004805480602002602001604051908101604052809291908181526020018280548015610bb857602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b7f5790505b5050505050905090565b60085463ffffffff16421080610be65750600854600160201b900463ffffffff1642115b15610c045760405163f6e8504160e01b815260040160405180910390fd5b8063ffffffff16421115610c2b57604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b82169383019390935264636c61696d60d81b60548301523390921b9091166059820152606d8101869052608d81018590526001600160e01b031960e084901b1660ad820152610ca6916001600160a01b0316906107989060b10161074f565b610cc357604051638baa579f60e01b815260040160405180910390fd5b610ced7f0000000000000000000000000000000000000000000000000000000000000000856128b0565b15610d0b57604051635899c0df60e11b815260040160405180910390fd5b610d357f0000000000000000000000000000000000000000000000000000000000000000846128b0565b15610d5357604051635899c0df60e11b815260040160405180910390fd5b336000908152601060209081526040808320546011835281842054601290935292205485811115610d975760405163542f378d60e11b815260040160405180910390fd5b82600003610db857604051633a267e8960e11b815260040160405180910390fd5b82610dc38789612871565b1115610de257604051636c2b7e2d60e11b815260040160405180910390fd5b6000610dee3389611393565b90508015610e4557610e008184612871565b33600090815260116020526040902055600c54610e1e908290612871565b600c8190556009541015610e455760405163325b168760e21b815260040160405180910390fd5b6000610e51838961289d565b90508015610e8557610e638184612871565b33600090815260126020526040902055600e54610e81908290612871565b600e555b81158015610e91575080155b15610eaf57604051633a267e8960e11b815260040160405180910390fd5b6000808311610ebf576000610f65565b600654600754600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3c91906128c4565b610f4790600a6129c5565b610f519086612830565b610f5b9190612830565b610f65919061285d565b90508015610f8457600554610f84906001600160a01b03163383612121565b8115610fbe57610fbe6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163384612121565b604080518281526020810184905233917f34fcbac0073d7c3d388e51312faf357774904998eeb8fca628b9e6f65ee1cbf7910160405180910390a250505050505050505050565b61100d611fff565b6110176000612152565b565b611021611fff565b6005546001600160a01b03161561104b5760405163c7c5196560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b038a16179055600687905560078690556008805463ffffffff87811667ffffffffffffffff1990921691909117600160201b87831602176dffffffffffff00000000000000001916600160401b8683160261ffff60601b191617600160601b61ffff86160217918290556009839055166000036110f05760405163364dd21b60e21b815260040160405180910390fd5b600854600160201b900463ffffffff166000036111205760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff600160201b820481169116106111515760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff9081167f00000000000000000000000000000000000000000000000000000000000000009091161061119e5760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff808216600160401b9092041610156111d15760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff600160201b82048116600160401b90920416111561120a5760405163364dd21b60e21b815260040160405180910390fd5b60065460000361122d57604051636c2b7e2d60e11b815260040160405180910390fd5b60075460000361125057604051636c2b7e2d60e11b815260040160405180910390fd5b60095460000361127357604051636c2b7e2d60e11b815260040160405180910390fd5b600854612710600160601b90910461ffff1611156112a457604051636c2b7e2d60e11b815260040160405180910390fd5b600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131b91906128c4565b506005546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611364573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113889190612884565b505050505050505050565b60085460009063ffffffff164210156113ae575060006114c0565b600854600160401b900463ffffffff1642106113ee576001600160a01b0383166000908152601160205260409020546113e7908361289d565b90506114c0565b6001600160a01b0383166000908152601160205260409020546008546114249063ffffffff80821691600160401b9004166129d4565b60085463ffffffff9182169161143b91164261289d565b6008546127109061145790600160601b900461ffff16826129f8565b6114659061ffff1687612830565b61146f919061285d565b6114799190612830565b611483919061285d565b6008546127109061149f90600160601b900461ffff1686612830565b6114a9919061285d565b6114b39190612871565b6114bd919061289d565b90505b92915050565b60606003805480602002602001604051908101604052809291908181526020018280548015610bb857602002820191906000526020600020905b815481526020019060010190808311611500575050505050905090565b611525611fff565b60135460ff16156115495760405163805ddd3960e01b815260040160405180910390fd5b6013805460ff1916600117905563ffffffff7f000000000000000000000000000000000000000000000000000000000000000016421161159c576040516311a75df160e11b815260040160405180910390fd5b600a54600160201b900463ffffffff16158015906115c95750600a54600160201b900463ffffffff164211155b156115e7576040516311a75df160e11b815260040160405180910390fd5b6000600954600b54106115fc57600954611600565b600b545b90506000600d54600f54836116159190612871565b61161f919061289d565b90508060000361164257604051633a267e8960e11b815260040160405180910390fd5b6116766001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168483612121565b505050565b611683611fff565b6005546001600160a01b03166116ac57604051632b38492f60e21b815260040160405180910390fd5b6000600954600b54106116c1576009546116c5565b600b545b6005546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117379190612884565b6005549091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116036117d4576000600e5483600b54611782919061289d565b61178c919061289d565b60135490915060ff166117c6576000600d54600f54856117ac9190612871565b6117b6919061289d565b90506117c28183612871565b9150505b6117d0818361289d565b9150505b6000600d54600c54846117e7919061289d565b6117f1919061289d565b90506000600654600754600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561184e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187291906128c4565b61187d90600a6129c5565b6118879085612830565b6118919190612830565b61189b919061285d565b90508083116118bd57604051633a267e8960e11b815260040160405180910390fd5b6118de856118cb838661289d565b6005546001600160a01b03169190612121565b5050505050565b6118ed611fff565b600a5463ffffffff16156119145760405163c7c5196560e01b815260040160405180910390fd5b600a805463ffffffff838116600160201b0267ffffffffffffffff19909216818616179190911791829055166000036119605760405163364dd21b60e21b815260040160405180910390fd5b600a54600160201b900463ffffffff166000036119905760405163364dd21b60e21b815260040160405180910390fd5b600a5463ffffffff600160201b820481169116106119c15760405163364dd21b60e21b815260040160405180910390fd5b600a5463ffffffff9081167f000000000000000000000000000000000000000000000000000000000000000090911610611a0e5760405163364dd21b60e21b815260040160405180910390fd5b5050565b600a5463ffffffff16421080611a365750600a54600160201b900463ffffffff1642115b15611a5457604051630262240360e31b815260040160405180910390fd5b8063ffffffff16421115611a7b57604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b821693830193909352651c99599d5b9960d21b60548301523390921b909116605a820152606e8101869052608e81018590526001600160e01b031960e084901b1660ae820152611af7916001600160a01b0316906107989060b20161074f565b611b1457604051638baa579f60e01b815260040160405180910390fd5b611b3e7f0000000000000000000000000000000000000000000000000000000000000000856128b0565b15611b5c57604051635899c0df60e11b815260040160405180910390fd5b611b867f0000000000000000000000000000000000000000000000000000000000000000846128b0565b15611ba457604051635899c0df60e11b815260040160405180910390fd5b3360009081526011602052604090205415611bd257604051630c8d9eab60e31b815260040160405180910390fd5b3360009081526012602052604090205415611c005760405163542f378d60e11b815260040160405180910390fd5b3360009081526010602052604081205490819003611c3157604051633a267e8960e11b815260040160405180910390fd5b80611c3c8587612871565b14611c5a57604051636c2b7e2d60e11b815260040160405180910390fd5b336000908152601260205260409020819055600d54611c7a908690612871565b600d55600e54611c8b908590612871565b600e55611cc26001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163383612121565b604080518681526020810186905233917f73f04af9dcc582a923ec15d3eea990fe34adabfff2879e28d44572e01a54abb6910160405180910390a25050505050565b611d0c611fff565b6001600160a01b038116611d3b57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b611d4481612152565b50565b611d4f611fff565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff164211611d95576040516311a75df160e11b815260040160405180910390fd5b600854600160201b900463ffffffff1615801590611dc25750600854600160201b900463ffffffff164211155b15611de0576040516311a75df160e11b815260040160405180910390fd5b600a54600160201b900463ffffffff1615801590611e0d5750600a54600160201b900463ffffffff164211155b15611e2b576040516311a75df160e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb69190612884565b6005549091506000906001600160a01b031615801590611f0557506005547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116911614155b611f10576000611f7c565b6005546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611f58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7c9190612884565b905081158015611f8a575080155b15611fa857604051633a267e8960e11b815260040160405180910390fd5b8115611fe257611fe26001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168484612121565b801561167657600554611676906001600160a01b03168483612121565b6000546001600160a01b031633146110175760405163118cdaa760e01b8152336004820152602401611d32565b60026001540361204f57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600080600061206585856121a2565b509092509050600081600381111561207f5761207f612a13565b14801561209d5750856001600160a01b0316826001600160a01b0316145b806120ae57506120ae8686866121ef565b925050505b9392505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610b3c9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506122ca565b6040516001600160a01b0383811660248301526044820183905261167691859182169063a9059cbb906064016120ef565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600083516041036121dc5760208401516040850151606086015160001a6121ce8882858561232d565b9550955095505050506121e8565b50508151600091506002905b9250925092565b6000806000856001600160a01b03168585604051602401612211929190612a4d565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516122469190612a87565b600060405180830381855afa9150503d8060008114612281576040519150601f19603f3d011682016040523d82523d6000602084013e612286565b606091505b509150915081801561229a57506020815110155b80156120ae57508051630b135d3f60e11b906122bf9083016020908101908401612884565b149695505050505050565b60006122df6001600160a01b038416836123fc565b905080516000141580156123045750808060200190518101906123029190612aa3565b155b1561167657604051635274afe760e01b81526001600160a01b0384166004820152602401611d32565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561236857506000915060039050826123f2565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156123bc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166123e8575060009250600191508290506123f2565b9250600091508190505b9450945094915050565b60606114bd8383600084600080856001600160a01b031684866040516124229190612a87565b60006040518083038185875af1925050503d806000811461245f576040519150601f19603f3d011682016040523d82523d6000602084013e612464565b606091505b50915091506120ae8683836060826124845761247f826124cb565b6120b3565b815115801561249b57506001600160a01b0384163b155b156124c457604051639996b31560e01b81526001600160a01b0385166004820152602401611d32565b50806120b3565b8051156124db5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114611d4457600080fd5b60006020828403121561251b57600080fd5b81356120b3816124f4565b60ff81168114611d4457600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261255c57600080fd5b813567ffffffffffffffff8082111561257757612577612535565b604051601f8301601f19908116603f0116810190828211818310171561259f5761259f612535565b816040528381528660208588010111156125b857600080fd5b836020870160208301376000602085830101528094505050505092915050565b803563ffffffff811681146125ec57600080fd5b919050565b6000806000806080858703121561260757600080fd5b84359350602085013561261981612526565b9250604085013567ffffffffffffffff81111561263557600080fd5b6126418782880161254b565b925050612650606086016125d8565b905092959194509250565b6020808252825182820181905260009190848201906040850190845b8181101561269757835161ffff1683529284019291840191600101612677565b50909695505050505050565b600080600080608085870312156126b957600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561263557600080fd5b600080600080600080600080610100898b0312156126fb57600080fd5b8835612706816124f4565b9750602089013596506040890135955061272260608a016125d8565b945061273060808a016125d8565b935061273e60a08a016125d8565b925060c089013561ffff8116811461275557600080fd5b8092505060e089013590509295985092959890939650565b6000806040838503121561278057600080fd5b823561278b816124f4565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b81811015612697578351835292840192918401916001016127b5565b600080604083850312156127e457600080fd5b6127ed836125d8565b91506127fb602084016125d8565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176114c0576114c061281a565b634e487b7160e01b600052601260045260246000fd5b60008261286c5761286c612847565b500490565b808201808211156114c0576114c061281a565b60006020828403121561289657600080fd5b5051919050565b818103818111156114c0576114c061281a565b6000826128bf576128bf612847565b500690565b6000602082840312156128d657600080fd5b81516120b381612526565b600181815b8085111561291c5781600019048211156129025761290261281a565b8085161561290f57918102915b93841c93908002906128e6565b509250929050565b600082612933575060016114c0565b81612940575060006114c0565b816001811461295657600281146129605761297c565b60019150506114c0565b60ff8411156129715761297161281a565b50506001821b6114c0565b5060208310610133831016604e8410600b841016171561299f575081810a6114c0565b6129a983836128e1565b80600019048211156129bd576129bd61281a565b029392505050565b60006114bd60ff841683612924565b63ffffffff8281168282160390808211156129f1576129f161281a565b5092915050565b61ffff8281168282160390808211156129f1576129f161281a565b634e487b7160e01b600052602160045260246000fd5b60005b83811015612a44578181015183820152602001612a2c565b50506000910152565b8281526040602082015260008251806040840152612a72816060850160208701612a29565b601f01601f1916919091016060019392505050565b60008251612a99818460208701612a29565b9190910192915050565b600060208284031215612ab557600080fd5b815180151581146120b357600080fdfea264697066735822122062539ec853e07dded8a46c82c40c3e9d12bf7ac9a723382ad5f6ccec773ff38764736f6c63430008140033000000000000000000000000462a647318d8dc1f0b5217b14cdcc90957305a1d000000000000000000000000ccdbbb6273684dd9421bb992222282f6def8ca9c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000004a817c80000000000000000000000000000000000000000000000000000000000669508380000000000000000000000000000000000000000000000000000000066958dd0000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000000000000017d784000000000000000000000000000000000000000000000000000000000023c34600000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102485760003560e01c80639661cb0d1161013b578063e9fdfd9f116100b8578063fa09e6301161007c578063fa09e6301461055c578063fb86a4041461056f578063fc0c546a14610596578063fc294b75146105a9578063ff6bca69146105d257600080fd5b8063e9fdfd9f146104f4578063f0d93c6614610504578063f2fde38b14610517578063f3437ff51461052a578063f8d60d431461053357600080fd5b8063ce6b3467116100ff578063ce6b346714610487578063d09edf311461049a578063d72637c8146104ad578063dfb34abb146104c4578063e6c01fbf146104e157600080fd5b80639661cb0d14610432578063a8602acb1461043b578063c7cc1a691461044e578063cac246ef14610457578063cd0038f11461047e57600080fd5b80635f03b6b2116101c9578063739455431161018d57806373945543146103cf5780637bb899a3146103e257806382f46db9146103f55780638da5cb5b1461040a578063947721dd1461041b57600080fd5b80635f03b6b21461034857806361c0d14814610358578063649b4b131461037f5780636b2fa37414610388578063715018a6146103c757600080fd5b806317009a5e1161021057806317009a5e146102e6578063172958941461030e5780632e51cf98146103175780633986e8501461032c5780635c3281261461033f57600080fd5b80630485978f1461024d578063058a628f14610289578063068eb22f1461029e578063114dae53146102ca57806313114a9d146102dd575b600080fd5b61027661025b366004612509565b6001600160a01b031660009081526011602052604090205490565b6040519081526020015b60405180910390f35b61029c610297366004612509565b6105f9565b005b6008546102b590600160201b900463ffffffff1681565b60405163ffffffff9091168152602001610280565b61029c6102d83660046125f1565b610623565b610276600f5481565b6008546102fb90600160601b900461ffff1681565b60405161ffff9091168152602001610280565b610276600b5481565b61031f610b42565b604051610280919061265b565b61029c61033a3660046126a3565b610bc2565b61027660095481565b6008546102b59063ffffffff1681565b6102767f000000000000000000000000000000000000000000000000000000000bebc20081565b61027660065481565b6103af7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781565b6040516001600160a01b039091168152602001610280565b61029c611005565b61029c6103dd3660046126de565b611019565b6102766103f036600461276d565b611393565b6103fd6114c6565b6040516102809190612799565b6000546001600160a01b03166103af565b600a546102b590600160201b900463ffffffff1681565b610276600c5481565b61029c610449366004612509565b61151d565b610276600e5481565b6102b57f0000000000000000000000000000000000000000000000000000000066958dd081565b610276600d5481565b61029c610495366004612509565b61167b565b6002546103af906001600160a01b031681565b6008546102b590600160401b900463ffffffff1681565b6013546104d19060ff1681565b6040519015158152602001610280565b61029c6104ef3660046127d1565b6118e5565b600a546102b59063ffffffff1681565b61029c6105123660046126a3565b611a12565b61029c610525366004612509565b611d04565b61027660075481565b610276610541366004612509565b6001600160a01b031660009081526010602052604090205490565b61029c61056a366004612509565b611d47565b6102767f00000000000000000000000000000000000000000000000000000004a817c80081565b6005546103af906001600160a01b031681565b6102766105b7366004612509565b6001600160a01b031660009081526012602052604090205490565b6102b57f000000000000000000000000000000000000000000000000000000006695083881565b610601611fff565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61062b61202c565b7f000000000000000000000000000000000000000000000000000000006695083863ffffffff1642108061068457507f0000000000000000000000000000000000000000000000000000000066958dd063ffffffff1642115b156106a25760405163e00c8ecd60e01b815260040160405180910390fd5b8063ffffffff164211156106c957604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b8216938301939093526619195c1bdcda5d60ca1b60548301523390921b909116605b8201526001600160f81b031960f886901b16606f820152607081018690526001600160e01b031960e084901b16609082015261079e916001600160a01b031690610798906094015b604051602081830303815290604052805190602001207f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b84612056565b6107bb57604051638baa579f60e01b815260040160405180910390fd5b600061271060048560ff16815481106107d6576107d6612804565b6000918252602090912060108204015461080091600f166002026101000a900461ffff1687612830565b61080a919061285d565b905080600f5461081a9190612871565b600f556040516370a0823160e01b81523060048201526000907f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa158015610884573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a89190612884565b90506108eb33306108b9858a612871565b6001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7169291906120ba565b6040516370a0823160e01b8152306004820152600090839083906001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec716906370a0823190602401602060405180830381865afa158015610956573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097a9190612884565b610984919061289d565b61098e919061289d565b9050806000036109b157604051633a267e8960e11b815260040160405180910390fd5b6109db7f000000000000000000000000000000000000000000000000000000000bebc200826128b0565b156109f957604051635899c0df60e11b815260040160405180910390fd5b80600b54610a079190612871565b600b557f00000000000000000000000000000000000000000000000000000004a817c80015801590610a5a57507f00000000000000000000000000000000000000000000000000000004a817c800600b54115b15610a7857604051634bc461a160e11b815260040160405180910390fd5b33600090815260106020526040812054610a93908390612871565b905060038760ff1681548110610aab57610aab612804565b9060005260206000200154811115610ad6576040516330e57efd60e21b815260040160405180910390fd5b33600081815260106020908152604091829020849055815185815260ff8b16918101919091529081018690527f999cbaf5148925f92ba8d941276e0a13cadad3823058b47817fb1a10875310579060600160405180910390a250505050610b3c60018055565b50505050565b60606004805480602002602001604051908101604052809291908181526020018280548015610bb857602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610b7f5790505b5050505050905090565b60085463ffffffff16421080610be65750600854600160201b900463ffffffff1642115b15610c045760405163f6e8504160e01b815260040160405180910390fd5b8063ffffffff16421115610c2b57604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b82169383019390935264636c61696d60d81b60548301523390921b9091166059820152606d8101869052608d81018590526001600160e01b031960e084901b1660ad820152610ca6916001600160a01b0316906107989060b10161074f565b610cc357604051638baa579f60e01b815260040160405180910390fd5b610ced7f000000000000000000000000000000000000000000000000000000000bebc200856128b0565b15610d0b57604051635899c0df60e11b815260040160405180910390fd5b610d357f000000000000000000000000000000000000000000000000000000000bebc200846128b0565b15610d5357604051635899c0df60e11b815260040160405180910390fd5b336000908152601060209081526040808320546011835281842054601290935292205485811115610d975760405163542f378d60e11b815260040160405180910390fd5b82600003610db857604051633a267e8960e11b815260040160405180910390fd5b82610dc38789612871565b1115610de257604051636c2b7e2d60e11b815260040160405180910390fd5b6000610dee3389611393565b90508015610e4557610e008184612871565b33600090815260116020526040902055600c54610e1e908290612871565b600c8190556009541015610e455760405163325b168760e21b815260040160405180910390fd5b6000610e51838961289d565b90508015610e8557610e638184612871565b33600090815260126020526040902055600e54610e81908290612871565b600e555b81158015610e91575080155b15610eaf57604051633a267e8960e11b815260040160405180910390fd5b6000808311610ebf576000610f65565b600654600754600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3c91906128c4565b610f4790600a6129c5565b610f519086612830565b610f5b9190612830565b610f65919061285d565b90508015610f8457600554610f84906001600160a01b03163383612121565b8115610fbe57610fbe6001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7163384612121565b604080518281526020810184905233917f34fcbac0073d7c3d388e51312faf357774904998eeb8fca628b9e6f65ee1cbf7910160405180910390a250505050505050505050565b61100d611fff565b6110176000612152565b565b611021611fff565b6005546001600160a01b03161561104b5760405163c7c5196560e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b038a16179055600687905560078690556008805463ffffffff87811667ffffffffffffffff1990921691909117600160201b87831602176dffffffffffff00000000000000001916600160401b8683160261ffff60601b191617600160601b61ffff86160217918290556009839055166000036110f05760405163364dd21b60e21b815260040160405180910390fd5b600854600160201b900463ffffffff166000036111205760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff600160201b820481169116106111515760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff9081167f0000000000000000000000000000000000000000000000000000000066958dd09091161061119e5760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff808216600160401b9092041610156111d15760405163364dd21b60e21b815260040160405180910390fd5b60085463ffffffff600160201b82048116600160401b90920416111561120a5760405163364dd21b60e21b815260040160405180910390fd5b60065460000361122d57604051636c2b7e2d60e11b815260040160405180910390fd5b60075460000361125057604051636c2b7e2d60e11b815260040160405180910390fd5b60095460000361127357604051636c2b7e2d60e11b815260040160405180910390fd5b600854612710600160601b90910461ffff1611156112a457604051636c2b7e2d60e11b815260040160405180910390fd5b600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061131b91906128c4565b506005546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611364573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113889190612884565b505050505050505050565b60085460009063ffffffff164210156113ae575060006114c0565b600854600160401b900463ffffffff1642106113ee576001600160a01b0383166000908152601160205260409020546113e7908361289d565b90506114c0565b6001600160a01b0383166000908152601160205260409020546008546114249063ffffffff80821691600160401b9004166129d4565b60085463ffffffff9182169161143b91164261289d565b6008546127109061145790600160601b900461ffff16826129f8565b6114659061ffff1687612830565b61146f919061285d565b6114799190612830565b611483919061285d565b6008546127109061149f90600160601b900461ffff1686612830565b6114a9919061285d565b6114b39190612871565b6114bd919061289d565b90505b92915050565b60606003805480602002602001604051908101604052809291908181526020018280548015610bb857602002820191906000526020600020905b815481526020019060010190808311611500575050505050905090565b611525611fff565b60135460ff16156115495760405163805ddd3960e01b815260040160405180910390fd5b6013805460ff1916600117905563ffffffff7f0000000000000000000000000000000000000000000000000000000066958dd016421161159c576040516311a75df160e11b815260040160405180910390fd5b600a54600160201b900463ffffffff16158015906115c95750600a54600160201b900463ffffffff164211155b156115e7576040516311a75df160e11b815260040160405180910390fd5b6000600954600b54106115fc57600954611600565b600b545b90506000600d54600f54836116159190612871565b61161f919061289d565b90508060000361164257604051633a267e8960e11b815260040160405180910390fd5b6116766001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168483612121565b505050565b611683611fff565b6005546001600160a01b03166116ac57604051632b38492f60e21b815260040160405180910390fd5b6000600954600b54106116c1576009546116c5565b600b545b6005546040516370a0823160e01b81523060048201529192506000916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117379190612884565b6005549091506001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781169116036117d4576000600e5483600b54611782919061289d565b61178c919061289d565b60135490915060ff166117c6576000600d54600f54856117ac9190612871565b6117b6919061289d565b90506117c28183612871565b9150505b6117d0818361289d565b9150505b6000600d54600c54846117e7919061289d565b6117f1919061289d565b90506000600654600754600560009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561184e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187291906128c4565b61187d90600a6129c5565b6118879085612830565b6118919190612830565b61189b919061285d565b90508083116118bd57604051633a267e8960e11b815260040160405180910390fd5b6118de856118cb838661289d565b6005546001600160a01b03169190612121565b5050505050565b6118ed611fff565b600a5463ffffffff16156119145760405163c7c5196560e01b815260040160405180910390fd5b600a805463ffffffff838116600160201b0267ffffffffffffffff19909216818616179190911791829055166000036119605760405163364dd21b60e21b815260040160405180910390fd5b600a54600160201b900463ffffffff166000036119905760405163364dd21b60e21b815260040160405180910390fd5b600a5463ffffffff600160201b820481169116106119c15760405163364dd21b60e21b815260040160405180910390fd5b600a5463ffffffff9081167f0000000000000000000000000000000000000000000000000000000066958dd090911610611a0e5760405163364dd21b60e21b815260040160405180910390fd5b5050565b600a5463ffffffff16421080611a365750600a54600160201b900463ffffffff1642115b15611a5457604051630262240360e31b815260040160405180910390fd5b8063ffffffff16421115611a7b57604051638baa579f60e01b815260040160405180910390fd5b600254604080514660208201526001600160601b031930606090811b821693830193909352651c99599d5b9960d21b60548301523390921b909116605a820152606e8101869052608e81018590526001600160e01b031960e084901b1660ae820152611af7916001600160a01b0316906107989060b20161074f565b611b1457604051638baa579f60e01b815260040160405180910390fd5b611b3e7f000000000000000000000000000000000000000000000000000000000bebc200856128b0565b15611b5c57604051635899c0df60e11b815260040160405180910390fd5b611b867f000000000000000000000000000000000000000000000000000000000bebc200846128b0565b15611ba457604051635899c0df60e11b815260040160405180910390fd5b3360009081526011602052604090205415611bd257604051630c8d9eab60e31b815260040160405180910390fd5b3360009081526012602052604090205415611c005760405163542f378d60e11b815260040160405180910390fd5b3360009081526010602052604081205490819003611c3157604051633a267e8960e11b815260040160405180910390fd5b80611c3c8587612871565b14611c5a57604051636c2b7e2d60e11b815260040160405180910390fd5b336000908152601260205260409020819055600d54611c7a908690612871565b600d55600e54611c8b908590612871565b600e55611cc26001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7163383612121565b604080518681526020810186905233917f73f04af9dcc582a923ec15d3eea990fe34adabfff2879e28d44572e01a54abb6910160405180910390a25050505050565b611d0c611fff565b6001600160a01b038116611d3b57604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b611d4481612152565b50565b611d4f611fff565b7f0000000000000000000000000000000000000000000000000000000066958dd063ffffffff164211611d95576040516311a75df160e11b815260040160405180910390fd5b600854600160201b900463ffffffff1615801590611dc25750600854600160201b900463ffffffff164211155b15611de0576040516311a75df160e11b815260040160405180910390fd5b600a54600160201b900463ffffffff1615801590611e0d5750600a54600160201b900463ffffffff164211155b15611e2b576040516311a75df160e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316906370a0823190602401602060405180830381865afa158015611e92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eb69190612884565b6005549091506000906001600160a01b031615801590611f0557506005547f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03908116911614155b611f10576000611f7c565b6005546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611f58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7c9190612884565b905081158015611f8a575080155b15611fa857604051633a267e8960e11b815260040160405180910390fd5b8115611fe257611fe26001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7168484612121565b801561167657600554611676906001600160a01b03168483612121565b6000546001600160a01b031633146110175760405163118cdaa760e01b8152336004820152602401611d32565b60026001540361204f57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b600080600061206585856121a2565b509092509050600081600381111561207f5761207f612a13565b14801561209d5750856001600160a01b0316826001600160a01b0316145b806120ae57506120ae8686866121ef565b925050505b9392505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610b3c9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506122ca565b6040516001600160a01b0383811660248301526044820183905261167691859182169063a9059cbb906064016120ef565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080600083516041036121dc5760208401516040850151606086015160001a6121ce8882858561232d565b9550955095505050506121e8565b50508151600091506002905b9250925092565b6000806000856001600160a01b03168585604051602401612211929190612a4d565b60408051601f198184030181529181526020820180516001600160e01b0316630b135d3f60e11b179052516122469190612a87565b600060405180830381855afa9150503d8060008114612281576040519150601f19603f3d011682016040523d82523d6000602084013e612286565b606091505b509150915081801561229a57506020815110155b80156120ae57508051630b135d3f60e11b906122bf9083016020908101908401612884565b149695505050505050565b60006122df6001600160a01b038416836123fc565b905080516000141580156123045750808060200190518101906123029190612aa3565b155b1561167657604051635274afe760e01b81526001600160a01b0384166004820152602401611d32565b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561236857506000915060039050826123f2565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156123bc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166123e8575060009250600191508290506123f2565b9250600091508190505b9450945094915050565b60606114bd8383600084600080856001600160a01b031684866040516124229190612a87565b60006040518083038185875af1925050503d806000811461245f576040519150601f19603f3d011682016040523d82523d6000602084013e612464565b606091505b50915091506120ae8683836060826124845761247f826124cb565b6120b3565b815115801561249b57506001600160a01b0384163b155b156124c457604051639996b31560e01b81526001600160a01b0385166004820152602401611d32565b50806120b3565b8051156124db5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0381168114611d4457600080fd5b60006020828403121561251b57600080fd5b81356120b3816124f4565b60ff81168114611d4457600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261255c57600080fd5b813567ffffffffffffffff8082111561257757612577612535565b604051601f8301601f19908116603f0116810190828211818310171561259f5761259f612535565b816040528381528660208588010111156125b857600080fd5b836020870160208301376000602085830101528094505050505092915050565b803563ffffffff811681146125ec57600080fd5b919050565b6000806000806080858703121561260757600080fd5b84359350602085013561261981612526565b9250604085013567ffffffffffffffff81111561263557600080fd5b6126418782880161254b565b925050612650606086016125d8565b905092959194509250565b6020808252825182820181905260009190848201906040850190845b8181101561269757835161ffff1683529284019291840191600101612677565b50909695505050505050565b600080600080608085870312156126b957600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561263557600080fd5b600080600080600080600080610100898b0312156126fb57600080fd5b8835612706816124f4565b9750602089013596506040890135955061272260608a016125d8565b945061273060808a016125d8565b935061273e60a08a016125d8565b925060c089013561ffff8116811461275557600080fd5b8092505060e089013590509295985092959890939650565b6000806040838503121561278057600080fd5b823561278b816124f4565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b81811015612697578351835292840192918401916001016127b5565b600080604083850312156127e457600080fd5b6127ed836125d8565b91506127fb602084016125d8565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176114c0576114c061281a565b634e487b7160e01b600052601260045260246000fd5b60008261286c5761286c612847565b500490565b808201808211156114c0576114c061281a565b60006020828403121561289657600080fd5b5051919050565b818103818111156114c0576114c061281a565b6000826128bf576128bf612847565b500690565b6000602082840312156128d657600080fd5b81516120b381612526565b600181815b8085111561291c5781600019048211156129025761290261281a565b8085161561290f57918102915b93841c93908002906128e6565b509250929050565b600082612933575060016114c0565b81612940575060006114c0565b816001811461295657600281146129605761297c565b60019150506114c0565b60ff8411156129715761297161281a565b50506001821b6114c0565b5060208310610133831016604e8410600b841016171561299f575081810a6114c0565b6129a983836128e1565b80600019048211156129bd576129bd61281a565b029392505050565b60006114bd60ff841683612924565b63ffffffff8281168282160390808211156129f1576129f161281a565b5092915050565b61ffff8281168282160390808211156129f1576129f161281a565b634e487b7160e01b600052602160045260246000fd5b60005b83811015612a44578181015183820152602001612a2c565b50506000910152565b8281526040602082015260008251806040840152612a72816060850160208701612a29565b601f01601f1916919091016060019392505050565b60008251612a99818460208701612a29565b9190910192915050565b600060208284031215612ab557600080fd5b815180151581146120b357600080fdfea264697066735822122062539ec853e07dded8a46c82c40c3e9d12bf7ac9a723382ad5f6ccec773ff38764736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000462a647318d8dc1f0b5217b14cdcc90957305a1d000000000000000000000000ccdbbb6273684dd9421bb992222282f6def8ca9c000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000000000000000000000000000000000004a817c80000000000000000000000000000000000000000000000000000000000669508380000000000000000000000000000000000000000000000000000000066958dd0000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc2000000000000000000000000000000000000000000000000000000000017d784000000000000000000000000000000000000000000000000000000000023c34600000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : initialOwner_ (address): 0x462A647318d8Dc1f0B5217B14CDcc90957305a1D
Arg [1] : authorizer_ (address): 0xccdbbb6273684DD9421Bb992222282F6Def8ca9C
Arg [2] : currencyToken_ (address): 0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [3] : hardCap_ (uint256): 20000000000
Arg [4] : depositStartDate_ (uint32): 1721043000
Arg [5] : depositEndDate_ (uint32): 1721077200
Arg [6] : depositIncrement_ (uint256): 200000000
Arg [7] : tiersLimit_ (uint256[]): 200000000,200000000,400000000,600000000,800000000,1000000000,1000000000
Arg [8] : tiersFeesBasisPoint_ (uint16[]): 1000,0,0,0,0,0,0
-----Encoded View---------------
25 Constructor Arguments found :
Arg [0] : 000000000000000000000000462a647318d8dc1f0b5217b14cdcc90957305a1d
Arg [1] : 000000000000000000000000ccdbbb6273684dd9421bb992222282f6def8ca9c
Arg [2] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [3] : 00000000000000000000000000000000000000000000000000000004a817c800
Arg [4] : 0000000000000000000000000000000000000000000000000000000066950838
Arg [5] : 0000000000000000000000000000000000000000000000000000000066958dd0
Arg [6] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [10] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [11] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [12] : 0000000000000000000000000000000000000000000000000000000017d78400
Arg [13] : 0000000000000000000000000000000000000000000000000000000023c34600
Arg [14] : 000000000000000000000000000000000000000000000000000000002faf0800
Arg [15] : 000000000000000000000000000000000000000000000000000000003b9aca00
Arg [16] : 000000000000000000000000000000000000000000000000000000003b9aca00
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [18] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [19] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [21] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
524:27468:15:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18495:115;;;;;;:::i;:::-;-1:-1:-1;;;;;18587:16:15;18561:7;18587:16;;;:6;:16;;;;;;;18495:115;;;;548:25:16;;;536:2;521:18;18495:115:15;;;;;;;;27886:104;;;;;;:::i;:::-;;:::i;:::-;;4845:26;;;;;-1:-1:-1;;;4845:26:15;;;;;;;;;758:10:16;746:23;;;728:42;;716:2;701:18;4845:26:15;584:192:16;8615:2723:15;;;;;;:::i;:::-;;:::i;6505:24::-;;;;;;5203:41;;;;;-1:-1:-1;;;5203:41:15;;;;;;;;;2694:6:16;2682:19;;;2664:38;;2652:2;2637:18;5203:41:15;2520:188:16;5861:35:15;;;;;;19033:117;;;:::i;:::-;;;;;;;:::i;11423:4095::-;;;;;;:::i;:::-;;:::i;5348:33::-;;;;;;4746:28;;;;;;;;;4123:41;;;;;4454:34;;;;;;3379:45;;;;;;;;-1:-1:-1;;;;;4081:32:16;;;4063:51;;4051:2;4036:18;3379:45:15;3895:225:16;2293:101:0;;;:::i;20177:1758:15:-;;;;;;:::i;:::-;;:::i;19259:803::-;;;;;;:::i;:::-;;:::i;18873:100::-;;;:::i;:::-;;;;;;;:::i;1638:85:0:-;1684:7;1710:6;-1:-1:-1;;;;;1710:6:0;1638:85;;5659:27:15;;;;;-1:-1:-1;;;5659:27:15;;;;;;6015:33;;;;;;22829:1211;;;;;;:::i;:::-;;:::i;6345:41::-;;;;;;3970:38;;;;;6176:41;;;;;;24138:2332;;;;;;:::i;:::-;;:::i;3226:25::-;;;;;-1:-1:-1;;;;;3226:25:15;;;4989:33;;;;;-1:-1:-1;;;4989:33:15;;;;;;7167:48;;;;;;;;;;;;6322:14:16;;6315:22;6297:41;;6285:2;6270:18;7167:48:15;6157:187:16;22050:603:15;;;;;;:::i;:::-;;:::i;5558:29::-;;;;;;;;;15579:2641;;;;;;:::i;:::-;;:::i;2543:215:0:-;;;;;;:::i;:::-;;:::i;4580:36:15:-;;;;;;18292:133;;;;;;:::i;:::-;-1:-1:-1;;;;;18400:18:15;18374:7;18400:18;;;:8;:18;;;;;;;18292:133;26638:1152;;;;;;:::i;:::-;;:::i;3528:32::-;;;;;4337:27;;;;;-1:-1:-1;;;;;4337:27:15;;;18681:131;;;;;;:::i;:::-;-1:-1:-1;;;;;18788:17:15;18762:7;18788:17;;;:7;:17;;;;;;;18681:131;3857:40;;;;;27886:104;1531:13:0;:11;:13::i;:::-;27959:10:15::1;:24:::0;;-1:-1:-1;;;;;;27959:24:15::1;-1:-1:-1::0;;;;;27959:24:15;;;::::1;::::0;;;::::1;::::0;;27886:104::o;8615:2723::-;2356:21:8;:19;:21::i;:::-;8863:16:15::1;8845:34;;:15;:34;:82;;;;8913:14;8895:32;;:15;:32;8845:82;8828:132;;;8945:15;;-1:-1:-1::0;;;8945:15:15::1;;;;;;;;;;;8828:132;9034:20;9016:38;;:15;:38;9012:69;;;9063:18;;-1:-1:-1::0;;;9063:18:15::1;;;;;;;;;;;9012:69;9215:10;::::0;9339:334:::1;::::0;;9385:13:::1;9339:334;::::0;::::1;6974:19:16::0;-1:-1:-1;;;;;;9436:4:15::1;7081:2:16::0;7077:15;;;7073:24;;7059:12;;;7052:46;;;;-1:-1:-1;;;7114:12:16;;;7107:31;9510:10:15::1;7172:15:16::0;;;7168:24;;;7154:12;;;7147:46;-1:-1:-1;;;;;;7249:3:16;7227:16;;;7223:36;7209:12;;;7202:58;7276:12;;;7269:28;;;-1:-1:-1;;;;;;7354:3:16;7332:16;;;7328:43;7313:13;;;7306:66;9161:594:15::1;::::0;-1:-1:-1;;;;;9215:10:15::1;::::0;9243:470:::1;::::0;7388:13:16;;9339:334:15::1;;;;;;;;;;;;;9304:391;;;;;;1403:34:11::0;1298:14;1390:48;;;1499:4;1492:25;;;;1597:4;1581:21;;;1222:460;9243:470:15::1;9731:10;9161:36;:594::i;:::-;9143:648;;9773:18;;-1:-1:-1::0;;;9773:18:15::1;;;;;;;;;;;9143:648;9832:13;9894:6;9859:19;9879:10;9859:31;;;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;::::1;;::::0;9849:41:::1;::::0;9859:31;;::::1;;;;::::0;::::1;;;9849:7:::0;:41:::1;:::i;:::-;9848:52;;;;:::i;:::-;9832:68;;9968:5;9956:9;;:17;;;;:::i;:::-;9944:9;:29:::0;10051:38:::1;::::0;-1:-1:-1;;;10051:38:15;;10083:4:::1;10051:38;::::0;::::1;4063:51:16::0;10024:24:15::1;::::0;10051:13:::1;-1:-1:-1::0;;;;;10051:23:15::1;::::0;::::1;::::0;4036:18:16;;10051:38:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10024:65:::0;-1:-1:-1;10137:120:15::1;10181:10;10213:4;10232:15;10242:5:::0;10232:7;:15:::1;:::i;:::-;-1:-1:-1::0;;;;;10137:13:15::1;:30;::::0;:120;;:30:::1;:120::i;:::-;10344:38;::::0;-1:-1:-1;;;10344:38:15;;10376:4:::1;10344:38;::::0;::::1;4063:51:16::0;10315:26:15::1;::::0;10428:5;;10397:16;;-1:-1:-1;;;;;10344:13:15::1;:23;::::0;::::1;::::0;4036:18:16;;10344:38:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:69;;;;:::i;:::-;:89;;;;:::i;:::-;10315:118;;10481:18;10503:1;10481:23:::0;10477:55:::1;;10513:19;;-1:-1:-1::0;;;10513:19:15::1;;;;;;;;;;;10477:55;10604:37;10625:16;10604:18:::0;:37:::1;:::i;:::-;:42:::0;10600:85:::1;;10667:18;;-1:-1:-1::0;;;10667:18:15::1;;;;;;;;;;;10600:85;10783:18;10760:20;;:41;;;;:::i;:::-;10737:20;:64:::0;10860:7:::1;:11:::0;;;;:45:::1;;;10898:7;10875:20;;:30;10860:45;10856:86;;;10926:16;;-1:-1:-1::0;;;10926:16:15::1;;;;;;;;;;;10856:86;11014:10;10986:16;11005:20:::0;;;:8:::1;:20;::::0;;;;;:41:::1;::::0;11028:18;;11005:41:::1;:::i;:::-;10986:60;;11118:10;11129;11118:22;;;;;;;;;;:::i;:::-;;;;;;;;;11107:8;:33;11103:64;;;11149:18;;-1:-1:-1::0;;;11149:18:15::1;;;;;;;;;;;11103:64;11213:10;11204:20;::::0;;;:8:::1;:20;::::0;;;;;;;;:31;;;11273:58;;8873:25:16;;;8946:4;8934:17;;8914:18;;;8907:45;;;;8968:18;;;8961:34;;;11273:58:15::1;::::0;8861:2:16;8846:18;11273:58:15::1;;;;;;;8781:2557;;;;2398:20:8::0;1713:1;2924:21;;2744:208;2398:20;8615:2723:15;;;;:::o;19033:117::-;19090:15;19124:19;19117:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19033:117;:::o;11423:4095::-;11657:14;;;;11639:15;:32;;:66;;-1:-1:-1;11693:12:15;;-1:-1:-1;;;11693:12:15;;;;11675:15;:30;11639:66;11635:104;;;11726:13;;-1:-1:-1;;;11726:13:15;;;;;;;;;;;11635:104;11813:20;11795:38;;:15;:38;11791:69;;;11842:18;;-1:-1:-1;;;11842:18:15;;;;;;;;;;;11791:69;11994:10;;12118:343;;;12164:13;12118:343;;;9374:19:16;-1:-1:-1;;;;;;12215:4:15;9481:2:16;9477:15;;;9473:24;;9459:12;;;9452:46;;;;-1:-1:-1;;;9514:12:16;;;9507:29;12287:10:15;9570:15:16;;;9566:24;;;9552:12;;;9545:46;9607:12;;;9600:28;;;9644:13;;;9637:29;;;-1:-1:-1;;;;;;9723:3:16;9701:16;;;9697:43;9682:13;;;9675:66;11940:603:15;;-1:-1:-1;;;;;11994:10:15;;12022:479;;9757:13:16;;12118:343:15;9006:770:16;11940:603:15;11922:657;;12561:18;;-1:-1:-1;;;12561:18:15;;;;;;;;;;;11922:657;12658:33;12675:16;12658:14;:33;:::i;:::-;:38;12654:69;;12705:18;;-1:-1:-1;;;12705:18:15;;;;;;;;;;;12654:69;12802:33;12819:16;12802:14;:33;:::i;:::-;:38;12798:69;;12849:18;;-1:-1:-1;;;12849:18:15;;;;;;;;;;;12798:69;12946:10;12910:24;12937:20;;;:8;:20;;;;;;;;;13023:6;:18;;;;;;13109:7;:19;;;;;;13186:32;;;13182:62;;;13227:17;;-1:-1:-1;;;13227:17:15;;;;;;;;;;;13182:62;13293:16;13313:1;13293:21;13289:53;;13323:19;;-1:-1:-1;;;13323:19:15;;;;;;;;;;;13289:53;13478:16;13444:31;13461:14;13444;:31;:::i;:::-;:50;13440:91;;;13515:16;;-1:-1:-1;;;13515:16:15;;;;;;;;;;;13440:91;13574:24;13601:79;13632:10;13656:14;13601:17;:79::i;:::-;13574:106;-1:-1:-1;13738:20:15;;13734:466;;13837:33;13854:16;13837:14;:33;:::i;:::-;13823:10;13816:18;;;;:6;:18;;;;;:54;13949:18;;:37;;13970:16;;13949:37;:::i;:::-;13928:18;:58;;;14119:18;;-1:-1:-1;14094:95:15;;;14162:27;;-1:-1:-1;;;14162:27:15;;;;;;;;;;;14094:95;14262:25;14290:32;14307:15;14290:14;:32;:::i;:::-;14262:60;-1:-1:-1;14381:21:15;;14377:325;;14482:35;14500:17;14482:15;:35;:::i;:::-;14468:10;14460:19;;;;:7;:19;;;;;:57;14629:26;;:62;;14674:17;;14629:62;:::i;:::-;14584:26;:107;14377:325;14767:21;;:47;;;;-1:-1:-1;14792:22:15;;14767:47;14763:91;;;14835:19;;-1:-1:-1;;;14835:19:15;;;;;;;;;;;14763:91;14916:31;14969:1;14950:16;:20;:172;;15121:1;14950:172;;;15087:19;;15062:21;;15027:5;;;;;;;;;-1:-1:-1;;;;;15027:5:15;-1:-1:-1;;;;;15027:14:15;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15021:22;;:2;:22;:::i;:::-;14986:57;;:16;:57;:::i;:::-;:97;;;;:::i;:::-;14985:121;;;;:::i;:::-;14916:206;-1:-1:-1;15173:27:15;;15169:100;;15214:5;;:55;;-1:-1:-1;;;;;15214:5:15;15233:10;15245:23;15214:18;:55::i;:::-;15320:21;;15316:96;;15355:57;-1:-1:-1;;;;;15355:13:15;:26;15382:10;15394:17;15355:26;:57::i;:::-;15450:61;;;11590:25:16;;;11646:2;11631:18;;11624:34;;;15456:10:15;;15450:61;;11563:18:16;15450:61:15;;;;;;;11587:3931;;;;;;11423:4095;;;;:::o;2293:101:0:-;1531:13;:11;:13::i;:::-;2357:30:::1;2384:1;2357:18;:30::i;:::-;2293:101::o:0;20177:1758:15:-;1531:13:0;:11;:13::i;:::-;20572:5:15::1;::::0;-1:-1:-1;;;;;20572:5:15::1;:35:::0;20568:66:::1;;20616:18;;-1:-1:-1::0;;;20616:18:15::1;;;;;;;;;;;20568:66;20660:5;:14:::0;;-1:-1:-1;;;;;;20660:14:15::1;-1:-1:-1::0;;;;;20660:14:15;::::1;;::::0;;20684:19:::1;:42:::0;;;20736:21:::1;:46:::0;;;20792:14:::1;:32:::0;;::::1;::::0;;::::1;-1:-1:-1::0;;20834:28:15;;;;;;;-1:-1:-1;;;20834:28:15;;::::1;;;-1:-1:-1::0;;20924:58:15;-1:-1:-1;;;20872:42:15;;::::1;;-1:-1:-1::0;;;;20924:58:15;;-1:-1:-1;;;20924:58:15::1;::::0;::::1;;;::::0;;;;20992:18:::1;:40:::0;;;21074:14:::1;-1:-1:-1::0;21074:19:15;21070:46:::1;;21102:14;;-1:-1:-1::0;;;21102:14:15::1;;;;;;;;;;;21070:46;21130:12;::::0;-1:-1:-1;;;21130:12:15;::::1;;;21146:1;21130:17:::0;21126:44:::1;;21156:14;;-1:-1:-1::0;;;21156:14:15::1;;;;;;;;;;;21126:44;21202:12;::::0;::::1;-1:-1:-1::0;;;21202:12:15;::::1;::::0;::::1;21184:14:::0;::::1;:30;21180:57;;21223:14;;-1:-1:-1::0;;;21223:14:15::1;;;;;;;;;;;21180:57;21269:14;::::0;::::1;::::0;;::::1;21251;:32:::0;;::::1;;21247:59;;21292:14;;-1:-1:-1::0;;;21292:14:15::1;;;;;;;;;;;21247:59;21342:14;::::0;::::1;::::0;;::::1;-1:-1:-1::0;;;21320:19:15;;::::1;;:36;21316:63;;;21365:14;;-1:-1:-1::0;;;21365:14:15::1;;;;;;;;;;;21316:63;21415:12;::::0;::::1;-1:-1:-1::0;;;21415:12:15;::::1;::::0;::::1;-1:-1:-1::0;;;21393:19:15;;::::1;;:34;21389:61;;;21436:14;;-1:-1:-1::0;;;21436:14:15::1;;;;;;;;;;;21389:61;21490:19;;21513:1;21490:24:::0;21486:53:::1;;21523:16;;-1:-1:-1::0;;;21523:16:15::1;;;;;;;;;;;21486:53;21553:21;;21578:1;21553:26:::0;21549:55:::1;;21588:16;;-1:-1:-1::0;;;21588:16:15::1;;;;;;;;;;;21549:55;21618:18;;21640:1;21618:23:::0;21614:52:::1;;21650:16;;-1:-1:-1::0;;;21650:16:15::1;;;;;;;;;;;21614:52;21734:27;::::0;21764:6:::1;-1:-1:-1::0;;;21734:27:15;;::::1;;;:36;21730:65;;;21779:16;;-1:-1:-1::0;;;21779:16:15::1;;;;;;;;;;;21730:65;21872:5;;;;;;;;;-1:-1:-1::0;;;;;21872:5:15::1;-1:-1:-1::0;;;;;21872:14:15::1;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;21898:5:15::1;::::0;:30:::1;::::0;-1:-1:-1;;;21898:30:15;;21922:4:::1;21898:30;::::0;::::1;4063:51:16::0;-1:-1:-1;;;;;21898:5:15;;::::1;::::0;:15:::1;::::0;4036:18:16;;21898:30:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;20177:1758:::0;;;;;;;;:::o;19259:803::-;19457:14;;19371:7;;19457:14;;19439:15;:32;19435:46;;;-1:-1:-1;19480:1:15;19473:8;;19435:46;19569:19;;-1:-1:-1;;;19569:19:15;;;;19550:15;:38;19546:96;;-1:-1:-1;;;;;19626:16:15;;;;;;:6;:16;;;;;;19609:33;;:14;:33;:::i;:::-;19602:40;;;;19546:96;-1:-1:-1;;;;;20039:16:15;;;;;;:6;:16;;;;;;20020:14;;19998:36;;20020:14;;;;;-1:-1:-1;;;19998:19:15;;;:36;:::i;:::-;19936:14;;19825:210;;;;;19918:32;;19936:14;19918:15;:32;:::i;:::-;19855:27;;19907:6;;19846:36;;-1:-1:-1;;;19855:27:15;;;;19907:6;19846:36;:::i;:::-;19828:55;;;;:14;:55;:::i;:::-;19827:86;;;;:::i;:::-;19826:125;;;;:::i;:::-;19825:210;;;;:::i;:::-;19759:27;;19790:6;;19742:44;;-1:-1:-1;;;19759:27:15;;;;19742:14;:44;:::i;:::-;19741:55;;;;:::i;:::-;19740:295;;;;:::i;:::-;19739:316;;;;:::i;:::-;19720:335;;19259:803;;;;;:::o;18873:100::-;18921:16;18956:10;18949:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18873:100;:::o;22829:1211::-;1531:13:0;:11;:13::i;:::-;22970:36:15::1;::::0;::::1;;22966:99;;;23027:38;;-1:-1:-1::0;;;23027:38:15::1;;;;;;;;;;;22966:99;23076:36;:43:::0;;-1:-1:-1;;23076:43:15::1;23115:4;23076:43;::::0;;23180:33:::1;23199:14;23180:33;:15;:33;23176:62;;23222:16;;-1:-1:-1::0;;;23222:16:15::1;;;;;;;;;;;23176:62;23298:13;::::0;-1:-1:-1;;;23298:13:15;::::1;;;:17:::0;;;;:53:::1;;-1:-1:-1::0;23338:13:15::1;::::0;-1:-1:-1;;;23338:13:15;::::1;;;23319:15;:32;;23298:53;23294:94;;;23372:16;;-1:-1:-1::0;;;23372:16:15::1;;;;;;;;;;;23294:94;23468:33;23539:18;;23504:20;;:53;:121;;23607:18;;23504:121;;;23572:20;;23504:121;23468:157;;23685:34;23786:26;;23762:9;;23722:25;:49;;;;:::i;:::-;:90;;;;:::i;:::-;23685:127;;23875:26;23905:1;23875:31:::0;23871:63:::1;;23915:19;;-1:-1:-1::0;;;23915:19:15::1;;;;;;;;;;;23871:63;23974:59;-1:-1:-1::0;;;;;23974:13:15::1;:26;24001:3:::0;24006:26;23974::::1;:59::i;:::-;22900:1140;;22829:1211:::0;:::o;24138:2332::-;1531:13:0;:11;:13::i;:::-;24244:5:15::1;::::0;-1:-1:-1;;;;;24244:5:15::1;24240:62;;24288:14;;-1:-1:-1::0;;;24288:14:15::1;;;;;;;;;;;24240:62;24382:33;24453:18;;24418:20;;:53;:121;;24521:18;;24418:121;;;24486:20;;24418:121;24603:5;::::0;:30:::1;::::0;-1:-1:-1;;;24603:30:15;;24627:4:::1;24603:30;::::0;::::1;4063:51:16::0;24382:157:15;;-1:-1:-1;24579:21:15::1;::::0;-1:-1:-1;;;;;24603:5:15;;::::1;::::0;:15:::1;::::0;4036:18:16;;24603:30:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;24708:5;::::0;24579:54;;-1:-1:-1;;;;;;24717:13:15::1;24708:22:::0;::::1;:5:::0;::::1;:22:::0;24704:1113:::1;;24792:24;24902:26;;24858:25;24819:20;;:64;;;;:::i;:::-;:109;;;;:::i;:::-;25065:36;::::0;24792:136;;-1:-1:-1;25065:36:15::1;;25060:545;;25226:34;25343:26;;25311:9;;25263:25;:57;;;;:::i;:::-;:106;;;;:::i;:::-;25226:143:::0;-1:-1:-1;25525:65:15::1;25226:143:::0;25525:16;:65:::1;:::i;:::-;25486:104;;25103:502;25060:545;25774:32;25790:16:::0;25774:13;:32:::1;:::i;:::-;25758:48;;24732:1085;24704:1113;25869:24;25969:26;;25936:18;;25896:25;:58;;;;:::i;:::-;:99;;;;:::i;:::-;25869:126;;26051:31;26179:19;;26154:21;;26123:5;;;;;;;;;-1:-1:-1::0;;;;;26123:5:15::1;-1:-1:-1::0;;;;;26123:14:15::1;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;26117:22;::::0;:2:::1;:22;:::i;:::-;26086:53;::::0;:16;:53:::1;:::i;:::-;:89;;;;:::i;:::-;26085:113;;;;:::i;:::-;26051:147;;26299:23;26282:13;:40;26278:84;;26343:19;;-1:-1:-1::0;;;26343:19:15::1;;;;;;;;;;;26278:84;26399:64;26418:3:::0;26423:39:::1;26439:23:::0;26423:13;:39:::1;:::i;:::-;26399:5;::::0;-1:-1:-1;;;;;26399:5:15::1;::::0;:64;:18:::1;:64::i;:::-;24199:2271;;;;24138:2332:::0;:::o;22050:603::-;1531:13:0;:11;:13::i;:::-;22220:15:15::1;::::0;::::1;;:20:::0;22216:51:::1;;22249:18;;-1:-1:-1::0;;;22249:18:15::1;;;;;;;;;;;22216:51;22293:15;:34:::0;;::::1;22337:30:::0;;::::1;-1:-1:-1::0;;;22337:30:15::1;-1:-1:-1::0;;22337:30:15;;;22293:34;;::::1;22337:30:::0;;;;::::1;::::0;;;;22409:15:::1;22293;22409:20:::0;22405:47:::1;;22438:14;;-1:-1:-1::0;;;22438:14:15::1;;;;;;;;;;;22405:47;22466:13;::::0;-1:-1:-1;;;22466:13:15;::::1;;;22483:1;22466:18:::0;22462:45:::1;;22493:14;;-1:-1:-1::0;;;22493:14:15::1;;;;;;;;;;;22462:45;22540:13;::::0;::::1;-1:-1:-1::0;;;22540:13:15;::::1;::::0;::::1;22521:15:::0;::::1;:32;22517:59;;22562:14;;-1:-1:-1::0;;;22562:14:15::1;;;;;;;;;;;22517:59;22608:15;::::0;::::1;::::0;;::::1;22590:14;:33:::0;;::::1;;22586:60;;22632:14;;-1:-1:-1::0;;;22632:14:15::1;;;;;;;;;;;22586:60;22050:603:::0;;:::o;15579:2641::-;15828:15;;;;15810;:33;;:68;;-1:-1:-1;15865:13:15;;-1:-1:-1;;;15865:13:15;;;;15847:15;:31;15810:68;15793:117;;;15896:14;;-1:-1:-1;;;15896:14:15;;;;;;;;;;;15793:117;15984:20;15966:38;;:15;:38;15962:69;;;16013:18;;-1:-1:-1;;;16013:18:15;;;;;;;;;;;15962:69;16165:10;;16289:344;;;16335:13;16289:344;;;12393:19:16;-1:-1:-1;;;;;;16386:4:15;12500:2:16;12496:15;;;12492:24;;12478:12;;;12471:46;;;;-1:-1:-1;;;12533:12:16;;;12526:30;16459:10:15;12590:15:16;;;12586:24;;;12572:12;;;12565:46;12627:12;;;12620:28;;;12664:13;;;12657:29;;;-1:-1:-1;;;;;;12743:3:16;12721:16;;;12717:43;12702:13;;;12695:66;16111:604:15;;-1:-1:-1;;;;;16165:10:15;;16193:480;;12777:13:16;;16289:344:15;12025:771:16;16111:604:15;16093:658;;16733:18;;-1:-1:-1;;;16733:18:15;;;;;;;;;;;16093:658;16830:33;16847:16;16830:14;:33;:::i;:::-;:38;16826:69;;16877:18;;-1:-1:-1;;;16877:18:15;;;;;;;;;;;16826:69;16974:33;16991:16;16974:14;:33;:::i;:::-;:38;16970:69;;17021:18;;-1:-1:-1;;;17021:18:15;;;;;;;;;;;16970:69;17097:10;17111:1;17090:18;;;:6;:18;;;;;;:22;17086:51;;17121:16;;-1:-1:-1;;;17121:16:15;;;;;;;;;;;17086:51;17197:10;17211:1;17189:19;;;:7;:19;;;;;;:23;17185:53;;17221:17;;-1:-1:-1;;;17221:17:15;;;;;;;;;;;17185:53;17317:10;17281:24;17308:20;;;:8;:20;;;;;;;17377:21;;;17373:53;;17407:19;;-1:-1:-1;;;17407:19:15;;;;;;;;;;;17373:53;17559:16;17524:31;17541:14;17524;:31;:::i;:::-;:51;17520:92;;17596:16;;-1:-1:-1;;;17596:16:15;;;;;;;;;;;17520:92;17668:10;17660:19;;;;:7;:19;;;;;:38;;;17799:26;;:55;;17840:14;;17799:55;:::i;:::-;17758:26;:96;17955:26;;:55;;17996:14;;17955:55;:::i;:::-;17914:26;:96;18069:56;-1:-1:-1;;;;;18069:13:15;:26;18096:10;18108:16;18069:26;:56::i;:::-;18163:50;;;11590:25:16;;;11646:2;11631:18;;11624:34;;;18170:10:15;;18163:50;;11563:18:16;18163:50:15;;;;;;;15744:2476;15579:2641;;;;:::o;2543:215:0:-;1531:13;:11;:13::i;:::-;-1:-1:-1;;;;;2627:22:0;::::1;2623:91;;2672:31;::::0;-1:-1:-1;;;2672:31:0;;2700:1:::1;2672:31;::::0;::::1;4063:51:16::0;4036:18;;2672:31:0::1;;;;;;;;2623:91;2723:28;2742:8;2723:18;:28::i;:::-;2543:215:::0;:::o;26638:1152:15:-;1531:13:0;:11;:13::i;:::-;26770:14:15::1;26751:33;;:15;:33;26747:62;;26793:16;;-1:-1:-1::0;;;26793:16:15::1;;;;;;;;;;;26747:62;26868:12;::::0;-1:-1:-1;;;26868:12:15;::::1;;;:16:::0;;;;:51:::1;;-1:-1:-1::0;26907:12:15::1;::::0;-1:-1:-1;;;26907:12:15;::::1;;;26888:15;:31;;26868:51;26864:92;;;26940:16;;-1:-1:-1::0;;;26940:16:15::1;;;;;;;;;;;26864:92;27016:13;::::0;-1:-1:-1;;;27016:13:15;::::1;;;:17:::0;;;;:53:::1;;-1:-1:-1::0;27056:13:15::1;::::0;-1:-1:-1;;;27056:13:15;::::1;;;27037:15;:32;;27016:53;27012:94;;;27090:16;;-1:-1:-1::0;;;27090:16:15::1;;;;;;;;;;;27012:94;27176:38;::::0;-1:-1:-1;;;27176:38:15;;27208:4:::1;27176:38;::::0;::::1;4063:51:16::0;27149:24:15::1;::::0;27176:13:::1;-1:-1:-1::0;;;;;27176:23:15::1;::::0;::::1;::::0;4036:18:16;;27176:38:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;27278:5;::::0;27149:65;;-1:-1:-1;27254:21:15::1;::::0;-1:-1:-1;;;;;27278:5:15::1;:35:::0;;::::1;::::0;:73:::1;;-1:-1:-1::0;27329:5:15::1;::::0;27338:13:::1;-1:-1:-1::0;;;;;27329:22:15;;::::1;:5:::0;::::1;:22;;27278:73;:134;;27411:1;27278:134;;;27366:5;::::0;:30:::1;::::0;-1:-1:-1;;;27366:30:15;;27390:4:::1;27366:30;::::0;::::1;4063:51:16::0;-1:-1:-1;;;;;27366:5:15;;::::1;::::0;:15:::1;::::0;4036:18:16;;27366:30:15::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;27254:158:::0;-1:-1:-1;27475:21:15;;:43;::::1;;;-1:-1:-1::0;27500:18:15;;27475:43:::1;27471:87;;;27539:19;;-1:-1:-1::0;;;27539:19:15::1;;;;;;;;;;;27471:87;27602:20:::0;;27598:87:::1;;27636:49;-1:-1:-1::0;;;;;27636:13:15::1;:26;27663:3:::0;27668:16;27636:26:::1;:49::i;:::-;27726:17:::0;;27722:61:::1;;27745:5;::::0;:38:::1;::::0;-1:-1:-1;;;;;27745:5:15::1;27764:3:::0;27769:13;27745:18:::1;:38::i;1796:162:0:-:0;1684:7;1710:6;-1:-1:-1;;;;;1710:6:0;735:10:7;1855:23:0;1851:101;;1901:40;;-1:-1:-1;;;1901:40:0;;735:10:7;1901:40:0;;;4063:51:16;4036:18;;1901:40:0;3895:225:16;2431:307:8;1755:1;2558:7;;:18;2554:86;;2599:30;;-1:-1:-1;;;2599:30:8;;;;;;;;;;;2554:86;1755:1;2714:7;:17;2431:307::o;1039:368:12:-;1145:4;1162:17;1181:24;1211:33;1228:4;1234:9;1211:16;:33::i;:::-;-1:-1:-1;1161:83:12;;-1:-1:-1;1161:83:12;-1:-1:-1;1283:26:12;1274:5;:35;;;;;;;;:::i;:::-;;:58;;;;;1326:6;-1:-1:-1;;;;;1313:19:12;:9;-1:-1:-1;;;;;1313:19:12;;1274:58;1273:127;;;;1349:51;1376:6;1384:4;1390:9;1349:26;:51::i;:::-;1254:146;;;;1039:368;;;;;;:::o;1702:188:5:-;1829:53;;-1:-1:-1;;;;;13191:15:16;;;1829:53:5;;;13173:34:16;13243:15;;;13223:18;;;13216:43;13275:18;;;13268:34;;;1802:81:5;;1822:5;;1844:18;;;;;13108::16;;1829:53:5;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1829:53:5;;;;;;;;;;;1802:19;:81::i;1303:160::-;1412:43;;-1:-1:-1;;;;;13505:32:16;;;1412:43:5;;;13487:51:16;13554:18;;;13547:34;;;1385:71:5;;1405:5;;1427:14;;;;;13460:18:16;;1412:43:5;13313:274:16;2912:187:0;2985:16;3004:6;;-1:-1:-1;;;;;3020:17:0;;;-1:-1:-1;;;;;;3020:17:0;;;;;;3052:40;;3004:6;;;;;;;3052:40;;2985:16;3052:40;2975:124;2912:187;:::o;2129:766:10:-;2210:7;2219:12;2233:7;2256:9;:16;2276:2;2256:22;2252:637;;2592:4;2577:20;;2571:27;2641:4;2626:20;;2620:27;2698:4;2683:20;;2677:27;2294:9;2669:36;2739:25;2750:4;2669:36;2571:27;2620;2739:10;:25::i;:::-;2732:32;;;;;;;;;;;2252:637;-1:-1:-1;;2860:16:10;;2811:1;;-1:-1:-1;2815:35:10;;2252:637;2129:766;;;;;:::o;1813:458:12:-;1956:4;1973:12;1987:19;2010:6;-1:-1:-1;;;;;2010:17:12;2084:4;2090:9;2041:60;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;2041:60:12;;;;;;;;;;;;;;-1:-1:-1;;;;;2041:60:12;-1:-1:-1;;;2041:60:12;;;2010:101;;;2041:60;2010:101;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1972:139;;;;2129:7;:42;;;;;2169:2;2152:6;:13;:19;;2129:42;:134;;;;-1:-1:-1;2187:29:12;;-1:-1:-1;;;2228:34:12;2187:29;;;;;;;;;;;;:::i;:::-;:76;;1813:458;-1:-1:-1;;;;;;1813:458:12:o;4059:629:5:-;4478:23;4504:33;-1:-1:-1;;;;;4504:27:5;;4532:4;4504:27;:33::i;:::-;4478:59;;4551:10;:17;4572:1;4551:22;;:57;;;;;4589:10;4578:30;;;;;;;;;;;;:::i;:::-;4577:31;4551:57;4547:135;;;4631:40;;-1:-1:-1;;;4631:40:5;;-1:-1:-1;;;;;4081:32:16;;4631:40:5;;;4063:51:16;4036:18;;4631:40:5;3895:225:16;5140:1530:10;5266:7;;;6199:66;6186:79;;6182:164;;;-1:-1:-1;6297:1:10;;-1:-1:-1;6301:30:10;;-1:-1:-1;6333:1:10;6281:54;;6182:164;6457:24;;;6440:14;6457:24;;;;;;;;;15307:25:16;;;15380:4;15368:17;;15348:18;;;15341:45;;;;15402:18;;;15395:34;;;15445:18;;;15438:34;;;6457:24:10;;15279:19:16;;6457:24:10;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6457:24:10;;-1:-1:-1;;6457:24:10;;;-1:-1:-1;;;;;;;6495:20:10;;6491:113;;-1:-1:-1;6547:1:10;;-1:-1:-1;6551:29:10;;-1:-1:-1;6547:1:10;;-1:-1:-1;6531:62:10;;6491:113;6622:6;-1:-1:-1;6630:20:10;;-1:-1:-1;6630:20:10;;-1:-1:-1;5140:1530:10;;;;;;;;;:::o;2705:151:6:-;2780:12;2811:38;2833:6;2841:4;2847:1;2780:12;3421;3435:23;3462:6;-1:-1:-1;;;;;3462:11:6;3481:5;3488:4;3462:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3420:73;;;;3510:55;3537:6;3545:7;3554:10;4769:12;4798:7;4793:408;;4821:19;4829:10;4821:7;:19::i;:::-;4793:408;;;5045:17;;:22;:49;;;;-1:-1:-1;;;;;;5071:18:6;;;:23;5045:49;5041:119;;;5121:24;;-1:-1:-1;;;5121:24:6;;-1:-1:-1;;;;;4081:32:16;;5121:24:6;;;4063:51:16;4036:18;;5121:24:6;3895:225:16;5041:119:6;-1:-1:-1;5180:10:6;5173:17;;5743:516;5874:17;;:21;5870:383;;6102:10;6096:17;6158:15;6145:10;6141:2;6137:19;6130:44;5870:383;6225:17;;-1:-1:-1;;;6225:17:6;;;;;;;;;;;14:131:16;-1:-1:-1;;;;;89:31:16;;79:42;;69:70;;135:1;132;125:12;150:247;209:6;262:2;250:9;241:7;237:23;233:32;230:52;;;278:1;275;268:12;230:52;317:9;304:23;336:31;361:5;336:31;:::i;781:114::-;865:4;858:5;854:16;847:5;844:27;834:55;;885:1;882;875:12;900:127;961:10;956:3;952:20;949:1;942:31;992:4;989:1;982:15;1016:4;1013:1;1006:15;1032:718;1074:5;1127:3;1120:4;1112:6;1108:17;1104:27;1094:55;;1145:1;1142;1135:12;1094:55;1181:6;1168:20;1207:18;1244:2;1240;1237:10;1234:36;;;1250:18;;:::i;:::-;1325:2;1319:9;1293:2;1379:13;;-1:-1:-1;;1375:22:16;;;1399:2;1371:31;1367:40;1355:53;;;1423:18;;;1443:22;;;1420:46;1417:72;;;1469:18;;:::i;:::-;1509:10;1505:2;1498:22;1544:2;1536:6;1529:18;1590:3;1583:4;1578:2;1570:6;1566:15;1562:26;1559:35;1556:55;;;1607:1;1604;1597:12;1556:55;1671:2;1664:4;1656:6;1652:17;1645:4;1637:6;1633:17;1620:54;1718:1;1711:4;1706:2;1698:6;1694:15;1690:26;1683:37;1738:6;1729:15;;;;;;1032:718;;;;:::o;1755:163::-;1822:20;;1882:10;1871:22;;1861:33;;1851:61;;1908:1;1905;1898:12;1851:61;1755:163;;;:::o;1923:592::-;2015:6;2023;2031;2039;2092:3;2080:9;2071:7;2067:23;2063:33;2060:53;;;2109:1;2106;2099:12;2060:53;2145:9;2132:23;2122:33;;2205:2;2194:9;2190:18;2177:32;2218:29;2241:5;2218:29;:::i;:::-;2266:5;-1:-1:-1;2322:2:16;2307:18;;2294:32;2349:18;2338:30;;2335:50;;;2381:1;2378;2371:12;2335:50;2404:49;2445:7;2436:6;2425:9;2421:22;2404:49;:::i;:::-;2394:59;;;2472:37;2505:2;2494:9;2490:18;2472:37;:::i;:::-;2462:47;;1923:592;;;;;;;:::o;2713:643::-;2882:2;2934:21;;;3004:13;;2907:18;;;3026:22;;;2853:4;;2882:2;3105:15;;;;3079:2;3064:18;;;2853:4;3148:182;3162:6;3159:1;3156:13;3148:182;;;3227:13;;3242:6;3223:26;3211:39;;3305:15;;;;3270:12;;;;3184:1;3177:9;3148:182;;;-1:-1:-1;3347:3:16;;2713:643;-1:-1:-1;;;;;;2713:643:16:o;3361:529::-;3455:6;3463;3471;3479;3532:3;3520:9;3511:7;3507:23;3503:33;3500:53;;;3549:1;3546;3539:12;3500:53;3585:9;3572:23;3562:33;;3642:2;3631:9;3627:18;3614:32;3604:42;;3697:2;3686:9;3682:18;3669:32;3724:18;3716:6;3713:30;3710:50;;;3756:1;3753;3746:12;4125:862;4265:6;4273;4281;4289;4297;4305;4313;4321;4374:3;4362:9;4353:7;4349:23;4345:33;4342:53;;;4391:1;4388;4381:12;4342:53;4430:9;4417:23;4449:31;4474:5;4449:31;:::i;:::-;4499:5;-1:-1:-1;4551:2:16;4536:18;;4523:32;;-1:-1:-1;4602:2:16;4587:18;;4574:32;;-1:-1:-1;4625:37:16;4658:2;4643:18;;4625:37;:::i;:::-;4615:47;;4681:38;4714:3;4703:9;4699:19;4681:38;:::i;:::-;4671:48;;4738:38;4771:3;4760:9;4756:19;4738:38;:::i;:::-;4728:48;;4828:3;4817:9;4813:19;4800:33;4877:6;4868:7;4864:20;4855:7;4852:33;4842:61;;4899:1;4896;4889:12;4842:61;4922:7;4912:17;;;4976:3;4965:9;4961:19;4948:33;4938:43;;4125:862;;;;;;;;;;;:::o;4992:315::-;5060:6;5068;5121:2;5109:9;5100:7;5096:23;5092:32;5089:52;;;5137:1;5134;5127:12;5089:52;5176:9;5163:23;5195:31;5220:5;5195:31;:::i;:::-;5245:5;5297:2;5282:18;;;;5269:32;;-1:-1:-1;;;4992:315:16:o;5312:632::-;5483:2;5535:21;;;5605:13;;5508:18;;;5627:22;;;5454:4;;5483:2;5706:15;;;;5680:2;5665:18;;;5454:4;5749:169;5763:6;5760:1;5757:13;5749:169;;;5824:13;;5812:26;;5893:15;;;;5858:12;;;;5785:1;5778:9;5749:169;;6349:256;6415:6;6423;6476:2;6464:9;6455:7;6451:23;6447:32;6444:52;;;6492:1;6489;6482:12;6444:52;6515:28;6533:9;6515:28;:::i;:::-;6505:38;;6562:37;6595:2;6584:9;6580:18;6562:37;:::i;:::-;6552:47;;6349:256;;;;;:::o;7412:127::-;7473:10;7468:3;7464:20;7461:1;7454:31;7504:4;7501:1;7494:15;7528:4;7525:1;7518:15;7544:127;7605:10;7600:3;7596:20;7593:1;7586:31;7636:4;7633:1;7626:15;7660:4;7657:1;7650:15;7676:168;7749:9;;;7780;;7797:15;;;7791:22;;7777:37;7767:71;;7818:18;;:::i;7849:127::-;7910:10;7905:3;7901:20;7898:1;7891:31;7941:4;7938:1;7931:15;7965:4;7962:1;7955:15;7981:120;8021:1;8047;8037:35;;8052:18;;:::i;:::-;-1:-1:-1;8086:9:16;;7981:120::o;8106:125::-;8171:9;;;8192:10;;;8189:36;;;8205:18;;:::i;8236:184::-;8306:6;8359:2;8347:9;8338:7;8334:23;8330:32;8327:52;;;8375:1;8372;8365:12;8327:52;-1:-1:-1;8398:16:16;;8236:184;-1:-1:-1;8236:184:16:o;8425:128::-;8492:9;;;8513:11;;;8510:37;;;8527:18;;:::i;8558:112::-;8590:1;8616;8606:35;;8621:18;;:::i;:::-;-1:-1:-1;8655:9:16;;8558:112::o;9781:247::-;9849:6;9902:2;9890:9;9881:7;9877:23;9873:32;9870:52;;;9918:1;9915;9908:12;9870:52;9950:9;9944:16;9969:29;9992:5;9969:29;:::i;10033:422::-;10122:1;10165:5;10122:1;10179:270;10200:7;10190:8;10187:21;10179:270;;;10259:4;10255:1;10251:6;10247:17;10241:4;10238:27;10235:53;;;10268:18;;:::i;:::-;10318:7;10308:8;10304:22;10301:55;;;10338:16;;;;10301:55;10417:22;;;;10377:15;;;;10179:270;;;10183:3;10033:422;;;;;:::o;10460:806::-;10509:5;10539:8;10529:80;;-1:-1:-1;10580:1:16;10594:5;;10529:80;10628:4;10618:76;;-1:-1:-1;10665:1:16;10679:5;;10618:76;10710:4;10728:1;10723:59;;;;10796:1;10791:130;;;;10703:218;;10723:59;10753:1;10744:10;;10767:5;;;10791:130;10828:3;10818:8;10815:17;10812:43;;;10835:18;;:::i;:::-;-1:-1:-1;;10891:1:16;10877:16;;10906:5;;10703:218;;11005:2;10995:8;10992:16;10986:3;10980:4;10977:13;10973:36;10967:2;10957:8;10954:16;10949:2;10943:4;10940:12;10936:35;10933:77;10930:159;;;-1:-1:-1;11042:19:16;;;11074:5;;10930:159;11121:34;11146:8;11140:4;11121:34;:::i;:::-;11191:6;11187:1;11183:6;11179:19;11170:7;11167:32;11164:58;;;11202:18;;:::i;:::-;11240:20;;10460:806;-1:-1:-1;;;10460:806:16:o;11271:140::-;11329:5;11358:47;11399:4;11389:8;11385:19;11379:4;11358:47;:::i;11669:175::-;11737:10;11780;;;11768;;;11764:27;;11803:12;;;11800:38;;;11818:18;;:::i;:::-;11800:38;11669:175;;;;:::o;11849:171::-;11917:6;11956:10;;;11944;;;11940:27;;11979:12;;;11976:38;;;11994:18;;:::i;12801:127::-;12862:10;12857:3;12853:20;12850:1;12843:31;12893:4;12890:1;12883:15;12917:4;12914:1;12907:15;13592:250;13677:1;13687:113;13701:6;13698:1;13695:13;13687:113;;;13777:11;;;13771:18;13758:11;;;13751:39;13723:2;13716:10;13687:113;;;-1:-1:-1;;13834:1:16;13816:16;;13809:27;13592:250::o;13847:465::-;14022:6;14011:9;14004:25;14065:2;14060;14049:9;14045:18;14038:30;13985:4;14097:6;14091:13;14140:6;14135:2;14124:9;14120:18;14113:34;14156:79;14228:6;14223:2;14212:9;14208:18;14203:2;14195:6;14191:15;14156:79;:::i;:::-;14296:2;14275:15;-1:-1:-1;;14271:29:16;14256:45;;;;14303:2;14252:54;;13847:465;-1:-1:-1;;;13847:465:16:o;14317:287::-;14446:3;14484:6;14478:13;14500:66;14559:6;14554:3;14547:4;14539:6;14535:17;14500:66;:::i;:::-;14582:16;;;;;14317:287;-1:-1:-1;;14317:287:16:o;14798:277::-;14865:6;14918:2;14906:9;14897:7;14893:23;14889:32;14886:52;;;14934:1;14931;14924:12;14886:52;14966:9;14960:16;15019:5;15012:13;15005:21;14998:5;14995:32;14985:60;;15041:1;15038;15031:12
Swarm Source
ipfs://62539ec853e07dded8a46c82c40c3e9d12bf7ac9a723382ad5f6ccec773ff387
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.