Source Code
Latest 25 from a total of 33 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Multisend Ether | 146724122 | 4 days ago | IN | 0.0000202 ETH | 0.000000007026 | ||||
| Multisend Token | 146668538 | 5 days ago | IN | 0.000033408860772 ETH | 0.000000017197 | ||||
| Multisend Ether | 146265064 | 15 days ago | IN | 0.001086904109589 ETH | 0.000000013732 | ||||
| Multisend Token | 146264763 | 15 days ago | IN | 0.001458333333333 ETH | 0.000000002263 | ||||
| Multisend Token | 145793714 | 26 days ago | IN | 0.01182920760815 ETH | 0.000000026732 | ||||
| Multisend Token | 145338394 | 36 days ago | IN | 0.000001871676615 ETH | 0.00000025291 | ||||
| Multisend Token | 145111012 | 41 days ago | IN | 0.00595744680851 ETH | 0.000000354674 | ||||
| Multisend Token | 145110954 | 41 days ago | IN | 0.003211009174311 ETH | 0.000000309845 | ||||
| Multisend Token | 145110829 | 41 days ago | IN | 0.016521739130434 ETH | 0.000001706278 | ||||
| Multisend Token | 145110640 | 41 days ago | IN | 0.009271523178807 ETH | 0.000000492567 | ||||
| Multisend Ether | 144975645 | 44 days ago | IN | 0.00002121 ETH | 0.000000031245 | ||||
| Multisend Token | 144762961 | 49 days ago | IN | 0.00227027027027 ETH | 0.000000043437 | ||||
| Multisend Token | 144620655 | 53 days ago | IN | 0.000002043378352 ETH | 0.000000029279 | ||||
| Multisend Token | 144411640 | 58 days ago | IN | 0.000000099092486 ETH | 0.000000040512 | ||||
| Multisend Token | 144398710 | 58 days ago | IN | 0.000000988842141 ETH | 0.000000016175 | ||||
| Multisend Ether | 144362539 | 59 days ago | IN | 0.0000202 ETH | 0.000000125774 | ||||
| Multisend Ether | 144346140 | 59 days ago | IN | 0.001111 ETH | 0.000000034498 | ||||
| Multisend Token ... | 144228318 | 62 days ago | IN | 0 ETH | 0.000000114589 | ||||
| Multisend Ether | 144211391 | 62 days ago | IN | 0.0000404 ETH | 0.000000046319 | ||||
| Multisend Eth Ga... | 144201823 | 62 days ago | IN | 0.000202 ETH | 0.000000153407 | ||||
| Multisend Token | 144197999 | 62 days ago | IN | 0.000003568152206 ETH | 0.000000009921 | ||||
| Multisend Ether | 144188243 | 63 days ago | IN | 0.00002 ETH | 0.000000007834 | ||||
| Multisend Token | 144163036 | 63 days ago | IN | 0 ETH | 0.000000148253 | ||||
| Multisend Ether | 144068818 | 65 days ago | IN | 0.0000002 ETH | 0.000000110766 | ||||
| Multisend Token | 144068490 | 65 days ago | IN | 0 ETH | 0.000000155384 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 146724122 | 4 days ago | 0.00000016 ETH | ||||
| 146724122 | 4 days ago | 0.00000004 ETH | ||||
| 146724122 | 4 days ago | 0.00001 ETH | ||||
| 146724122 | 4 days ago | 0.00001 ETH | ||||
| 146668538 | 5 days ago | 0.000026727088617 ETH | ||||
| 146668538 | 5 days ago | 0.000006681772154 ETH | ||||
| 146265064 | 15 days ago | 0.000767123287671 ETH | ||||
| 146265064 | 15 days ago | 0.000191780821917 ETH | ||||
| 146265064 | 15 days ago | 0.000064 ETH | ||||
| 146265064 | 15 days ago | 0.000064 ETH | ||||
| 146264763 | 15 days ago | 0.001166666666666 ETH | ||||
| 146264763 | 15 days ago | 0.000291666666666 ETH | ||||
| 145793714 | 26 days ago | 0.00946336608652 ETH | ||||
| 145793714 | 26 days ago | 0.00236584152163 ETH | ||||
| 145338394 | 36 days ago | 0.000001497341292 ETH | ||||
| 145338394 | 36 days ago | 0.000000374335323 ETH | ||||
| 145111012 | 41 days ago | 0.004765957446808 ETH | ||||
| 145111012 | 41 days ago | 0.001191489361702 ETH | ||||
| 145110954 | 41 days ago | 0.002568807339449 ETH | ||||
| 145110954 | 41 days ago | 0.000642201834862 ETH | ||||
| 145110829 | 41 days ago | 0.013217391304347 ETH | ||||
| 145110829 | 41 days ago | 0.003304347826086 ETH | ||||
| 145110640 | 41 days ago | 0.007417218543046 ETH | ||||
| 145110640 | 41 days ago | 0.001854304635761 ETH | ||||
| 144975645 | 44 days ago | 0.000000168 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PushSender
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "./ValidationSender.sol";
import "./Messages.sol";
import "../libraries/UnsafeMath.sol";
contract PushSender is ValidationSender, Messages {
using SafeERC20 for IERC20;
using SafeTransferLib for IERC20;
using Address for address payable;
using Address for address;
using UnsafeMath for uint256;
address public constant ETH_ADDRESS = 0x000000000000000000000000000000000000bEEF;
IPermit2 public permit2;
event Multisent(uint256 total, IERC20 tokenAddress);
event Permit2Set(address permit2);
event ReferralModeUpdated(bool newMode);
constructor(
uint256 _fee,
uint256 _referralFee,
address payable _beneficiary20,
address payable _beneficiary80,
VipTier[] memory _tiers,
address _permit2Addr
) {
require(_fee >= _referralFee, "Referral fee can't be more than service fee");
referralFee = _referralFee;
fee = _fee;
require(_beneficiary20 != address(0), "Beneficiary20 can't be zero address");
beneficiary20 = _beneficiary20;
require(_beneficiary80 != address(0), "Beneficiary80 can't be zero address");
beneficiary80 = _beneficiary80;
for (uint8 i = 0; i < _tiers.length; i++) {
require(_tiers[i].price != 0, "Price can't be zero");
require(_tiers[i].duration != 0, "Duration can't be zero");
tiers.push(_tiers[i]);
}
if (_permit2Addr != address(0)) {
permit2 = IPermit2(_permit2Addr);
}
}
function multisendEther(Recipient[] calldata recipients) external payable returns (uint256 gasLeft) {
return _multisendEther(recipients, payable(msg.sender), 0);
}
function multisendEtherWithSignature(Recipient[] calldata recipients, bytes calldata signature, uint256 deadline)
external
payable
returns (uint256 gasLeft)
{
return _multisendEtherWithSignature(recipients, signature, deadline, false, 0);
}
function multisendEtherWithPersonalSignature(
Recipient[] calldata recipients,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendEtherWithSignature(recipients, signature, deadline, true, 0);
}
function multisendEtherWithContractSignature(
Recipient[] calldata recipients,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
return _multisendEther(recipients, payable(signer), 0);
}
function multisendEthGasLimit(Recipient[] calldata recipients, uint256 etherTransferGasLimit)
external
payable
returns (uint256 gasLeft)
{
return _multisendEther(recipients, payable(msg.sender), etherTransferGasLimit);
}
function multisendEthSignatureGasLimit(
Recipient[] calldata recipients,
uint256 etherTransferGasLimit,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendEtherWithSignature(recipients, signature, deadline, false, etherTransferGasLimit);
}
function multisendEthPersonalSignatureGasLimit(
Recipient[] calldata recipients,
uint256 etherTransferGasLimit,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendEtherWithSignature(recipients, signature, deadline, true, etherTransferGasLimit);
}
function multisendEthContractSignatureGasLimit(
Recipient[] calldata recipients,
uint256 etherTransferGasLimit,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
return _multisendEther(recipients, payable(signer), etherTransferGasLimit);
}
function multisendToken(IERC20 token, Recipient[] calldata recipients, uint256 total, address payable referral)
external
payable
returns (uint256 gasLeft)
{
_chargeFee(referral);
token.safeTransferFrom(msg.sender, address(this), total);
return _multisendToken(token, recipients, total, msg.sender);
}
function multisendTokenWithSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendTokenWithSignature(token, recipients, total, referral, signature, deadline, false);
}
function multisendTokenWithPersonalSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendTokenWithSignature(token, recipients, total, referral, signature, deadline, true);
}
function multisendTokenWithContractSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
_chargeFee(referral);
token.safeTransferFrom(signer, address(this), total);
return _multisendToken(token, recipients, total, signer);
}
function multisendTokenPermit2(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails
) external payable returns (uint256 gasLeft) {
return _multisendTokenPermit2(token, recipients, total, referral, permitSig, msg.sender, permitDetails);
}
function multisendTokenPermit2WithSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendTokenPermit2WithSignature(
token, recipients, total, referral, permitSig, permitDetails, signature, deadline, false
);
}
function multisendTokenPermit2WithPersonalSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendTokenPermit2WithSignature(
token, recipients, total, referral, permitSig, permitDetails, signature, deadline, true
);
}
function multisendTokenPermit2WithContractSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
return _multisendTokenPermit2(token, recipients, total, referral, permitSig, signer, permitDetails);
}
function multisendDeflationaryToken(IERC20 token, Recipient[] calldata recipients, address payable referral)
external
payable
returns (uint256 gasLeft)
{
_chargeFee(referral);
return _multisendDeflationaryToken(token, recipients, msg.sender);
}
function multisendDeflationaryTokenWithSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendDeflationaryTokenWithSignature(token, recipients, referral, signature, deadline, false);
}
function multisendDeflationaryTokenWithPersonalSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendDeflationaryTokenWithSignature(token, recipients, referral, signature, deadline, true);
}
function multisendDeflationaryTokenWithContractSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "the signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
_chargeFee(referral);
return _multisendDeflationaryToken(token, recipients, signer);
}
function multisendDeflationaryTokenPermit2(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails
) external payable returns (uint256 gasLeft) {
return _multisendDeflationaryTokenPermit2(token, recipients, referral, permitDetails, permitSig, msg.sender);
}
function multisendDeflationaryTokenPermit2WithSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendDeflationaryTokenPermit2WithSignature(
token, recipients, referral, permitDetails, permitSig, signature, deadline, false
);
}
function multisendDeflationaryTokenPermit2WithPersonalSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
return _multisendDeflationaryTokenPermit2WithSignature(
token, recipients, referral, permitDetails, permitSig, signature, deadline, true
);
}
function multisendDeflationaryTokenPermit2WithContractSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle calldata permitDetails,
address signer,
bytes calldata signature,
uint256 deadline
) external payable returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
checkContractApprove(signer, msg.sender, deadline, signature);
return _multisendDeflationaryTokenPermit2(token, recipients, referral, permitDetails, permitSig, signer);
}
// INTERNAL FUNCTIONS ---------------------------------------------
// ----------------------------------------------------------------
function _multisendEther(
Recipient[] calldata recipients,
address payable etherHolder,
uint256 etherTransferGasLimit
) internal returns (uint256 gasLeft) {
uint256 unspentEther = msg.value;
uint256 requiredTotal;
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i = i.unsafeInc()) {
uint256 amount = recipients[i].amount;
require(unspentEther >= amount, "Incorrect recipients amounts: sum more than total");
requiredTotal += amount;
bool success;
if (etherTransferGasLimit > 0) {
(success,) = recipients[i].addr.call{value: amount, gas: etherTransferGasLimit}("");
} else {
success = recipients[i].addr.send(amount);
}
if (success) {
unchecked {
unspentEther -= amount;
}
}
}
uint256 sentTotal = msg.value - unspentEther;
uint256 change = requiredTotal - sentTotal;
if (change > 0) {
require(change <= unspentEther, "Low msg.value");
unchecked {
unspentEther -= change;
}
etherHolder.sendValue(change);
}
if (unspentEther > 0) {
_sendBeneficiaryFee(unspentEther);
}
emit Multisent(sentTotal, IERC20(ETH_ADDRESS));
return gasleft();
}
function _multisendEtherWithSignature(
Recipient[] calldata recipients,
bytes calldata signature,
uint256 deadline,
bool isPersonalSignature,
uint256 etherTransferGasLimit
) internal returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
address etherHolder = isPersonalSignature
? getPersonalApprover(msg.sender, deadline, signature)
: getApprover(msg.sender, deadline, signature);
return _multisendEther(recipients, payable(etherHolder), etherTransferGasLimit);
}
function _multisendToken(IERC20 token, Recipient[] calldata recipients, uint256 total, address tokenHolder)
internal
returns (uint256 gasLeft)
{
require(recipients.length > 0, "No recipients sent");
uint256 unspentToken = total;
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i = i.unsafeInc()) {
uint256 amount = recipients[i].amount;
require(unspentToken >= amount, "Incorrect recipients amounts: sum more than total");
bool success = token.lowGasTransfer(recipients[i].addr, amount);
if (success) {
unchecked {
unspentToken -= amount;
}
}
}
if (unspentToken > 0) {
token.safeTransfer(tokenHolder, unspentToken);
}
emit Multisent(total - unspentToken, token);
return gasleft();
}
function _multisendTokenWithSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata signature,
uint256 deadline,
bool isPersonalSignature
) internal returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
address tokenHolder = isPersonalSignature
? getPersonalApprover(msg.sender, deadline, signature)
: getApprover(msg.sender, deadline, signature);
_chargeFee(referral);
token.safeTransferFrom(tokenHolder, address(this), total);
return _multisendToken(token, recipients, total, tokenHolder);
}
function _multisendTokenPermit2(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
address signer,
IPermit2.PermitSingle memory permitDetails
) internal returns (uint256 gasLeft) {
require(address(permit2) != address(0), "No permit2 in this chain");
_chargeFee(referral);
if (permitSig.length != 0) {
permit2.permit(signer, permitDetails, permitSig);
}
permit2.transferFrom(signer, address(this), uint160(total), address(token));
return _multisendToken(IERC20(token), recipients, total, signer);
}
function _multisendTokenPermit2WithSignature(
IERC20 token,
Recipient[] calldata recipients,
uint256 total,
address payable referral,
bytes calldata permitSig,
IPermit2.PermitSingle memory permitDetails,
bytes calldata signature,
uint256 deadline,
bool isPersonalSignature
) internal returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
address tokenHolder = isPersonalSignature
? getPersonalApprover(msg.sender, deadline, signature)
: getApprover(msg.sender, deadline, signature);
return _multisendTokenPermit2(token, recipients, total, referral, permitSig, tokenHolder, permitDetails);
}
function _multisendDeflationaryToken(IERC20 token, Recipient[] calldata recipients, address tokenHolder)
internal
returns (uint256 gasLeft)
{
require(recipients.length > 0, "No recipients sent");
require(address(token).isContract(), "Token address empty code");
uint256 total;
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i = i.unsafeInc()) {
uint256 amount = recipients[i].amount;
bool success = token.lowGasTransferFrom(tokenHolder, recipients[i].addr, amount);
if (success) {
unchecked {
total += amount;
}
}
}
emit Multisent(total, token);
return gasleft();
}
function _multisendDeflationaryTokenWithSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
bytes calldata signature,
uint256 deadline,
bool isPersonalSignature
) internal returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "the signature has expired");
address tokenHolder = isPersonalSignature
? getPersonalApprover(msg.sender, deadline, signature)
: getApprover(msg.sender, deadline, signature);
_chargeFee(referral);
return _multisendDeflationaryToken(token, recipients, tokenHolder);
}
function _multisendDeflationaryTokenPermit2(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata signature,
address signer
) internal returns (uint256 gasLeft) {
require(address(permit2) != address(0), "No permit2 in this chain");
require(recipients.length > 0, "No recipients sent");
require(address(token).isContract(), "Token address empty code");
_chargeFee(referral);
if (signature.length != 0) {
permit2.permit(signer, permitDetails, signature);
}
uint256 total;
for (uint256 i = 0; i < recipients.length; i = i.unsafeInc()) {
try permit2.transferFrom(signer, recipients[i].addr, uint160(recipients[i].amount), address(token)) {
unchecked {
total += recipients[i].amount;
}
} catch {}
}
emit Multisent(total, token);
return gasleft();
}
function _multisendDeflationaryTokenPermit2WithSignature(
IERC20 token,
Recipient[] calldata recipients,
address payable referral,
IPermit2.PermitSingle calldata permitDetails,
bytes calldata permitSig,
bytes calldata signature,
uint256 deadline,
bool isPersonalSignature
) internal returns (uint256 gasLeft) {
require(deadline >= block.timestamp, "The signature has expired");
address tokenHolder = isPersonalSignature
? getPersonalApprover(msg.sender, deadline, signature)
: getApprover(msg.sender, deadline, signature);
return _multisendDeflationaryTokenPermit2(token, recipients, referral, permitDetails, permitSig, tokenHolder);
}
function _chargeFee(address payable referral) internal override {
super._chargeFee(referral);
}
function _permit2() internal view virtual override returns (IPermit2) {
return permit2;
}
function tokenFallback(address _from, uint256 _value, bytes memory _data) external {}
fallback() external payable {
if (msg.value > 0) {
_sendBeneficiaryFee(msg.value);
}
}
receive() external payable {
if (msg.value > 0) {
_sendBeneficiaryFee(msg.value);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../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 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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "../FeeChargeable.sol";
import "../interfaces/IPermit2.sol";
import "../libraries/SafeTransferLib.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
abstract contract ValidationSender is FeeChargeable {
using SafeERC20 for IERC20;
using SafeTransferLib for IERC20;
struct Recipient {
address payable addr;
uint256 amount;
}
function _permit2() internal view virtual returns (IPermit2);
function validateEther(Recipient[] calldata recipients)
external
payable
returns (uint256 gasLeft, Recipient[] memory badAddresses)
{
badAddresses = new Recipient[](recipients.length);
uint256 total = msg.value;
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
bool success = recipients[i].addr.send(recipients[i].amount);
if (!success) {
badAddresses[i] = recipients[i];
} else {
total -= recipients[i].amount;
}
}
if (total > 0) {
_sendBeneficiaryFee(total);
}
gasLeft = gasleft();
}
function validateEtherGasLimit(Recipient[] calldata recipients, uint256 etherTransferGasLimit)
external
payable
returns (uint256 gasLeft, Recipient[] memory badAddresses)
{
badAddresses = new Recipient[](recipients.length);
uint256 total = msg.value;
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
(bool success,) = recipients[i].addr.call{value: recipients[i].amount, gas: etherTransferGasLimit}("");
if (!success) {
badAddresses[i] = recipients[i];
} else {
total -= recipients[i].amount;
}
}
if (total > 0) {
_sendBeneficiaryFee(total);
}
gasLeft = gasleft();
}
function validateToken(IERC20 token, uint256 total, Recipient[] calldata recipients)
external
payable
returns (bool isDeflationary, uint256 gasLeft, Recipient[] memory badAddresses)
{
_chargeFee(payable(address(0)));
badAddresses = new Recipient[](recipients.length);
uint256 balanceDiff = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), total);
balanceDiff = token.balanceOf(address(this)) - balanceDiff;
if (balanceDiff != total) {
// isDeflationary
return (true, 0, badAddresses);
}
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
balanceDiff = token.balanceOf(recipients[i].addr);
bool success = token.lowGasTransfer(recipients[i].addr, recipients[i].amount);
balanceDiff = success ? token.balanceOf(recipients[i].addr) - balanceDiff : 0;
if (success && balanceDiff != recipients[i].amount) {
// isDeflationary
return (true, 0, badAddresses);
}
if (!success) {
badAddresses[i] = recipients[i];
}
}
gasLeft = gasleft();
}
function validateDeflationaryToken(IERC20 token, Recipient[] calldata recipients)
external
payable
returns (uint256 gasLeft, Recipient[] memory badAddresses)
{
_chargeFee(payable(address(0)));
badAddresses = new Recipient[](recipients.length);
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
bool success = token.lowGasTransferFrom(msg.sender, recipients[i].addr, recipients[i].amount);
if (!success) {
badAddresses[i] = recipients[i];
}
}
gasLeft = gasleft();
}
function validateTokenPermit2(
IERC20 token,
uint160 total,
Recipient[] calldata recipients,
bytes calldata signature,
IPermit2.PermitSingle calldata permitDetails
) external payable returns (bool isDeflationary, uint256 gasLeft, Recipient[] memory badAddresses) {
_chargeFee(payable(address(0)));
badAddresses = new Recipient[](recipients.length);
uint256 balanceDiff = token.balanceOf(address(this));
if (signature.length != 0) {
_permit2().permit(msg.sender, permitDetails, signature);
}
_permit2().transferFrom(msg.sender, address(this), total, address(token));
balanceDiff = token.balanceOf(address(this)) - balanceDiff;
if (balanceDiff != total) {
// isDeflationary
return (true, 0, badAddresses);
}
for (uint256 i = 0; i < recipients.length; i++) {
balanceDiff = token.balanceOf(recipients[i].addr);
bool success = token.lowGasTransfer(recipients[i].addr, recipients[i].amount);
balanceDiff = success ? token.balanceOf(recipients[i].addr) - balanceDiff : 0;
if (success && balanceDiff != recipients[i].amount) {
// isDeflationary
return (true, 0, badAddresses);
}
if (!success) {
badAddresses[i] = recipients[i];
}
}
gasLeft = gasleft();
}
function validateDeflationaryTokenPermit2(
IERC20 token,
Recipient[] calldata recipients,
bytes calldata signature,
IPermit2.PermitSingle calldata permitDetails
) external payable returns (uint256 gasLeft, Recipient[] memory badAddresses) {
_chargeFee(payable(address(0)));
badAddresses = new Recipient[](recipients.length);
if (signature.length != 0) {
_permit2().permit(msg.sender, permitDetails, signature);
}
uint256 length = recipients.length;
for (uint256 i = 0; i < length; i++) {
try _permit2().transferFrom(msg.sender, recipients[i].addr, uint160(recipients[i].amount), address(token)) {}
catch {
badAddresses[i] = recipients[i];
}
}
gasLeft = gasleft();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../interfaces/ISignatureValidator.sol";
abstract contract Messages {
struct Authorization {
address authorizedSigner;
uint256 expiration;
}
/**
* Domain separator encoding per EIP 712.
* keccak256(
* "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"
* )
*/
bytes32 public constant EIP712_DOMAIN_TYPEHASH = 0xd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472;
/**
* Validator struct type encoding per EIP 712
* keccak256(
* "Authorization(address authorizedSigner,uint256 expiration)"
* )
*/
bytes32 private constant AUTHORIZATION_TYPEHASH = 0xe419504a688f0e6ea59c2708f49b2bbc10a2da71770bd6e1b324e39c73e7dc25;
/**
* Domain separator per EIP 712
*/
// bytes32 public DOMAIN_SEPARATOR;
function DOMAIN_SEPARATOR() public view returns (bytes32) {
bytes32 salt = 0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558;
return keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH, keccak256("Multisender"), keccak256("3.0"), block.chainid, address(this), salt
)
);
}
/**
* @notice Calculates authorizationHash according to EIP 712.
* @param _authorizedSigner address of trustee
* @param _expiration expiration date
* @return bytes32 EIP 712 hash of _authorization.
*/
function hash(address _authorizedSigner, uint256 _expiration) public pure returns (bytes32) {
return keccak256(abi.encode(AUTHORIZATION_TYPEHASH, _authorizedSigner, _expiration));
}
function getApprover(address spender, uint256 deadline, bytes memory signature) public view returns (address) {
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), hash(spender, deadline)));
(address signer,) = ECDSA.tryRecover(digest, signature);
require(signer != address(0), "the signature is invalid");
return signer;
}
function getPersonalApprover(address spender, uint256 deadline, bytes memory signature)
public
view
returns (address)
{
bytes32 digest = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n", "96", abi.encode(block.chainid, spender, deadline))
);
(address signer,) = ECDSA.tryRecover(digest, signature);
require(signer != address(0), "the signature is invalid");
return signer;
}
function checkContractApprove(address signer, address spender, uint256 deadline, bytes memory signature)
public
view
returns (bool)
{
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), hash(spender, deadline)));
bytes4 value = ISignatureValidator(signer).isValidSignature(digest, signature);
require(
value == EIP1271_MAGIC_VALUE || value == EIP1271_MAGIC_VALUE_SAFE, "Invalid contract signature provided"
);
return true;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library UnsafeMath {
function unsafeInc(uint256 x) internal pure returns (uint256) {
unchecked {
return x + 1;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @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.
*/
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].
*/
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
pragma solidity 0.8.19;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
abstract contract FeeChargeable {
using Address for address payable;
struct VipTier {
uint256 duration;
uint256 price;
}
uint256 public fee;
uint256 public referralFee;
address payable public beneficiary20;
address payable public beneficiary80;
VipTier[] public tiers;
mapping(address => uint256) public hasVipUntil;
event PurchaseVIP(address customer, uint256 tier);
// USERS METHODS --------------------------------------------------
// ----------------------------------------------------------------
function buyVip(uint256 tier) external payable {
require(msg.value >= tiers[tier].price, "Not enough ETH value for VIP status purchase");
_sendBeneficiaryFee(msg.value);
uint256 start = Math.max(hasVipUntil[msg.sender], block.timestamp);
hasVipUntil[msg.sender] = start + tiers[tier].duration;
emit PurchaseVIP(msg.sender, tier);
}
function currentFee(address customer) public view returns (uint256) {
if (hasVipUntil[customer] >= block.timestamp) {
return 0;
}
return fee;
}
function getAllVipTiers() external view returns (VipTier[] memory) {
return tiers;
}
function _sendBeneficiaryFee(uint256 _fee) internal {
uint256 fee20 = (_fee * 20) / 100;
// no ReentrancyGuard because trusted recipients
beneficiary20.sendValue(fee20);
beneficiary80.sendValue(_fee - fee20);
}
function _chargeFee(address payable referral) internal virtual {
uint256 value = msg.value;
if (value > 0) {
uint256 refFee;
if (referral != address(0)) {
refFee = Math.min(referralFee, value);
// no check of success by design
bool success = referral.send(refFee);
if (!success) {
refFee = 0;
}
}
if (value > refFee) {
_sendBeneficiaryFee(value - refFee);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Minimal Permit2 interface, derived from
// https://github.com/Uniswap/permit2/blob/main/src/interfaces/ISignatureTransfer.sol
interface IPermit2 {
// The permit data for a token
struct PermitDetails {
// ERC20 token address
address token;
// the maximum amount allowed to spend
uint160 amount;
// timestamp at which a spender's token allowances become invalid
uint48 expiration;
// an incrementing value indexed per owner,token,and spender for each signature
uint48 nonce;
}
// The permit message signed for a single token allowance
struct PermitSingle {
// the permit data for a single token alownce
PermitDetails details;
// address permissioned on the allowed tokens
address spender;
// deadline on the permit signature
uint256 sigDeadline;
}
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
function allowance(address owner, address token, address spender) external returns (uint160, uint48, uint48);
function transferFrom(address from, address to, uint160 amount, address token) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
library SafeTransferLib {
function lowGasTransferFrom(IERC20 token, address from, address to, uint256 amount)
internal
returns (bool success)
{
assembly {
// We'll write our calldata to this slot below, but restore it later.
let memPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(4, from) // Append the "from" argument.
mstore(36, to) // Append the "to" argument.
mstore(68, amount) // Append the "amount" argument.
success :=
and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because that's the total length of our calldata (4 + 32 * 3)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), token, 0, 0, 100, 0, 32)
)
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, memPointer) // Restore the memPointer.
}
}
function lowGasTransfer(IERC20 token, address to, uint256 amount) internal returns (bool success) {
assembly {
// We'll write our calldata to this slot below, but restore it later.
let memPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(0, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(4, to) // Append the "to" argument.
mstore(36, amount) // Append the "amount" argument.
success :=
and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because that's the total length of our calldata (4 + 32 * 2)
// Counterintuitively, this call() must be positioned after the or() in the
// surrounding and() because and() evaluates its arguments from right to left.
call(gas(), token, 0, 0, 68, 0, 32)
)
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, memPointer) // Restore the memPointer.
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @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,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode 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 {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]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
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);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode 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 {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
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]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
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.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// 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);
}
// 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);
}
return (signer, RecoverError.NoError);
}
/**
* @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) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
// bytes4(keccak256("isValidSignature(bytes32,bytes)")
bytes4 constant EIP1271_MAGIC_VALUE = 0x1626ba7e;
// bytes4(keccak256("isValidSignature(bytes,bytes)")
// https://github.com/safe-global/safe-core-sdk/blob/4b8db6d633cd208740592c59e0959c14d56e41e9/packages/protocol-kit/contracts/safe_V1_2_0/interfaces/ISignatureValidator.sol#L5
bytes4 constant EIP1271_MAGIC_VALUE_SAFE = 0x20c13b0b;
abstract contract ISignatureValidator {
/**
* @notice EIP1271 method to validate a signature.
* @param _hash Hash of the data signed on the behalf of address(this).
* @param _signature Signature byte array associated with _data.
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes32 _hash, bytes memory _signature) external view virtual returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @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), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(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) {
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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
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 keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @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);
}
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@solmate/=lib/solmate/",
"ds-test/=lib/solmate/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_referralFee","type":"uint256"},{"internalType":"address payable","name":"_beneficiary20","type":"address"},{"internalType":"address payable","name":"_beneficiary80","type":"address"},{"components":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"internalType":"struct FeeChargeable.VipTier[]","name":"_tiers","type":"tuple[]"},{"internalType":"address","name":"_permit2Addr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"},{"indexed":false,"internalType":"contract IERC20","name":"tokenAddress","type":"address"}],"name":"Multisent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"permit2","type":"address"}],"name":"Permit2Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"customer","type":"address"},{"indexed":false,"internalType":"uint256","name":"tier","type":"uint256"}],"name":"PurchaseVIP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"newMode","type":"bool"}],"name":"ReferralModeUpdated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beneficiary20","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beneficiary80","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"}],"name":"buyVip","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"checkContractApprove","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"customer","type":"address"}],"name":"currentFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAllVipTiers","outputs":[{"components":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"internalType":"struct FeeChargeable.VipTier[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"getApprover","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"getPersonalApprover","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasVipUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_authorizedSigner","type":"address"},{"internalType":"uint256","name":"_expiration","type":"uint256"}],"name":"hash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"}],"name":"multisendDeflationaryToken","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"}],"name":"multisendDeflationaryTokenPermit2","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenPermit2WithContractSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenPermit2WithPersonalSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenPermit2WithSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenWithContractSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenWithPersonalSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendDeflationaryTokenWithSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"etherTransferGasLimit","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEthContractSignatureGasLimit","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"etherTransferGasLimit","type":"uint256"}],"name":"multisendEthGasLimit","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"etherTransferGasLimit","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEthPersonalSignatureGasLimit","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"etherTransferGasLimit","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEthSignatureGasLimit","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"}],"name":"multisendEther","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEtherWithContractSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEtherWithPersonalSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendEtherWithSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"}],"name":"multisendToken","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"}],"name":"multisendTokenPermit2","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenPermit2WithContractSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenPermit2WithPersonalSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"permitSig","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenPermit2WithSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenWithContractSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenWithPersonalSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"address payable","name":"referral","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"multisendTokenWithSignature","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"permit2","outputs":[{"internalType":"contract IPermit2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tiers","outputs":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"tokenFallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"}],"name":"validateDeflationaryToken","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"}],"name":"validateDeflationaryTokenPermit2","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"}],"name":"validateEther","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"uint256","name":"etherTransferGasLimit","type":"uint256"}],"name":"validateEtherGasLimit","outputs":[{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"total","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"}],"name":"validateToken","outputs":[{"internalType":"bool","name":"isDeflationary","type":"bool"},{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint160","name":"total","type":"uint160"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"recipients","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"},{"internalType":"uint48","name":"expiration","type":"uint48"},{"internalType":"uint48","name":"nonce","type":"uint48"}],"internalType":"struct IPermit2.PermitDetails","name":"details","type":"tuple"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"sigDeadline","type":"uint256"}],"internalType":"struct IPermit2.PermitSingle","name":"permitDetails","type":"tuple"}],"name":"validateTokenPermit2","outputs":[{"internalType":"bool","name":"isDeflationary","type":"bool"},{"internalType":"uint256","name":"gasLeft","type":"uint256"},{"components":[{"internalType":"address payable","name":"addr","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct ValidationSender.Recipient[]","name":"badAddresses","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162004e6a38038062004e6a8339810160408190526200003491620003d3565b848610156200009e5760405162461bcd60e51b815260206004820152602b60248201527f526566657272616c206665652063616e2774206265206d6f7265207468616e2060448201526a736572766963652066656560a81b60648201526084015b60405180910390fd5b600185905560008690556001600160a01b0384166200010c5760405162461bcd60e51b815260206004820152602360248201527f42656e656669636961727932302063616e2774206265207a65726f206164647260448201526265737360e81b606482015260840162000095565b600280546001600160a01b0319166001600160a01b03868116919091179091558316620001885760405162461bcd60e51b815260206004820152602360248201527f42656e656669636961727938302063616e2774206265207a65726f206164647260448201526265737360e81b606482015260840162000095565b600380546001600160a01b0319166001600160a01b03851617905560005b82518160ff161015620002fb57828160ff1681518110620001cb57620001cb620004fe565b602002602001015160200151600003620002285760405162461bcd60e51b815260206004820152601360248201527f50726963652063616e2774206265207a65726f00000000000000000000000000604482015260640162000095565b828160ff1681518110620002405762000240620004fe565b6020026020010151600001516000036200029d5760405162461bcd60e51b815260206004820152601660248201527f4475726174696f6e2063616e2774206265207a65726f00000000000000000000604482015260640162000095565b6004838260ff1681518110620002b757620002b7620004fe565b602090810291909101810151825460018181018555600094855293839020825160029092020190815591015191015580620002f28162000514565b915050620001a6565b506001600160a01b038116156200032857600680546001600160a01b0319166001600160a01b0383161790555b50505050505062000542565b6001600160a01b03811681146200034a57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156200038857620003886200034d565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620003b957620003b96200034d565b604052919050565b8051620003ce8162000334565b919050565b60008060008060008060c08789031215620003ed57600080fd5b8651955060208088015195506040808901516200040a8162000334565b60608a01519096506200041d8162000334565b60808a01519095506001600160401b03808211156200043b57600080fd5b818b0191508b601f8301126200045057600080fd5b8151818111156200046557620004656200034d565b62000475858260051b016200038e565b818152858101925060069190911b83018501908d8211156200049657600080fd5b928501925b81841015620004db5784848f031215620004b55760008081fd5b620004bf62000363565b845181528685015187820152835292840192918501916200049b565b809750505050505050620004f260a08801620003c1565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b600060ff821660ff81036200053957634e487b7160e01b600052601160045260246000fd5b60010192915050565b61491880620005526000396000f3fe6080604052600436106102975760003560e01c80636abb9a461161015a578063a734f06e116100c1578063c7977be71161007a578063c7977be7146106fa578063d4fb0a871461072e578063d7df0ebf14610741578063ddca3f4314610754578063f6bbf0a21461076a578063fe9017581461077d576102ad565b8063a734f06e14610678578063a838e34c1461068e578063b23a1088146106a1578063b766d62c146106b4578063c051eb84146106c7578063c0ee0b8a146106da576102ad565b806384ae2bc61161011357806384ae2bc6146105e757806384b14f96146105fd5780638e031cb61461061d578063926988b4146106305780639a2631ad146106435780639da9eaa514610656576102ad565b80636abb9a461461055b578063708256b41461056e57806373922184146105815780637b6423b9146105945780637e9505c0146105b457806380b2740d146105c7576102ad565b80632fba23bf116101fe57806356e89613116101b757806356e89613146104cf578063574a5e12146104e2578063591552da146104f55780635d40019b1461051557806361bcaabe146105285780636857c1ce1461053b576102ad565b80632fba23bf146104345780633644e515146104475780633e52c01c1461045c57806343933aa01461046f57806346d5bea11461049c57806351208fb3146104af576102ad565b806312261ee71161025057806312261ee71461038f5780631b641a7d146103c75780631e292472146103da57806323950ddd146103ed57806329d822c2146104005780632defb6fd14610421576102ad565b806301cea205146102bc578063039af9eb146102f157806306b16c7f146103265780630caeb05c146103475780630f0b726c1461036957806310d56a2c1461037c576102ad565b366102ad5734156102ab576102ab34610790565b005b34156102ab576102ab34610790565b3480156102c857600080fd5b506102dc6102d73660046134ca565b6107e5565b60405190151581526020015b60405180910390f35b3480156102fd57600080fd5b5061031161030c366004613535565b61093e565b604080519283526020830191909152016102e8565b610339610334366004613592565b61096c565b6040519081526020016102e8565b61035a610355366004613636565b61097a565b6040516102e89392919061372c565b61033961037736600461374d565b610e3f565b61035a61038a3660046137c0565b610e5b565b34801561039b57600080fd5b506006546103af906001600160a01b031681565b6040516001600160a01b0390911681526020016102e8565b6103396103d536600461381b565b61124e565b6103396103e8366004613895565b61126c565b6103396103fb36600461397e565b6112a1565b61041361040e366004613a62565b6112c6565b6040516102e8929190613ab6565b61041361042f366004613acf565b611411565b610339610442366004613b10565b611598565b34801561045357600080fd5b506103396115ab565b61033961046a366004613b10565b611679565b34801561047b57600080fd5b5061033961048a366004613baf565b60056020526000908152604090205481565b6103396104aa366004613bcc565b61168c565b3480156104bb57600080fd5b506103396104ca366004613c77565b611701565b6103396104dd366004613acf565b611768565b6103396104f0366004613ca3565b61177e565b34801561050157600080fd5b50610339610510366004613baf565b6117ef565b610339610523366004613cfd565b61181e565b610339610536366004613d64565b61183e565b34801561054757600080fd5b506103af610556366004613e16565b6118f1565b6102ab610569366004613535565b6119b1565b61033961057c366004613e6e565b611ae0565b61033961058f366004613f73565b611b77565b3480156105a057600080fd5b506103af6105af366004613e16565b611bf4565b6103396105c2366004613fff565b611c2c565b3480156105d357600080fd5b506003546103af906001600160a01b031681565b3480156105f357600080fd5b5061033960015481565b34801561060957600080fd5b506002546103af906001600160a01b031681565b61033961062b36600461406a565b611c40565b61033961063e366004613895565b611c6d565b61033961065136600461397e565b611c92565b34801561066257600080fd5b5061066b611ca8565b6040516102e891906140dd565b34801561068457600080fd5b506103af61beef81565b61041361069c366004613592565b611d1b565b6103396106af366004613fff565b611ed0565b6103396106c236600461374d565b611ee4565b6103396106d536600461412c565b611ef7565b3480156106e657600080fd5b506102ab6106f5366004613e16565b505050565b34801561070657600080fd5b506103397fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b61033961073c3660046141e8565b611f95565b61033961074f366004614244565b611fa7565b34801561076057600080fd5b5061033960005481565b6104136107783660046142f6565b611fc3565b61033961078b3660046141e8565b6121b9565b6000606461079f83601461439f565b6107a991906143b6565b6002549091506107c2906001600160a01b0316826121cb565b6107e16107cf82846143d8565b6003546001600160a01b0316906121cb565b5050565b6000806107f06115ab565b6107fa8686611701565b60405161190160f01b6020820152602281019290925260428201526062016040516020818303038152906040528051906020012090506000866001600160a01b0316631626ba7e83866040518363ffffffff1660e01b815260040161086092919061443b565b602060405180830381865afa15801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190614454565b90506001600160e01b03198116630b135d3f60e11b14806108d257506001600160e01b031981166320c13b0b60e01b145b61092f5760405162461bcd60e51b815260206004820152602360248201527f496e76616c696420636f6e7472616374207369676e61747572652070726f766960448201526219195960ea1b60648201526084015b60405180910390fd5b6001925050505b949350505050565b6004818154811061094e57600080fd5b60009182526020909120600290910201805460019091015490915082565b6000610936848433856122e4565b600080606061098960006124f4565b866001600160401b038111156109a1576109a1613400565b6040519080825280602002602001820160405280156109e657816020015b60408051808201909152600080825260208201528152602001906001900390816109bf5790505b506040516370a0823160e01b81523060048201529091506000906001600160a01b038c16906370a0823190602401602060405180830381865afa158015610a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a55919061447e565b90508515610ac6576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b57090610a9390339089908c908c906004016144d6565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b505050505b6006546001600160a01b03166001600160a01b03166336c7851633308d8f6040518563ffffffff1660e01b8152600401610b03949392919061457a565b600060405180830381600087803b158015610b1d57600080fd5b505af1158015610b31573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528392506001600160a01b038e1691506370a0823190602401602060405180830381865afa158015610b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9f919061447e565b610ba991906143d8565b9050896001600160a01b03168114610bc957600160009350935050610e32565b60005b88811015610e2c578b6001600160a01b03166370a082318b8b84818110610bf557610bf56145a5565b610c0b9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c73919061447e565b91506000610cd78b8b84818110610c8c57610c8c6145a5565b610ca29260206040909202019081019150613baf565b8c8c85818110610cb457610cb46145a5565b905060400201602001358f6001600160a01b03166125009092919063ffffffff16565b905080610ce5576000610d8f565b828d6001600160a01b03166370a082318d8d86818110610d0757610d076145a5565b610d1d9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d85919061447e565b610d8f91906143d8565b9250808015610db957508a8a83818110610dab57610dab6145a5565b905060400201602001358314155b15610dce576001600095509550505050610e32565b80610e19578a8a83818110610de557610de56145a5565b905060400201803603810190610dfb91906145bb565b848381518110610e0d57610e0d6145a5565b60200260200101819052505b5080610e2481614612565b915050610bcc565b505a9250505b9750975097945050505050565b6000610e518686868686600080612546565b9695505050505050565b6000806060610e6a60006124f4565b836001600160401b03811115610e8257610e82613400565b604051908082528060200260200182016040528015610ec757816020015b6040805180820190915260008082526020820152815260200190600190039081610ea05790505b506040516370a0823160e01b81523060048201529091506000906001600160a01b038916906370a0823190602401602060405180830381865afa158015610f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f36919061447e565b9050610f4d6001600160a01b03891633308a612604565b6040516370a0823160e01b815230600482015281906001600160a01b038a16906370a0823190602401602060405180830381865afa158015610f93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb7919061447e565b610fc191906143d8565b9050868114610fd857600160009350935050611244565b8460005b8181101561123d57896001600160a01b03166370a08231898984818110611005576110056145a5565b61101b9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561105f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611083919061447e565b925060006110e789898481811061109c5761109c6145a5565b6110b29260206040909202019081019150613baf565b8a8a858181106110c4576110c46145a5565b905060400201602001358d6001600160a01b03166125009092919063ffffffff16565b9050806110f557600061119f565b838b6001600160a01b03166370a082318b8b86818110611117576111176145a5565b61112d9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611171573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611195919061447e565b61119f91906143d8565b93508080156111c957508888838181106111bb576111bb6145a5565b905060400201602001358414155b156111df57600160009650965050505050611244565b8061122a578888838181106111f6576111f66145a5565b90506040020180360381019061120c91906145bb565b85838151811061121e5761121e6145a5565b60200260200101819052505b508061123581614612565b915050610fdc565b505a935050505b9450945094915050565b60006112608888888886898933612675565b98975050505050505050565b60006112918c8c8c8c8c8c8c611287368e90038e018e61462b565b8c8c8c60006128cc565b9c9b505050505050505050505050565b60006112b78b8b8b8b898c8c8b8b8b60006129a1565b9b9a5050505050505050505050565b600060606112d460006124f4565b826001600160401b038111156112ec576112ec613400565b60405190808252806020026020018201604052801561133157816020015b604080518082019091526000808252602082015281526020019060019003908161130a5790505b5090508260005b818110156114045760006113a433888885818110611358576113586145a5565b61136e9260206040909202019081019150613baf565b898986818110611380576113806145a5565b905060400201602001358b6001600160a01b0316612a63909392919063ffffffff16565b9050806113f1578686838181106113bd576113bd6145a5565b9050604002018036038101906113d391906145bb565b8483815181106113e5576113e56145a5565b60200260200101819052505b50806113fc81614612565b915050611338565b505a925050935093915050565b60006060826001600160401b0381111561142d5761142d613400565b60405190808252806020026020018201604052801561147257816020015b604080518082019091526000808252602082015281526020019060019003908161144b5790505b509050348360005b8181101561157c576000878783818110611496576114966145a5565b6114ac9260206040909202019081019150613baf565b6001600160a01b03166108fc8989858181106114ca576114ca6145a5565b905060400201602001359081150290604051600060405180830381858888f1935050505090508061153f57878783818110611507576115076145a5565b90506040020180360381019061151d91906145bb565b85838151811061152f5761152f6145a5565b6020026020010181905250611569565b878783818110611551576115516145a5565b905060400201602001358461156691906143d8565b93505b508061157481614612565b91505061147a565b50811561158c5761158c82610790565b5a935050509250929050565b6000611260888888888888886001612aae565b604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647260208201527f433b68d57964cf3844fb37130abb6d9de19030f03725ce749ad05453b740b157918101919091527fbe39c2702c76475cb6c2596f1e97ed8d703798e477af2efa214cbcda3006f17a60608201524660808201523060a08201527ff2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a55860c0820181905260009160e0016040516020818303038152906040528051906020012091505090565b6000611260888888888888886000612aae565b6000428210156116ae5760405162461bcd60e51b8152600401610926906146e5565b6116f085338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b506112918c8c8c8c8a8d8d8c612675565b604080517fe419504a688f0e6ea59c2708f49b2bbc10a2da71770bd6e1b324e39c73e7dc2560208201526001600160a01b03841691810191909152606081018290526000906080016040516020818303038152906040528051906020012090505b92915050565b600061177783833360006122e4565b9392505050565b6000428210156117a05760405162461bcd60e51b8152600401610926906146e5565b6117e285338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611260888887896122e4565b6001600160a01b038116600090815260056020526040812054421161181657506000919050565b505060005490565b6000611829826124f4565b61183585858533612b9d565b95945050505050565b60004282101561188c5760405162461bcd60e51b81526020600482015260196024820152781d1a19481cda59db985d1d5c99481a185cc8195e1c1a5c9959603a1b6044820152606401610926565b6118ce85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b506118d8866124f4565b6118e489898988612b9d565b9998505050505050505050565b604080514660208201526001600160a01b03851681830152606080820185905282518083039091018152608082019092526000918291611934919060a00161471c565b60405160208183030381529060405280519060200120905060006119588285612cce565b5090506001600160a01b0381166118355760405162461bcd60e51b815260206004820152601860248201527f746865207369676e617475726520697320696e76616c696400000000000000006044820152606401610926565b600481815481106119c4576119c46145a5565b906000526020600020906002020160010154341015611a3a5760405162461bcd60e51b815260206004820152602c60248201527f4e6f7420656e6f756768204554482076616c756520666f72205649502073746160448201526b74757320707572636861736560a01b6064820152608401610926565b611a4334610790565b33600090815260056020526040812054611a5d9042612d13565b905060048281548110611a7257611a726145a5565b90600052602060002090600202016000015481611a8f919061476c565b336000818152600560209081526040918290209390935580519182529181018490527fee4c6b99bbc510f4eaae1269a7e65d6bf4a6dcf0043ea60e68ada838afcdc552910160405180910390a15050565b600042821015611b025760405162461bcd60e51b8152600401610926906146e5565b611b4485338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611b668d8d8d8d8d8d8d8c8e803603810190611b61919061462b565b612d29565b9d9c50505050505050505050505050565b600042821015611b995760405162461bcd60e51b8152600401610926906146e5565b611bdb85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611be987878760006122e4565b979650505050505050565b600080611bff6115ab565b611c098686611701565b60405161190160f01b602082015260228101929092526042820152606201611934565b60006118e489898989898989896001612e7d565b6000611c4b826124f4565b611c606001600160a01b038716333086612604565b610e518686868633612f56565b60006112918c8c8c8c8c8c8c611c88368e90038e018e61462b565b8c8c8c60016128cc565b60006112b78b8b8b8b898c8c8b8b8b60016129a1565b60606004805480602002602001604051908101604052809291908181526020016000905b82821015611d1257838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190611ccc565b50505050905090565b60006060836001600160401b03811115611d3757611d37613400565b604051908082528060200260200182016040528015611d7c57816020015b6040805180820190915260008082526020820152815260200190600190039081611d555790505b509050348460005b81811015611eb3576000888883818110611da057611da06145a5565b611db69260206040909202019081019150613baf565b6001600160a01b0316898984818110611dd157611dd16145a5565b905060400201602001358890604051600060405180830381858888f193505050503d8060008114611e1e576040519150601f19603f3d011682016040523d82523d6000602084013e611e23565b606091505b5050905080611e7657888883818110611e3e57611e3e6145a5565b905060400201803603810190611e5491906145bb565b858381518110611e6657611e666145a5565b6020026020010181905250611ea0565b888883818110611e8857611e886145a5565b9050604002016020013584611e9d91906143d8565b93505b5080611eab81614612565b915050611d84565b508115611ec357611ec382610790565b5a93505050935093915050565b60006118e489898989898989896000612e7d565b6000610e51868686868660016000612546565b600042821015611f195760405162461bcd60e51b8152600401610926906146e5565b611f5b85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611f65866124f4565b611f7a6001600160a01b038b1686308a612604565b611f878a8a8a8a89612f56565b9a9950505050505050505050565b6000611be9878786868660008b612546565b60006118e48989898989898933611b61368c90038c018c61462b565b60006060611fd160006124f4565b856001600160401b03811115611fe957611fe9613400565b60405190808252806020026020018201604052801561202e57816020015b60408051808201909152600080825260208201528152602001906001900390816120075790505b50905083156120a0576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061206d90339087908a908a906004016144d6565b600060405180830381600087803b15801561208757600080fd5b505af115801561209b573d6000803e3d6000fd5b505050505b8560005b818110156121a9576006546001600160a01b03166336c78516338b8b858181106120d0576120d06145a5565b6120e69260206040909202019081019150613baf565b8c8c868181106120f8576120f86145a5565b905060400201602001358e6040518563ffffffff1660e01b8152600401612122949392919061457a565b600060405180830381600087803b15801561213c57600080fd5b505af192505050801561214d575060015b61219757888882818110612163576121636145a5565b90506040020180360381019061217991906145bb565b83828151811061218b5761218b6145a5565b60200260200101819052505b806121a181614612565b9150506120a4565b505a925050965096945050505050565b6000611be9878786868660018b612546565b8047101561221b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610926565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612268576040519150601f19603f3d011682016040523d82523d6000602084013e61226d565b606091505b50509050806106f55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610926565b6000348185815b81811015612433576000898983818110612307576123076145a5565b905060400201602001359050808510156123335760405162461bcd60e51b81526004016109269061477f565b61233d818561476c565b9350600087156123cc578a8a84818110612359576123596145a5565b61236f9260206040909202019081019150613baf565b6001600160a01b0316828990604051600060405180830381858888f193505050503d80600081146123bc576040519150601f19603f3d011682016040523d82523d6000602084013e6123c1565b606091505b50508091505061241d565b8a8a848181106123de576123de6145a5565b6123f49260206040909202019081019150613baf565b6001600160a01b03166108fc839081150290604051600060405180830381858888f19450505050505b80156124295781860395505b50506001016122eb565b50600061244084346143d8565b9050600061244e82856143d8565b905080156124ae57848111156124965760405162461bcd60e51b815260206004820152600d60248201526c4c6f77206d73672e76616c756560981b6044820152606401610926565b93849003936124ae6001600160a01b038916826121cb565b84156124bd576124bd85610790565b6040805183815261beef60208201526000805160206148c3833981519152910160405180910390a15a9a9950505050505050505050565b6124fd81613078565b50565b600060405163a9059cbb60e01b6000528360045282602452602060006044600080895af13d15601f3d116001600051141617169150600060605280604052509392505050565b6000428410156125685760405162461bcd60e51b8152600401610926906146e5565b6000836125b5576125b0338689898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b6125f6565b6125f6338689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b90506118e4898983866122e4565b6040516001600160a01b038085166024830152831660448201526064810182905261266f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526130f0565b50505050565b6006546000906001600160a01b03166126cb5760405162461bcd60e51b81526020600482015260186024820152772737903832b936b4ba191034b7103a3434b99031b430b4b760411b6044820152606401610926565b866126e85760405162461bcd60e51b8152600401610926906147d0565b6001600160a01b0389163b61273a5760405162461bcd60e51b8152602060048201526018602482015277546f6b656e206164647265737320656d70747920636f646560401b6044820152606401610926565b612743866124f4565b82156127b2576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061277f9085908990899089906004016144d6565b600060405180830381600087803b15801561279957600080fd5b505af11580156127ad573d6000803e3d6000fd5b505050505b6000805b8881101561288d576006546001600160a01b03166336c78516858c8c858181106127e2576127e26145a5565b6127f89260206040909202019081019150613baf565b8d8d8681811061280a5761280a6145a5565b905060400201602001358f6040518563ffffffff1660e01b8152600401612834949392919061457a565b600060405180830381600087803b15801561284e57600080fd5b505af192505050801561285f575060015b1561288557898982818110612876576128766145a5565b90506040020160200135820191505b6001016127b6565b50604080518281526001600160a01b038c1660208201526000805160206148c3833981519152910160405180910390a15a9a9950505050505050505050565b6000428310156128ee5760405162461bcd60e51b8152600401610926906146e5565b60008261293b57612936338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b61297c565b61297c338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b905061298f8e8e8e8e8e8e8e888f612d29565b9e9d5050505050505050505050505050565b6000428310156129c35760405162461bcd60e51b8152600401610926906146e5565b600082612a1057612a0b338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612a51565b612a51338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050611b668d8d8d8d8d8d8d88612675565b60006040516323b872dd60e01b6000528460045283602452826044526020600060646000808a5af13d15601f3d11600160005114161716915060006060528060405250949350505050565b600042831015612afc5760405162461bcd60e51b81526020600482015260196024820152781d1a19481cda59db985d1d5c99481a185cc8195e1c1a5c9959603a1b6044820152606401610926565b600082612b4957612b44338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612b8a565b612b8a338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050612b95876124f4565b611f878a8a8a845b600082612bbc5760405162461bcd60e51b8152600401610926906147d0565b6001600160a01b0385163b612c0e5760405162461bcd60e51b8152602060048201526018602482015277546f6b656e206164647265737320656d70747920636f646560401b6044820152606401610926565b600083815b81811015612c92576000878783818110612c2f57612c2f6145a5565b9050604002016020013590506000612c7b878a8a86818110612c5357612c536145a5565b612c699260206040909202019081019150613baf565b6001600160a01b038d16919085612a63565b90508015612c8857938101935b5050600101612c13565b50604080518381526001600160a01b03891660208201526000805160206148c3833981519152910160405180910390a15a979650505050505050565b6000808251604103612d045760208301516040840151606085015160001a612cf8878285856131c5565b94509450505050612d0c565b506000905060025b9250929050565b6000818311612d225781611777565b5090919050565b6006546000906001600160a01b0316612d7f5760405162461bcd60e51b81526020600482015260186024820152772737903832b936b4ba191034b7103a3434b99031b430b4b760411b6044820152606401610926565b612d88866124f4565b8315612df7576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b57090612dc490869086908a908a906004016147fc565b600060405180830381600087803b158015612dde57600080fd5b505af1158015612df2573d6000803e3d6000fd5b505050505b600660009054906101000a90046001600160a01b03166001600160a01b03166336c7851684308a8e6040518563ffffffff1660e01b8152600401612e3e949392919061457a565b600060405180830381600087803b158015612e5857600080fd5b505af1158015612e6c573d6000803e3d6000fd5b50505050611f878a8a8a8a87612f56565b600042831015612e9f5760405162461bcd60e51b8152600401610926906146e5565b600082612eec57612ee7338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612f2d565b612f2d338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050612f38876124f4565b612f4d6001600160a01b038c1682308b612604565b6112b78b8b8b8b855b600083612f755760405162461bcd60e51b8152600401610926906147d0565b828460005b81811015613018576000888883818110612f9657612f966145a5565b90506040020160200135905080841015612fc25760405162461bcd60e51b81526004016109269061477f565b60006130008a8a85818110612fd957612fd96145a5565b612fef9260206040909202019081019150613baf565b6001600160a01b038d169084612500565b9050801561300e5781850394505b5050600101612f7a565b508115613033576130336001600160a01b0389168584613289565b6000805160206148c383398151915261304c83876143d8565b604080519182526001600160a01b038b1660208301520160405180910390a15a98975050505050505050565b3480156107e15760006001600160a01b038316156130d65761309c600154836132b9565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f193505050509050806130d457600091505b505b808211156106f5576106f56130eb82846143d8565b610790565b6000613145826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166132c89092919063ffffffff16565b90508051600014806131665750808060200190518101906131669190614871565b6106f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610926565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156131fc5750600090506003613280565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613250573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661327957600060019250925050613280565b9150600090505b94509492505050565b6040516001600160a01b0383166024820152604481018290526106f590849063a9059cbb60e01b90606401612638565b6000818310612d225781611777565b6060610936848460008585600080866001600160a01b031685876040516132ef9190614893565b60006040518083038185875af1925050503d806000811461332c576040519150601f19603f3d011682016040523d82523d6000602084013e613331565b606091505b5091509150611be987838387606083156133ac5782516000036133a5576001600160a01b0385163b6133a55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610926565b5081610936565b61093683838151156133c15781518083602001fd5b8060405162461bcd60e51b815260040161092691906148af565b6001600160a01b03811681146124fd57600080fd5b80356133fb816133db565b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561343857613438613400565b60405290565b600082601f83011261344f57600080fd5b81356001600160401b038082111561346957613469613400565b604051601f8301601f19908116603f0116810190828211818310171561349157613491613400565b816040528381528660208588010111156134aa57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080608085870312156134e057600080fd5b84356134eb816133db565b935060208501356134fb816133db565b92506040850135915060608501356001600160401b0381111561351d57600080fd5b6135298782880161343e565b91505092959194509250565b60006020828403121561354757600080fd5b5035919050565b60008083601f84011261356057600080fd5b5081356001600160401b0381111561357757600080fd5b6020830191508360208260061b8501011115612d0c57600080fd5b6000806000604084860312156135a757600080fd5b83356001600160401b038111156135bd57600080fd5b6135c98682870161354e565b909790965060209590950135949350505050565b60008083601f8401126135ef57600080fd5b5081356001600160401b0381111561360657600080fd5b602083019150836020828501011115612d0c57600080fd5b600060c0828403121561363057600080fd5b50919050565b6000806000806000806000610140888a03121561365257600080fd5b873561365d816133db565b9650602088013561366d816133db565b955060408801356001600160401b038082111561368957600080fd5b6136958b838c0161354e565b909750955060608a01359150808211156136ae57600080fd5b506136bb8a828b016135dd565b90945092506136cf90508960808a0161361e565b905092959891949750929550565b600081518084526020808501945080840160005b8381101561372157815180516001600160a01b0316885283015183880152604090960195908201906001016136f1565b509495945050505050565b831515815282602082015260606040820152600061183560608301846136dd565b60008060008060006060868803121561376557600080fd5b85356001600160401b038082111561377c57600080fd5b61378889838a0161354e565b909750955060208801359150808211156137a157600080fd5b506137ae888289016135dd565b96999598509660400135949350505050565b600080600080606085870312156137d657600080fd5b84356137e1816133db565b93506020850135925060408501356001600160401b0381111561380357600080fd5b61380f8782880161354e565b95989497509550505050565b6000806000806000806000610140888a03121561383757600080fd5b8735613842816133db565b965060208801356001600160401b038082111561385e57600080fd5b61386a8b838c0161354e565b909850965060408a0135915061387f826133db565b909450606089013590808211156136ae57600080fd5b60008060008060008060008060008060006101a08c8e0312156138b757600080fd5b6138c08c6133f0565b9a506001600160401b038060208e013511156138db57600080fd5b6138eb8e60208f01358f0161354e565b909b50995060408d0135985061390360608e016133f0565b97508060808e0135111561391657600080fd5b6139268e60808f01358f016135dd565b90975095506139388e60a08f0161361e565b9450806101608e0135111561394c57600080fd5b5061395e8d6101608e01358e016135dd565b81945080935050506101808c013590509295989b509295989b9093969950565b6000806000806000806000806000806101808b8d03121561399e57600080fd5b8a356139a9816133db565b995060208b01356001600160401b03808211156139c557600080fd5b6139d18e838f0161354e565b909b50995060408d013591506139e6826133db565b90975060608c013590808211156139fc57600080fd5b613a088e838f016135dd565b9098509650869150613a1d8e60808f0161361e565b95506101408d0135915080821115613a3457600080fd5b50613a418d828e016135dd565b915080945050809250506101608b013590509295989b9194979a5092959850565b600080600060408486031215613a7757600080fd5b8335613a82816133db565b925060208401356001600160401b03811115613a9d57600080fd5b613aa98682870161354e565b9497909650939450505050565b82815260406020820152600061093660408301846136dd565b60008060208385031215613ae257600080fd5b82356001600160401b03811115613af857600080fd5b613b048582860161354e565b90969095509350505050565b600080600080600080600060a0888a031215613b2b57600080fd5b8735613b36816133db565b965060208801356001600160401b0380821115613b5257600080fd5b613b5e8b838c0161354e565b909850965060408a01359150613b73826133db565b90945060608901359080821115613b8957600080fd5b50613b968a828b016135dd565b989b979a50959894979596608090950135949350505050565b600060208284031215613bc157600080fd5b8135611777816133db565b60008060008060008060008060008060006101a08c8e031215613bee57600080fd5b613bf78c6133f0565b9a506001600160401b038060208e01351115613c1257600080fd5b613c228e60208f01358f0161354e565b909b509950613c3360408e016133f0565b98508060608e01351115613c4657600080fd5b613c568e60608f01358f016135dd565b9098509650613c688e60808f0161361e565b95506139386101408e016133f0565b60008060408385031215613c8a57600080fd5b8235613c95816133db565b946020939093013593505050565b600080600080600080600060a0888a031215613cbe57600080fd5b87356001600160401b0380821115613cd557600080fd5b613ce18b838c0161354e565b909950975060208a0135965060408a01359150613b73826133db565b60008060008060608587031215613d1357600080fd5b8435613d1e816133db565b935060208501356001600160401b03811115613d3957600080fd5b613d458782880161354e565b9094509250506040850135613d59816133db565b939692955090935050565b60008060008060008060008060c0898b031215613d8057600080fd5b8835613d8b816133db565b975060208901356001600160401b0380821115613da757600080fd5b613db38c838d0161354e565b909950975060408b01359150613dc8826133db565b90955060608a013590613dda826133db565b90945060808a01359080821115613df057600080fd5b50613dfd8b828c016135dd565b999c989b50969995989497949560a00135949350505050565b600080600060608486031215613e2b57600080fd5b8335613e36816133db565b92506020840135915060408401356001600160401b03811115613e5857600080fd5b613e648682870161343e565b9150509250925092565b6000806000806000806000806000806000806101c08d8f031215613e9157600080fd5b613e9a8d6133f0565b9b506001600160401b0360208e01351115613eb457600080fd5b613ec48e60208f01358f0161354e565b909b50995060408d01359850613edc60608e016133f0565b97506001600160401b0360808e01351115613ef657600080fd5b613f068e60808f01358f016135dd565b9097509550613f188e60a08f0161361e565b9450613f276101608e016133f0565b93506001600160401b036101808e01351115613f4257600080fd5b613f538e6101808f01358f016135dd565b81945080935050506101a08d013590509295989b509295989b509295989b565b60008060008060008060808789031215613f8c57600080fd5b86356001600160401b0380821115613fa357600080fd5b613faf8a838b0161354e565b909850965060208901359150613fc4826133db565b90945060408801359080821115613fda57600080fd5b50613fe789828a016135dd565b979a9699509497949695606090950135949350505050565b60008060008060008060008060c0898b03121561401b57600080fd5b8835614026816133db565b975060208901356001600160401b038082111561404257600080fd5b61404e8c838d0161354e565b909950975060408b0135965060608b01359150613dda826133db565b60008060008060006080868803121561408257600080fd5b853561408d816133db565b945060208601356001600160401b038111156140a857600080fd5b6140b48882890161354e565b9095509350506040860135915060608601356140cf816133db565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561411f578151805185528601518685015292840192908501906001016140fa565b5091979650505050505050565b600080600080600080600080600060e08a8c03121561414a57600080fd5b8935614155816133db565b985060208a01356001600160401b038082111561417157600080fd5b61417d8d838e0161354e565b909a50985060408c0135975060608c01359150614199826133db565b90955060808b0135906141ab826133db565b90945060a08b013590808211156141c157600080fd5b506141ce8c828d016135dd565b9a9d999c50979a9699959894979660c00135949350505050565b6000806000806000806080878903121561420157600080fd5b86356001600160401b038082111561421857600080fd5b6142248a838b0161354e565b9098509650602089013595506040890135915080821115613fda57600080fd5b600080600080600080600080610160898b03121561426157600080fd5b883561426c816133db565b975060208901356001600160401b038082111561428857600080fd5b6142948c838d0161354e565b909950975060408b0135965060608b013591506142b0826133db565b90945060808a013590808211156142c657600080fd5b506142d38b828c016135dd565b90945092506142e790508a60a08b0161361e565b90509295985092959890939650565b600080600080600080610120878903121561431057600080fd5b863561431b816133db565b955060208701356001600160401b038082111561433757600080fd5b6143438a838b0161354e565b9097509550604089013591508082111561435c57600080fd5b5061436989828a016135dd565b909450925061437d9050886060890161361e565b90509295509295509295565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761176257611762614389565b6000826143d357634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561176257611762614389565b60005b838110156144065781810151838201526020016143ee565b50506000910152565b600081518084526144278160208601602086016143eb565b601f01601f19169290920160200192915050565b828152604060208201526000610936604083018461440f565b60006020828403121561446657600080fd5b81516001600160e01b03198116811461177757600080fd5b60006020828403121561449057600080fd5b5051919050565b803565ffffffffffff811681146133fb57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385811682526000906101009086356144f5816133db565b818116602086015250602087013561450c816133db565b81811660408601525061452160408801614497565b65ffffffffffff80821660608701528061453d60608b01614497565b16608087015250506080870135614553816133db565b81811660a0860152505060a086013560c08401528060e0840152611be981840185876144ad565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000604082840312156145cd57600080fd5b604051604081018181106001600160401b03821117156145ef576145ef613400565b60405282356145fd816133db565b81526020928301359281019290925250919050565b60006001820161462457614624614389565b5060010190565b600081830360c081121561463e57600080fd5b604051606081018181106001600160401b038211171561466057614660613400565b604052608082121561467157600080fd5b614679613416565b91508335614686816133db565b82526020840135614696816133db565b60208301526146a760408501614497565b60408301526146b860608501614497565b60608301528181526146cc608085016133f0565b602082015260a093909301356040840152509092915050565b60208082526019908201527f546865207369676e617475726520686173206578706972656400000000000000604082015260600190565b7f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152611c9b60f11b601a8201526000825161475f81601c8501602087016143eb565b91909101601c0192915050565b8082018082111561176257611762614389565b60208082526031908201527f496e636f727265637420726563697069656e747320616d6f756e74733a2073756040820152701b481b5bdc99481d1a185b881d1bdd185b607a1b606082015260800190565b602080825260129082015271139bc81c9958da5c1a595b9d1cc81cd95b9d60721b604082015260600190565b600061010060018060a01b0380881684528651818151166020860152816020820151166040860152604081015165ffffffffffff80821660608801528060608401511660808801525050508060208801511660a085015250604086015160c08401528060e0840152611be981840185876144ad565b60006020828403121561488357600080fd5b8151801515811461177757600080fd5b600082516148a58184602087016143eb565b9190910192915050565b602081526000611777602083018461440f56fe15c3c1df3fd692b7e97a6f8e52214a2326147bdf6aa03789b046ad82cf090c21a264697066735822122071aa52db0733c3a192d7558a969993e288e34ea94fabf1a2d7771cc7863e578e64736f6c6343000813003300000000000000000000000000000000000000000000000000f8b0a10e4700000000000000000000000000000000000000000000000000000018de76816d8000000000000000000000000000e104db1807ae47de57ec86885afa8d39421394ee000000000000000000000000eaa234e20627df4f7b26e871876050f30e22495e00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000a688906bd8b0000
Deployed Bytecode
0x6080604052600436106102975760003560e01c80636abb9a461161015a578063a734f06e116100c1578063c7977be71161007a578063c7977be7146106fa578063d4fb0a871461072e578063d7df0ebf14610741578063ddca3f4314610754578063f6bbf0a21461076a578063fe9017581461077d576102ad565b8063a734f06e14610678578063a838e34c1461068e578063b23a1088146106a1578063b766d62c146106b4578063c051eb84146106c7578063c0ee0b8a146106da576102ad565b806384ae2bc61161011357806384ae2bc6146105e757806384b14f96146105fd5780638e031cb61461061d578063926988b4146106305780639a2631ad146106435780639da9eaa514610656576102ad565b80636abb9a461461055b578063708256b41461056e57806373922184146105815780637b6423b9146105945780637e9505c0146105b457806380b2740d146105c7576102ad565b80632fba23bf116101fe57806356e89613116101b757806356e89613146104cf578063574a5e12146104e2578063591552da146104f55780635d40019b1461051557806361bcaabe146105285780636857c1ce1461053b576102ad565b80632fba23bf146104345780633644e515146104475780633e52c01c1461045c57806343933aa01461046f57806346d5bea11461049c57806351208fb3146104af576102ad565b806312261ee71161025057806312261ee71461038f5780631b641a7d146103c75780631e292472146103da57806323950ddd146103ed57806329d822c2146104005780632defb6fd14610421576102ad565b806301cea205146102bc578063039af9eb146102f157806306b16c7f146103265780630caeb05c146103475780630f0b726c1461036957806310d56a2c1461037c576102ad565b366102ad5734156102ab576102ab34610790565b005b34156102ab576102ab34610790565b3480156102c857600080fd5b506102dc6102d73660046134ca565b6107e5565b60405190151581526020015b60405180910390f35b3480156102fd57600080fd5b5061031161030c366004613535565b61093e565b604080519283526020830191909152016102e8565b610339610334366004613592565b61096c565b6040519081526020016102e8565b61035a610355366004613636565b61097a565b6040516102e89392919061372c565b61033961037736600461374d565b610e3f565b61035a61038a3660046137c0565b610e5b565b34801561039b57600080fd5b506006546103af906001600160a01b031681565b6040516001600160a01b0390911681526020016102e8565b6103396103d536600461381b565b61124e565b6103396103e8366004613895565b61126c565b6103396103fb36600461397e565b6112a1565b61041361040e366004613a62565b6112c6565b6040516102e8929190613ab6565b61041361042f366004613acf565b611411565b610339610442366004613b10565b611598565b34801561045357600080fd5b506103396115ab565b61033961046a366004613b10565b611679565b34801561047b57600080fd5b5061033961048a366004613baf565b60056020526000908152604090205481565b6103396104aa366004613bcc565b61168c565b3480156104bb57600080fd5b506103396104ca366004613c77565b611701565b6103396104dd366004613acf565b611768565b6103396104f0366004613ca3565b61177e565b34801561050157600080fd5b50610339610510366004613baf565b6117ef565b610339610523366004613cfd565b61181e565b610339610536366004613d64565b61183e565b34801561054757600080fd5b506103af610556366004613e16565b6118f1565b6102ab610569366004613535565b6119b1565b61033961057c366004613e6e565b611ae0565b61033961058f366004613f73565b611b77565b3480156105a057600080fd5b506103af6105af366004613e16565b611bf4565b6103396105c2366004613fff565b611c2c565b3480156105d357600080fd5b506003546103af906001600160a01b031681565b3480156105f357600080fd5b5061033960015481565b34801561060957600080fd5b506002546103af906001600160a01b031681565b61033961062b36600461406a565b611c40565b61033961063e366004613895565b611c6d565b61033961065136600461397e565b611c92565b34801561066257600080fd5b5061066b611ca8565b6040516102e891906140dd565b34801561068457600080fd5b506103af61beef81565b61041361069c366004613592565b611d1b565b6103396106af366004613fff565b611ed0565b6103396106c236600461374d565b611ee4565b6103396106d536600461412c565b611ef7565b3480156106e657600080fd5b506102ab6106f5366004613e16565b505050565b34801561070657600080fd5b506103397fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b61033961073c3660046141e8565b611f95565b61033961074f366004614244565b611fa7565b34801561076057600080fd5b5061033960005481565b6104136107783660046142f6565b611fc3565b61033961078b3660046141e8565b6121b9565b6000606461079f83601461439f565b6107a991906143b6565b6002549091506107c2906001600160a01b0316826121cb565b6107e16107cf82846143d8565b6003546001600160a01b0316906121cb565b5050565b6000806107f06115ab565b6107fa8686611701565b60405161190160f01b6020820152602281019290925260428201526062016040516020818303038152906040528051906020012090506000866001600160a01b0316631626ba7e83866040518363ffffffff1660e01b815260040161086092919061443b565b602060405180830381865afa15801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a19190614454565b90506001600160e01b03198116630b135d3f60e11b14806108d257506001600160e01b031981166320c13b0b60e01b145b61092f5760405162461bcd60e51b815260206004820152602360248201527f496e76616c696420636f6e7472616374207369676e61747572652070726f766960448201526219195960ea1b60648201526084015b60405180910390fd5b6001925050505b949350505050565b6004818154811061094e57600080fd5b60009182526020909120600290910201805460019091015490915082565b6000610936848433856122e4565b600080606061098960006124f4565b866001600160401b038111156109a1576109a1613400565b6040519080825280602002602001820160405280156109e657816020015b60408051808201909152600080825260208201528152602001906001900390816109bf5790505b506040516370a0823160e01b81523060048201529091506000906001600160a01b038c16906370a0823190602401602060405180830381865afa158015610a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a55919061447e565b90508515610ac6576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b57090610a9390339089908c908c906004016144d6565b600060405180830381600087803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b505050505b6006546001600160a01b03166001600160a01b03166336c7851633308d8f6040518563ffffffff1660e01b8152600401610b03949392919061457a565b600060405180830381600087803b158015610b1d57600080fd5b505af1158015610b31573d6000803e3d6000fd5b50506040516370a0823160e01b81523060048201528392506001600160a01b038e1691506370a0823190602401602060405180830381865afa158015610b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9f919061447e565b610ba991906143d8565b9050896001600160a01b03168114610bc957600160009350935050610e32565b60005b88811015610e2c578b6001600160a01b03166370a082318b8b84818110610bf557610bf56145a5565b610c0b9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c73919061447e565b91506000610cd78b8b84818110610c8c57610c8c6145a5565b610ca29260206040909202019081019150613baf565b8c8c85818110610cb457610cb46145a5565b905060400201602001358f6001600160a01b03166125009092919063ffffffff16565b905080610ce5576000610d8f565b828d6001600160a01b03166370a082318d8d86818110610d0757610d076145a5565b610d1d9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610d61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d85919061447e565b610d8f91906143d8565b9250808015610db957508a8a83818110610dab57610dab6145a5565b905060400201602001358314155b15610dce576001600095509550505050610e32565b80610e19578a8a83818110610de557610de56145a5565b905060400201803603810190610dfb91906145bb565b848381518110610e0d57610e0d6145a5565b60200260200101819052505b5080610e2481614612565b915050610bcc565b505a9250505b9750975097945050505050565b6000610e518686868686600080612546565b9695505050505050565b6000806060610e6a60006124f4565b836001600160401b03811115610e8257610e82613400565b604051908082528060200260200182016040528015610ec757816020015b6040805180820190915260008082526020820152815260200190600190039081610ea05790505b506040516370a0823160e01b81523060048201529091506000906001600160a01b038916906370a0823190602401602060405180830381865afa158015610f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f36919061447e565b9050610f4d6001600160a01b03891633308a612604565b6040516370a0823160e01b815230600482015281906001600160a01b038a16906370a0823190602401602060405180830381865afa158015610f93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb7919061447e565b610fc191906143d8565b9050868114610fd857600160009350935050611244565b8460005b8181101561123d57896001600160a01b03166370a08231898984818110611005576110056145a5565b61101b9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa15801561105f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611083919061447e565b925060006110e789898481811061109c5761109c6145a5565b6110b29260206040909202019081019150613baf565b8a8a858181106110c4576110c46145a5565b905060400201602001358d6001600160a01b03166125009092919063ffffffff16565b9050806110f557600061119f565b838b6001600160a01b03166370a082318b8b86818110611117576111176145a5565b61112d9260206040909202019081019150613baf565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015611171573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611195919061447e565b61119f91906143d8565b93508080156111c957508888838181106111bb576111bb6145a5565b905060400201602001358414155b156111df57600160009650965050505050611244565b8061122a578888838181106111f6576111f66145a5565b90506040020180360381019061120c91906145bb565b85838151811061121e5761121e6145a5565b60200260200101819052505b508061123581614612565b915050610fdc565b505a935050505b9450945094915050565b60006112608888888886898933612675565b98975050505050505050565b60006112918c8c8c8c8c8c8c611287368e90038e018e61462b565b8c8c8c60006128cc565b9c9b505050505050505050505050565b60006112b78b8b8b8b898c8c8b8b8b60006129a1565b9b9a5050505050505050505050565b600060606112d460006124f4565b826001600160401b038111156112ec576112ec613400565b60405190808252806020026020018201604052801561133157816020015b604080518082019091526000808252602082015281526020019060019003908161130a5790505b5090508260005b818110156114045760006113a433888885818110611358576113586145a5565b61136e9260206040909202019081019150613baf565b898986818110611380576113806145a5565b905060400201602001358b6001600160a01b0316612a63909392919063ffffffff16565b9050806113f1578686838181106113bd576113bd6145a5565b9050604002018036038101906113d391906145bb565b8483815181106113e5576113e56145a5565b60200260200101819052505b50806113fc81614612565b915050611338565b505a925050935093915050565b60006060826001600160401b0381111561142d5761142d613400565b60405190808252806020026020018201604052801561147257816020015b604080518082019091526000808252602082015281526020019060019003908161144b5790505b509050348360005b8181101561157c576000878783818110611496576114966145a5565b6114ac9260206040909202019081019150613baf565b6001600160a01b03166108fc8989858181106114ca576114ca6145a5565b905060400201602001359081150290604051600060405180830381858888f1935050505090508061153f57878783818110611507576115076145a5565b90506040020180360381019061151d91906145bb565b85838151811061152f5761152f6145a5565b6020026020010181905250611569565b878783818110611551576115516145a5565b905060400201602001358461156691906143d8565b93505b508061157481614612565b91505061147a565b50811561158c5761158c82610790565b5a935050509250929050565b6000611260888888888888886001612aae565b604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647260208201527f433b68d57964cf3844fb37130abb6d9de19030f03725ce749ad05453b740b157918101919091527fbe39c2702c76475cb6c2596f1e97ed8d703798e477af2efa214cbcda3006f17a60608201524660808201523060a08201527ff2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a55860c0820181905260009160e0016040516020818303038152906040528051906020012091505090565b6000611260888888888888886000612aae565b6000428210156116ae5760405162461bcd60e51b8152600401610926906146e5565b6116f085338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b506112918c8c8c8c8a8d8d8c612675565b604080517fe419504a688f0e6ea59c2708f49b2bbc10a2da71770bd6e1b324e39c73e7dc2560208201526001600160a01b03841691810191909152606081018290526000906080016040516020818303038152906040528051906020012090505b92915050565b600061177783833360006122e4565b9392505050565b6000428210156117a05760405162461bcd60e51b8152600401610926906146e5565b6117e285338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611260888887896122e4565b6001600160a01b038116600090815260056020526040812054421161181657506000919050565b505060005490565b6000611829826124f4565b61183585858533612b9d565b95945050505050565b60004282101561188c5760405162461bcd60e51b81526020600482015260196024820152781d1a19481cda59db985d1d5c99481a185cc8195e1c1a5c9959603a1b6044820152606401610926565b6118ce85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b506118d8866124f4565b6118e489898988612b9d565b9998505050505050505050565b604080514660208201526001600160a01b03851681830152606080820185905282518083039091018152608082019092526000918291611934919060a00161471c565b60405160208183030381529060405280519060200120905060006119588285612cce565b5090506001600160a01b0381166118355760405162461bcd60e51b815260206004820152601860248201527f746865207369676e617475726520697320696e76616c696400000000000000006044820152606401610926565b600481815481106119c4576119c46145a5565b906000526020600020906002020160010154341015611a3a5760405162461bcd60e51b815260206004820152602c60248201527f4e6f7420656e6f756768204554482076616c756520666f72205649502073746160448201526b74757320707572636861736560a01b6064820152608401610926565b611a4334610790565b33600090815260056020526040812054611a5d9042612d13565b905060048281548110611a7257611a726145a5565b90600052602060002090600202016000015481611a8f919061476c565b336000818152600560209081526040918290209390935580519182529181018490527fee4c6b99bbc510f4eaae1269a7e65d6bf4a6dcf0043ea60e68ada838afcdc552910160405180910390a15050565b600042821015611b025760405162461bcd60e51b8152600401610926906146e5565b611b4485338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611b668d8d8d8d8d8d8d8c8e803603810190611b61919061462b565b612d29565b9d9c50505050505050505050505050565b600042821015611b995760405162461bcd60e51b8152600401610926906146e5565b611bdb85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611be987878760006122e4565b979650505050505050565b600080611bff6115ab565b611c098686611701565b60405161190160f01b602082015260228101929092526042820152606201611934565b60006118e489898989898989896001612e7d565b6000611c4b826124f4565b611c606001600160a01b038716333086612604565b610e518686868633612f56565b60006112918c8c8c8c8c8c8c611c88368e90038e018e61462b565b8c8c8c60016128cc565b60006112b78b8b8b8b898c8c8b8b8b60016129a1565b60606004805480602002602001604051908101604052809291908181526020016000905b82821015611d1257838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190611ccc565b50505050905090565b60006060836001600160401b03811115611d3757611d37613400565b604051908082528060200260200182016040528015611d7c57816020015b6040805180820190915260008082526020820152815260200190600190039081611d555790505b509050348460005b81811015611eb3576000888883818110611da057611da06145a5565b611db69260206040909202019081019150613baf565b6001600160a01b0316898984818110611dd157611dd16145a5565b905060400201602001358890604051600060405180830381858888f193505050503d8060008114611e1e576040519150601f19603f3d011682016040523d82523d6000602084013e611e23565b606091505b5050905080611e7657888883818110611e3e57611e3e6145a5565b905060400201803603810190611e5491906145bb565b858381518110611e6657611e666145a5565b6020026020010181905250611ea0565b888883818110611e8857611e886145a5565b9050604002016020013584611e9d91906143d8565b93505b5080611eab81614612565b915050611d84565b508115611ec357611ec382610790565b5a93505050935093915050565b60006118e489898989898989896000612e7d565b6000610e51868686868660016000612546565b600042821015611f195760405162461bcd60e51b8152600401610926906146e5565b611f5b85338487878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107e592505050565b50611f65866124f4565b611f7a6001600160a01b038b1686308a612604565b611f878a8a8a8a89612f56565b9a9950505050505050505050565b6000611be9878786868660008b612546565b60006118e48989898989898933611b61368c90038c018c61462b565b60006060611fd160006124f4565b856001600160401b03811115611fe957611fe9613400565b60405190808252806020026020018201604052801561202e57816020015b60408051808201909152600080825260208201528152602001906001900390816120075790505b50905083156120a0576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061206d90339087908a908a906004016144d6565b600060405180830381600087803b15801561208757600080fd5b505af115801561209b573d6000803e3d6000fd5b505050505b8560005b818110156121a9576006546001600160a01b03166336c78516338b8b858181106120d0576120d06145a5565b6120e69260206040909202019081019150613baf565b8c8c868181106120f8576120f86145a5565b905060400201602001358e6040518563ffffffff1660e01b8152600401612122949392919061457a565b600060405180830381600087803b15801561213c57600080fd5b505af192505050801561214d575060015b61219757888882818110612163576121636145a5565b90506040020180360381019061217991906145bb565b83828151811061218b5761218b6145a5565b60200260200101819052505b806121a181614612565b9150506120a4565b505a925050965096945050505050565b6000611be9878786868660018b612546565b8047101561221b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610926565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612268576040519150601f19603f3d011682016040523d82523d6000602084013e61226d565b606091505b50509050806106f55760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610926565b6000348185815b81811015612433576000898983818110612307576123076145a5565b905060400201602001359050808510156123335760405162461bcd60e51b81526004016109269061477f565b61233d818561476c565b9350600087156123cc578a8a84818110612359576123596145a5565b61236f9260206040909202019081019150613baf565b6001600160a01b0316828990604051600060405180830381858888f193505050503d80600081146123bc576040519150601f19603f3d011682016040523d82523d6000602084013e6123c1565b606091505b50508091505061241d565b8a8a848181106123de576123de6145a5565b6123f49260206040909202019081019150613baf565b6001600160a01b03166108fc839081150290604051600060405180830381858888f19450505050505b80156124295781860395505b50506001016122eb565b50600061244084346143d8565b9050600061244e82856143d8565b905080156124ae57848111156124965760405162461bcd60e51b815260206004820152600d60248201526c4c6f77206d73672e76616c756560981b6044820152606401610926565b93849003936124ae6001600160a01b038916826121cb565b84156124bd576124bd85610790565b6040805183815261beef60208201526000805160206148c3833981519152910160405180910390a15a9a9950505050505050505050565b6124fd81613078565b50565b600060405163a9059cbb60e01b6000528360045282602452602060006044600080895af13d15601f3d116001600051141617169150600060605280604052509392505050565b6000428410156125685760405162461bcd60e51b8152600401610926906146e5565b6000836125b5576125b0338689898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b6125f6565b6125f6338689898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b90506118e4898983866122e4565b6040516001600160a01b038085166024830152831660448201526064810182905261266f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526130f0565b50505050565b6006546000906001600160a01b03166126cb5760405162461bcd60e51b81526020600482015260186024820152772737903832b936b4ba191034b7103a3434b99031b430b4b760411b6044820152606401610926565b866126e85760405162461bcd60e51b8152600401610926906147d0565b6001600160a01b0389163b61273a5760405162461bcd60e51b8152602060048201526018602482015277546f6b656e206164647265737320656d70747920636f646560401b6044820152606401610926565b612743866124f4565b82156127b2576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b5709061277f9085908990899089906004016144d6565b600060405180830381600087803b15801561279957600080fd5b505af11580156127ad573d6000803e3d6000fd5b505050505b6000805b8881101561288d576006546001600160a01b03166336c78516858c8c858181106127e2576127e26145a5565b6127f89260206040909202019081019150613baf565b8d8d8681811061280a5761280a6145a5565b905060400201602001358f6040518563ffffffff1660e01b8152600401612834949392919061457a565b600060405180830381600087803b15801561284e57600080fd5b505af192505050801561285f575060015b1561288557898982818110612876576128766145a5565b90506040020160200135820191505b6001016127b6565b50604080518281526001600160a01b038c1660208201526000805160206148c3833981519152910160405180910390a15a9a9950505050505050505050565b6000428310156128ee5760405162461bcd60e51b8152600401610926906146e5565b60008261293b57612936338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b61297c565b61297c338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b905061298f8e8e8e8e8e8e8e888f612d29565b9e9d5050505050505050505050505050565b6000428310156129c35760405162461bcd60e51b8152600401610926906146e5565b600082612a1057612a0b338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612a51565b612a51338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050611b668d8d8d8d8d8d8d88612675565b60006040516323b872dd60e01b6000528460045283602452826044526020600060646000808a5af13d15601f3d11600160005114161716915060006060528060405250949350505050565b600042831015612afc5760405162461bcd60e51b81526020600482015260196024820152781d1a19481cda59db985d1d5c99481a185cc8195e1c1a5c9959603a1b6044820152606401610926565b600082612b4957612b44338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612b8a565b612b8a338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050612b95876124f4565b611f878a8a8a845b600082612bbc5760405162461bcd60e51b8152600401610926906147d0565b6001600160a01b0385163b612c0e5760405162461bcd60e51b8152602060048201526018602482015277546f6b656e206164647265737320656d70747920636f646560401b6044820152606401610926565b600083815b81811015612c92576000878783818110612c2f57612c2f6145a5565b9050604002016020013590506000612c7b878a8a86818110612c5357612c536145a5565b612c699260206040909202019081019150613baf565b6001600160a01b038d16919085612a63565b90508015612c8857938101935b5050600101612c13565b50604080518381526001600160a01b03891660208201526000805160206148c3833981519152910160405180910390a15a979650505050505050565b6000808251604103612d045760208301516040840151606085015160001a612cf8878285856131c5565b94509450505050612d0c565b506000905060025b9250929050565b6000818311612d225781611777565b5090919050565b6006546000906001600160a01b0316612d7f5760405162461bcd60e51b81526020600482015260186024820152772737903832b936b4ba191034b7103a3434b99031b430b4b760411b6044820152606401610926565b612d88866124f4565b8315612df7576006546040516302b67b5760e41b81526001600160a01b0390911690632b67b57090612dc490869086908a908a906004016147fc565b600060405180830381600087803b158015612dde57600080fd5b505af1158015612df2573d6000803e3d6000fd5b505050505b600660009054906101000a90046001600160a01b03166001600160a01b03166336c7851684308a8e6040518563ffffffff1660e01b8152600401612e3e949392919061457a565b600060405180830381600087803b158015612e5857600080fd5b505af1158015612e6c573d6000803e3d6000fd5b50505050611f878a8a8a8a87612f56565b600042831015612e9f5760405162461bcd60e51b8152600401610926906146e5565b600082612eec57612ee7338588888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611bf492505050565b612f2d565b612f2d338588888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118f192505050565b9050612f38876124f4565b612f4d6001600160a01b038c1682308b612604565b6112b78b8b8b8b855b600083612f755760405162461bcd60e51b8152600401610926906147d0565b828460005b81811015613018576000888883818110612f9657612f966145a5565b90506040020160200135905080841015612fc25760405162461bcd60e51b81526004016109269061477f565b60006130008a8a85818110612fd957612fd96145a5565b612fef9260206040909202019081019150613baf565b6001600160a01b038d169084612500565b9050801561300e5781850394505b5050600101612f7a565b508115613033576130336001600160a01b0389168584613289565b6000805160206148c383398151915261304c83876143d8565b604080519182526001600160a01b038b1660208301520160405180910390a15a98975050505050505050565b3480156107e15760006001600160a01b038316156130d65761309c600154836132b9565b90506000836001600160a01b03166108fc839081150290604051600060405180830381858888f193505050509050806130d457600091505b505b808211156106f5576106f56130eb82846143d8565b610790565b6000613145826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166132c89092919063ffffffff16565b90508051600014806131665750808060200190518101906131669190614871565b6106f55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610926565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156131fc5750600090506003613280565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613250573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661327957600060019250925050613280565b9150600090505b94509492505050565b6040516001600160a01b0383166024820152604481018290526106f590849063a9059cbb60e01b90606401612638565b6000818310612d225781611777565b6060610936848460008585600080866001600160a01b031685876040516132ef9190614893565b60006040518083038185875af1925050503d806000811461332c576040519150601f19603f3d011682016040523d82523d6000602084013e613331565b606091505b5091509150611be987838387606083156133ac5782516000036133a5576001600160a01b0385163b6133a55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610926565b5081610936565b61093683838151156133c15781518083602001fd5b8060405162461bcd60e51b815260040161092691906148af565b6001600160a01b03811681146124fd57600080fd5b80356133fb816133db565b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561343857613438613400565b60405290565b600082601f83011261344f57600080fd5b81356001600160401b038082111561346957613469613400565b604051601f8301601f19908116603f0116810190828211818310171561349157613491613400565b816040528381528660208588010111156134aa57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080608085870312156134e057600080fd5b84356134eb816133db565b935060208501356134fb816133db565b92506040850135915060608501356001600160401b0381111561351d57600080fd5b6135298782880161343e565b91505092959194509250565b60006020828403121561354757600080fd5b5035919050565b60008083601f84011261356057600080fd5b5081356001600160401b0381111561357757600080fd5b6020830191508360208260061b8501011115612d0c57600080fd5b6000806000604084860312156135a757600080fd5b83356001600160401b038111156135bd57600080fd5b6135c98682870161354e565b909790965060209590950135949350505050565b60008083601f8401126135ef57600080fd5b5081356001600160401b0381111561360657600080fd5b602083019150836020828501011115612d0c57600080fd5b600060c0828403121561363057600080fd5b50919050565b6000806000806000806000610140888a03121561365257600080fd5b873561365d816133db565b9650602088013561366d816133db565b955060408801356001600160401b038082111561368957600080fd5b6136958b838c0161354e565b909750955060608a01359150808211156136ae57600080fd5b506136bb8a828b016135dd565b90945092506136cf90508960808a0161361e565b905092959891949750929550565b600081518084526020808501945080840160005b8381101561372157815180516001600160a01b0316885283015183880152604090960195908201906001016136f1565b509495945050505050565b831515815282602082015260606040820152600061183560608301846136dd565b60008060008060006060868803121561376557600080fd5b85356001600160401b038082111561377c57600080fd5b61378889838a0161354e565b909750955060208801359150808211156137a157600080fd5b506137ae888289016135dd565b96999598509660400135949350505050565b600080600080606085870312156137d657600080fd5b84356137e1816133db565b93506020850135925060408501356001600160401b0381111561380357600080fd5b61380f8782880161354e565b95989497509550505050565b6000806000806000806000610140888a03121561383757600080fd5b8735613842816133db565b965060208801356001600160401b038082111561385e57600080fd5b61386a8b838c0161354e565b909850965060408a0135915061387f826133db565b909450606089013590808211156136ae57600080fd5b60008060008060008060008060008060006101a08c8e0312156138b757600080fd5b6138c08c6133f0565b9a506001600160401b038060208e013511156138db57600080fd5b6138eb8e60208f01358f0161354e565b909b50995060408d0135985061390360608e016133f0565b97508060808e0135111561391657600080fd5b6139268e60808f01358f016135dd565b90975095506139388e60a08f0161361e565b9450806101608e0135111561394c57600080fd5b5061395e8d6101608e01358e016135dd565b81945080935050506101808c013590509295989b509295989b9093969950565b6000806000806000806000806000806101808b8d03121561399e57600080fd5b8a356139a9816133db565b995060208b01356001600160401b03808211156139c557600080fd5b6139d18e838f0161354e565b909b50995060408d013591506139e6826133db565b90975060608c013590808211156139fc57600080fd5b613a088e838f016135dd565b9098509650869150613a1d8e60808f0161361e565b95506101408d0135915080821115613a3457600080fd5b50613a418d828e016135dd565b915080945050809250506101608b013590509295989b9194979a5092959850565b600080600060408486031215613a7757600080fd5b8335613a82816133db565b925060208401356001600160401b03811115613a9d57600080fd5b613aa98682870161354e565b9497909650939450505050565b82815260406020820152600061093660408301846136dd565b60008060208385031215613ae257600080fd5b82356001600160401b03811115613af857600080fd5b613b048582860161354e565b90969095509350505050565b600080600080600080600060a0888a031215613b2b57600080fd5b8735613b36816133db565b965060208801356001600160401b0380821115613b5257600080fd5b613b5e8b838c0161354e565b909850965060408a01359150613b73826133db565b90945060608901359080821115613b8957600080fd5b50613b968a828b016135dd565b989b979a50959894979596608090950135949350505050565b600060208284031215613bc157600080fd5b8135611777816133db565b60008060008060008060008060008060006101a08c8e031215613bee57600080fd5b613bf78c6133f0565b9a506001600160401b038060208e01351115613c1257600080fd5b613c228e60208f01358f0161354e565b909b509950613c3360408e016133f0565b98508060608e01351115613c4657600080fd5b613c568e60608f01358f016135dd565b9098509650613c688e60808f0161361e565b95506139386101408e016133f0565b60008060408385031215613c8a57600080fd5b8235613c95816133db565b946020939093013593505050565b600080600080600080600060a0888a031215613cbe57600080fd5b87356001600160401b0380821115613cd557600080fd5b613ce18b838c0161354e565b909950975060208a0135965060408a01359150613b73826133db565b60008060008060608587031215613d1357600080fd5b8435613d1e816133db565b935060208501356001600160401b03811115613d3957600080fd5b613d458782880161354e565b9094509250506040850135613d59816133db565b939692955090935050565b60008060008060008060008060c0898b031215613d8057600080fd5b8835613d8b816133db565b975060208901356001600160401b0380821115613da757600080fd5b613db38c838d0161354e565b909950975060408b01359150613dc8826133db565b90955060608a013590613dda826133db565b90945060808a01359080821115613df057600080fd5b50613dfd8b828c016135dd565b999c989b50969995989497949560a00135949350505050565b600080600060608486031215613e2b57600080fd5b8335613e36816133db565b92506020840135915060408401356001600160401b03811115613e5857600080fd5b613e648682870161343e565b9150509250925092565b6000806000806000806000806000806000806101c08d8f031215613e9157600080fd5b613e9a8d6133f0565b9b506001600160401b0360208e01351115613eb457600080fd5b613ec48e60208f01358f0161354e565b909b50995060408d01359850613edc60608e016133f0565b97506001600160401b0360808e01351115613ef657600080fd5b613f068e60808f01358f016135dd565b9097509550613f188e60a08f0161361e565b9450613f276101608e016133f0565b93506001600160401b036101808e01351115613f4257600080fd5b613f538e6101808f01358f016135dd565b81945080935050506101a08d013590509295989b509295989b509295989b565b60008060008060008060808789031215613f8c57600080fd5b86356001600160401b0380821115613fa357600080fd5b613faf8a838b0161354e565b909850965060208901359150613fc4826133db565b90945060408801359080821115613fda57600080fd5b50613fe789828a016135dd565b979a9699509497949695606090950135949350505050565b60008060008060008060008060c0898b03121561401b57600080fd5b8835614026816133db565b975060208901356001600160401b038082111561404257600080fd5b61404e8c838d0161354e565b909950975060408b0135965060608b01359150613dda826133db565b60008060008060006080868803121561408257600080fd5b853561408d816133db565b945060208601356001600160401b038111156140a857600080fd5b6140b48882890161354e565b9095509350506040860135915060608601356140cf816133db565b809150509295509295909350565b602080825282518282018190526000919060409081850190868401855b8281101561411f578151805185528601518685015292840192908501906001016140fa565b5091979650505050505050565b600080600080600080600080600060e08a8c03121561414a57600080fd5b8935614155816133db565b985060208a01356001600160401b038082111561417157600080fd5b61417d8d838e0161354e565b909a50985060408c0135975060608c01359150614199826133db565b90955060808b0135906141ab826133db565b90945060a08b013590808211156141c157600080fd5b506141ce8c828d016135dd565b9a9d999c50979a9699959894979660c00135949350505050565b6000806000806000806080878903121561420157600080fd5b86356001600160401b038082111561421857600080fd5b6142248a838b0161354e565b9098509650602089013595506040890135915080821115613fda57600080fd5b600080600080600080600080610160898b03121561426157600080fd5b883561426c816133db565b975060208901356001600160401b038082111561428857600080fd5b6142948c838d0161354e565b909950975060408b0135965060608b013591506142b0826133db565b90945060808a013590808211156142c657600080fd5b506142d38b828c016135dd565b90945092506142e790508a60a08b0161361e565b90509295985092959890939650565b600080600080600080610120878903121561431057600080fd5b863561431b816133db565b955060208701356001600160401b038082111561433757600080fd5b6143438a838b0161354e565b9097509550604089013591508082111561435c57600080fd5b5061436989828a016135dd565b909450925061437d9050886060890161361e565b90509295509295509295565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761176257611762614389565b6000826143d357634e487b7160e01b600052601260045260246000fd5b500490565b8181038181111561176257611762614389565b60005b838110156144065781810151838201526020016143ee565b50506000910152565b600081518084526144278160208601602086016143eb565b601f01601f19169290920160200192915050565b828152604060208201526000610936604083018461440f565b60006020828403121561446657600080fd5b81516001600160e01b03198116811461177757600080fd5b60006020828403121561449057600080fd5b5051919050565b803565ffffffffffff811681146133fb57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0385811682526000906101009086356144f5816133db565b818116602086015250602087013561450c816133db565b81811660408601525061452160408801614497565b65ffffffffffff80821660608701528061453d60608b01614497565b16608087015250506080870135614553816133db565b81811660a0860152505060a086013560c08401528060e0840152611be981840185876144ad565b6001600160a01b03948516815292841660208401529083166040830152909116606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000604082840312156145cd57600080fd5b604051604081018181106001600160401b03821117156145ef576145ef613400565b60405282356145fd816133db565b81526020928301359281019290925250919050565b60006001820161462457614624614389565b5060010190565b600081830360c081121561463e57600080fd5b604051606081018181106001600160401b038211171561466057614660613400565b604052608082121561467157600080fd5b614679613416565b91508335614686816133db565b82526020840135614696816133db565b60208301526146a760408501614497565b60408301526146b860608501614497565b60608301528181526146cc608085016133f0565b602082015260a093909301356040840152509092915050565b60208082526019908201527f546865207369676e617475726520686173206578706972656400000000000000604082015260600190565b7f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152611c9b60f11b601a8201526000825161475f81601c8501602087016143eb565b91909101601c0192915050565b8082018082111561176257611762614389565b60208082526031908201527f496e636f727265637420726563697069656e747320616d6f756e74733a2073756040820152701b481b5bdc99481d1a185b881d1bdd185b607a1b606082015260800190565b602080825260129082015271139bc81c9958da5c1a595b9d1cc81cd95b9d60721b604082015260600190565b600061010060018060a01b0380881684528651818151166020860152816020820151166040860152604081015165ffffffffffff80821660608801528060608401511660808801525050508060208801511660a085015250604086015160c08401528060e0840152611be981840185876144ad565b60006020828403121561488357600080fd5b8151801515811461177757600080fd5b600082516148a58184602087016143eb565b9190910192915050565b602081526000611777602083018461440f56fe15c3c1df3fd692b7e97a6f8e52214a2326147bdf6aa03789b046ad82cf090c21a264697066735822122071aa52db0733c3a192d7558a969993e288e34ea94fabf1a2d7771cc7863e578e64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000f8b0a10e4700000000000000000000000000000000000000000000000000000018de76816d8000000000000000000000000000e104db1807ae47de57ec86885afa8d39421394ee000000000000000000000000eaa234e20627df4f7b26e871876050f30e22495e00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba30000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000003782dace9d900000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000006f05b59d3b200000000000000000000000000000000000000000000000000000000000000278d000000000000000000000000000000000000000000000000000a688906bd8b0000
-----Decoded View---------------
Arg [0] : _fee (uint256): 70000000000000000
Arg [1] : _referralFee (uint256): 7000000000000000
Arg [2] : _beneficiary20 (address): 0xE104DB1807ae47De57EC86885AFa8D39421394eE
Arg [3] : _beneficiary80 (address): 0xEaA234e20627dF4f7B26E871876050f30E22495E
Arg [4] : _tiers (tuple[]):
Arg [1] : duration (uint256): 86400
Arg [2] : price (uint256): 250000000000000000
Arg [1] : duration (uint256): 604800
Arg [2] : price (uint256): 500000000000000000
Arg [1] : duration (uint256): 2592000
Arg [2] : price (uint256): 750000000000000000
Arg [5] : _permit2Addr (address): 0x000000000022D473030F116dDEE9F6B43aC78BA3
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000f8b0a10e470000
Arg [1] : 0000000000000000000000000000000000000000000000000018de76816d8000
Arg [2] : 000000000000000000000000e104db1807ae47de57ec86885afa8d39421394ee
Arg [3] : 000000000000000000000000eaa234e20627df4f7b26e871876050f30e22495e
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [5] : 000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba3
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [8] : 00000000000000000000000000000000000000000000000003782dace9d90000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000093a80
Arg [10] : 00000000000000000000000000000000000000000000000006f05b59d3b20000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000278d00
Arg [12] : 0000000000000000000000000000000000000000000000000a688906bd8b0000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.