Source Code
Overview
POL Balance
POL Value
$0.00Cross-Chain Transactions
Loading...
Loading
Contract Name:
ZkBobPoolUSDCMigrated
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "./ZkBobPool.sol";
import "./ZkBobTokenSellerMixin.sol";
import "./ZkBobUSDCPermitMixin.sol";
/**
* @title ZkBobPoolUSDCMigrated
* Shielded transactions pool for USDC tokens supporting USDC transfer authorizations
*/
contract ZkBobPoolUSDCMigrated is ZkBobPool, ZkBobTokenSellerMixin, ZkBobUSDCPermitMixin {
constructor(
uint256 __pool_id,
address _token,
ITransferVerifier _transfer_verifier,
ITreeVerifier _tree_verifier,
IBatchDepositVerifier _batch_deposit_verifier,
address _direct_deposit_queue
)
ZkBobPool(
__pool_id,
_token,
_transfer_verifier,
_tree_verifier,
_batch_deposit_verifier,
_direct_deposit_queue,
1,
1_000_000_000
)
{}
function migrationToUSDC() external {
require(msg.sender == address(this), "Incorrect invoker");
require(token == address(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174), "Incorrect token");
address bob_addr = address(0xB0B195aEFA3650A6908f15CdaC7D92F8a5791B0B);
uint256 cur_bob_balance = IERC20(bob_addr).balanceOf(address(this));
uint256 bob_decimals = IERC20Metadata(bob_addr).decimals();
// uint256 prev_usdc_balance = IERC20(token).balanceOf(address(this));
uint256 usdc_decimals = IERC20Metadata(token).decimals();
IBobVault bobswap = IBobVault(0x25E6505297b44f4817538fB2d91b88e1cF841B54);
bool retval = IERC20(bob_addr).approve(address(bobswap), cur_bob_balance);
uint256 usdc_received = bobswap.sell(token, cur_bob_balance);
require(IERC20(bob_addr).balanceOf(address(this)) == 0, "Incorrect swap");
// uint256 usdc_received = IERC20(token).balanceOf(address(this)) - prev_usdc_balance;
uint256 spent_on_fees = (cur_bob_balance / (10 ** (bob_decimals - usdc_decimals))) - usdc_received;
retval = IERC20(token).transferFrom(owner(), address(this), spent_on_fees);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol";
import "@uniswap/v3-periphery/contracts/interfaces/external/IWETH9.sol";
import "../interfaces/ITransferVerifier.sol";
import "../interfaces/ITreeVerifier.sol";
import "../interfaces/IBatchDepositVerifier.sol";
import "../interfaces/IMintableERC20.sol";
import "../interfaces/IOperatorManager.sol";
import "../interfaces/IERC20Permit.sol";
import "../interfaces/ITokenSeller.sol";
import "../interfaces/IZkBobDirectDepositQueue.sol";
import "../interfaces/IZkBobPool.sol";
import "../interfaces/IBobVault.sol";
import "./utils/Parameters.sol";
import "./utils/ZkBobAccounting.sol";
import "../utils/Ownable.sol";
import "../proxy/EIP1967Admin.sol";
/**
* @title ZkBobPool
* Shielded transactions pool
*/
abstract contract ZkBobPool is IZkBobPool, EIP1967Admin, Ownable, Parameters, ZkBobAccounting {
using SafeERC20 for IERC20;
uint256 internal constant MAX_POOL_ID = 0xffffff;
bytes4 internal constant MESSAGE_PREFIX_COMMON_V1 = 0x00000000;
uint256 internal immutable TOKEN_DENOMINATOR;
uint256 internal constant TOKEN_NUMERATOR = 1000;
uint256 public immutable pool_id;
ITransferVerifier public immutable transfer_verifier;
ITreeVerifier public immutable tree_verifier;
IBatchDepositVerifier public immutable batch_deposit_verifier;
address public immutable token;
IZkBobDirectDepositQueue public immutable direct_deposit_queue;
IOperatorManager public operatorManager;
mapping(uint256 => uint256) public nullifiers;
mapping(uint256 => uint256) public roots;
bytes32 public all_messages_hash;
mapping(address => uint256) public accumulatedFee;
event UpdateOperatorManager(address manager);
event WithdrawFee(address indexed operator, uint256 fee);
event Message(uint256 indexed index, bytes32 indexed hash, bytes message);
constructor(
uint256 __pool_id,
address _token,
ITransferVerifier _transfer_verifier,
ITreeVerifier _tree_verifier,
IBatchDepositVerifier _batch_deposit_verifier,
address _direct_deposit_queue,
uint256 _denominator,
uint256 _precision
)
ZkBobAccounting(_precision)
{
require(__pool_id <= MAX_POOL_ID, "ZkBobPool: exceeds max pool id");
require(Address.isContract(_token), "ZkBobPool: not a contract");
require(Address.isContract(address(_transfer_verifier)), "ZkBobPool: not a contract");
require(Address.isContract(address(_tree_verifier)), "ZkBobPool: not a contract");
require(Address.isContract(address(_batch_deposit_verifier)), "ZkBobPool: not a contract");
require(Address.isContract(_direct_deposit_queue), "ZkBobPool: not a contract");
require(TOKEN_NUMERATOR == 1 || _denominator == 1, "ZkBobPool: incorrect denominator");
pool_id = __pool_id;
token = _token;
transfer_verifier = _transfer_verifier;
tree_verifier = _tree_verifier;
batch_deposit_verifier = _batch_deposit_verifier;
direct_deposit_queue = IZkBobDirectDepositQueue(_direct_deposit_queue);
TOKEN_DENOMINATOR = _denominator;
}
/**
* @dev Throws if called by any account other than the current relayer operator.
*/
modifier onlyOperator() {
require(operatorManager.isOperator(_msgSender()), "ZkBobPool: not an operator");
_;
}
/**
* @dev Initializes pool proxy storage.
* Callable only once and only through EIP1967Proxy constructor / upgradeToAndCall.
* @param _root initial empty merkle tree root.
* @param _tvlCap initial upper cap on the entire pool tvl, 18 decimals.
* @param _dailyDepositCap initial daily limit on the sum of all deposits, 18 decimals.
* @param _dailyWithdrawalCap initial daily limit on the sum of all withdrawals, 18 decimals.
* @param _dailyUserDepositCap initial daily limit on the sum of all per-address deposits, 18 decimals.
* @param _depositCap initial limit on the amount of a single deposit, 18 decimals.
* @param _dailyUserDirectDepositCap initial daily limit on the sum of all per-address direct deposits, 18 decimals.
* @param _directDepositCap initial limit on the amount of a single direct deposit, 18 decimals.
*/
function initialize(
uint256 _root,
uint256 _tvlCap,
uint256 _dailyDepositCap,
uint256 _dailyWithdrawalCap,
uint256 _dailyUserDepositCap,
uint256 _depositCap,
uint256 _dailyUserDirectDepositCap,
uint256 _directDepositCap
)
external
{
require(msg.sender == address(this), "ZkBobPool: not initializer");
require(roots[0] == 0, "ZkBobPool: already initialized");
require(_root != 0, "ZkBobPool: zero root");
roots[0] = _root;
_setLimits(
0,
_tvlCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyWithdrawalCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyUserDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_depositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyUserDirectDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_directDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR
);
}
/**
* @dev Updates used operator manager contract.
* Callable only by the contract owner / proxy admin.
* @param _operatorManager new operator manager implementation.
*/
function setOperatorManager(IOperatorManager _operatorManager) external onlyOwner {
require(address(_operatorManager) != address(0), "ZkBobPool: manager is zero address");
operatorManager = _operatorManager;
emit UpdateOperatorManager(address(_operatorManager));
}
/**
* @dev Tells the denominator for converting pool token into zkBOB units.
*/
function denominator() external view returns (uint256) {
return TOKEN_NUMERATOR == 1 ? TOKEN_DENOMINATOR : (1 << 255) | TOKEN_NUMERATOR;
}
/**
* @dev Tells the current merkle tree index, which will be used for the next operation.
* Each operation increases merkle tree size by 128, so index is equal to the total number of seen operations, multiplied by 128.
* @return next operator merkle index.
*/
function pool_index() external view returns (uint256) {
return _txCount() << 7;
}
function _root() internal view override returns (uint256) {
return roots[_transfer_index()];
}
function _pool_id() internal view override returns (uint256) {
return pool_id;
}
/**
* @dev Converts given amount of tokens into native coins sent to the provided address.
* @param _user native coins receiver address.
* @param _tokenAmount amount to tokens to convert.
* @return actual converted amount, might be less than requested amount.
*/
function _withdrawNative(address _user, uint256 _tokenAmount) internal virtual returns (uint256);
/**
* @dev Performs token transfer using a signed permit signature.
* @param _user token depositor address, should correspond to the signature author.
* @param _nullifier nullifier and permit signature salt to avoid transaction data manipulation.
* @param _tokenAmount amount to tokens to deposit.
*/
function _transferFromByPermit(address _user, uint256 _nullifier, int256 _tokenAmount) internal virtual;
/**
* @dev Perform a zkBob pool transaction.
* Callable only by the current operator.
* Method uses a custom ABI encoding scheme described in CustomABIDecoder.
* Single transact() call performs either deposit, withdrawal or shielded transfer operation.
*/
function transact() external onlyOperator {
address user = msg.sender;
uint256 txType = _tx_type();
if (txType == 0) {
user = _deposit_spender();
} else if (txType == 2) {
user = _memo_receiver();
} else if (txType == 3) {
user = _memo_permit_holder();
}
int256 transfer_token_delta = _transfer_token_amount();
// For private transfers, operator can receive any fee amount. As receiving a fee is basically a withdrawal,
// we should consider operator's tier withdrawal limits respectfully.
// For deposits, fee transfers can be left unbounded, since they are paid from the deposits themselves,
// not from the pool funds.
// For withdrawals, withdrawal amount that is checked against limits for specific user is already inclusive
// of operator's fee, thus there is no need to consider it separately.
(,, uint256 txCount) = _recordOperation(user, transfer_token_delta);
uint256 nullifier = _transfer_nullifier();
{
uint256 _pool_index = txCount << 7;
require(nullifiers[nullifier] == 0, "ZkBobPool: doublespend detected");
require(_transfer_index() <= _pool_index, "ZkBobPool: transfer index out of bounds");
require(transfer_verifier.verifyProof(_transfer_pub(), _transfer_proof()), "ZkBobPool: bad transfer proof");
require(
tree_verifier.verifyProof(_tree_pub(roots[_pool_index]), _tree_proof()), "ZkBobPool: bad tree proof"
);
nullifiers[nullifier] = uint256(keccak256(abi.encodePacked(_transfer_out_commit(), _transfer_delta())));
_pool_index += 128;
roots[_pool_index] = _tree_root_after();
bytes memory message = _memo_message();
// restrict memo message prefix (items count in little endian) to be < 2**16
require(bytes4(message) & 0x0000ffff == MESSAGE_PREFIX_COMMON_V1, "ZkBobPool: bad message prefix");
bytes32 message_hash = keccak256(message);
bytes32 _all_messages_hash = keccak256(abi.encodePacked(all_messages_hash, message_hash));
all_messages_hash = _all_messages_hash;
emit Message(_pool_index, _all_messages_hash, message);
}
uint256 fee = _memo_fee();
int256 token_amount = transfer_token_delta + int256(fee);
int256 energy_amount = _transfer_energy_amount();
require(token_amount % int256(TOKEN_NUMERATOR) == 0, "ZkBobPool: incorrect token amount");
if (txType == 0) {
// Deposit
require(transfer_token_delta > 0 && energy_amount == 0, "ZkBobPool: incorrect deposit amounts");
IERC20(token).safeTransferFrom(
user, address(this), uint256(token_amount) * TOKEN_DENOMINATOR / TOKEN_NUMERATOR
);
} else if (txType == 1) {
// Transfer
require(token_amount == 0 && energy_amount == 0, "ZkBobPool: incorrect transfer amounts");
} else if (txType == 2) {
// Withdraw
require(token_amount <= 0 && energy_amount <= 0, "ZkBobPool: incorrect withdraw amounts");
uint256 native_amount = _memo_native_amount() * TOKEN_DENOMINATOR / TOKEN_NUMERATOR;
uint256 withdraw_amount = uint256(-token_amount) * TOKEN_DENOMINATOR / TOKEN_NUMERATOR;
if (native_amount > 0) {
withdraw_amount -= _withdrawNative(user, native_amount);
}
if (withdraw_amount > 0) {
IERC20(token).safeTransfer(user, withdraw_amount);
}
// energy withdrawals are not yet implemented, any transaction with non-zero energy_amount will revert
// future version of the protocol will support energy withdrawals through negative energy_amount
if (energy_amount < 0) {
revert("ZkBobPool: XP claiming is not yet enabled");
}
} else if (txType == 3) {
// Permittable token deposit
require(transfer_token_delta > 0 && energy_amount == 0, "ZkBobPool: incorrect deposit amounts");
_transferFromByPermit(user, nullifier, token_amount);
} else {
revert("ZkBobPool: Incorrect transaction type");
}
if (fee > 0) {
accumulatedFee[msg.sender] += fee;
}
}
/**
* @dev Appends a batch of direct deposits into a zkBob merkle tree.
* Callable only by the current operator.
* @param _root_after new merkle tree root after append.
* @param _indices list of indices for queued pending deposits.
* @param _out_commit out commitment for output notes serialized from direct deposits.
* @param _batch_deposit_proof snark proof for batch deposit verifier.
* @param _tree_proof snark proof for tree update verifier.
*/
function appendDirectDeposits(
uint256 _root_after,
uint256[] calldata _indices,
uint256 _out_commit,
uint256[8] memory _batch_deposit_proof,
uint256[8] memory _tree_proof
)
external
onlyOperator
{
(uint256 total, uint256 totalFee, uint256 hashsum, bytes memory message) =
direct_deposit_queue.collect(_indices, _out_commit);
(,, uint256 txCount) = _recordOperation(address(0), int256(total));
uint256 _pool_index = txCount << 7;
// verify that _out_commit corresponds to zero output account + 16 chosen notes + 111 empty notes
require(
batch_deposit_verifier.verifyProof([hashsum], _batch_deposit_proof), "ZkBobPool: bad batch deposit proof"
);
uint256[3] memory tree_pub = [roots[_pool_index], _root_after, _out_commit];
require(tree_verifier.verifyProof(tree_pub, _tree_proof), "ZkBobPool: bad tree proof");
_pool_index += 128;
roots[_pool_index] = _root_after;
bytes32 message_hash = keccak256(message);
bytes32 _all_messages_hash = keccak256(abi.encodePacked(all_messages_hash, message_hash));
all_messages_hash = _all_messages_hash;
if (totalFee > 0) {
accumulatedFee[msg.sender] += totalFee;
}
emit Message(_pool_index, _all_messages_hash, message);
}
/**
* @dev Records submitted direct deposit into the users limits.
* Callable only by the direct deposit queue.
* @param _sender direct deposit sender.
* @param _amount direct deposit amount in zkBOB units.
*/
function recordDirectDeposit(address _sender, uint256 _amount) external {
require(msg.sender == address(direct_deposit_queue), "ZkBobPool: not authorized");
_checkDirectDepositLimits(_sender, _amount);
}
/**
* @dev Withdraws accumulated fee on behalf of an operator.
* Callable only by the operator itself, or by a pre-configured operator fee receiver address.
* @param _operator address of an operator account to withdraw fee from.
* @param _to address of the accumulated fee tokens receiver.
*/
function withdrawFee(address _operator, address _to) external {
require(
_operator == msg.sender || operatorManager.isOperatorFeeReceiver(_operator, msg.sender),
"ZkBobPool: not authorized"
);
uint256 fee = accumulatedFee[_operator] * TOKEN_DENOMINATOR / TOKEN_NUMERATOR;
require(fee > 0, "ZkBobPool: no fee to withdraw");
IERC20(token).safeTransfer(_to, fee);
accumulatedFee[_operator] = 0;
emit WithdrawFee(_operator, fee);
}
/**
* @dev Updates pool usage limits.
* Callable only by the contract owner / proxy admin.
* @param _tier pool limits tier (0-254).
* @param _tvlCap new upper cap on the entire pool tvl, 18 decimals.
* @param _dailyDepositCap new daily limit on the sum of all deposits, 18 decimals.
* @param _dailyWithdrawalCap new daily limit on the sum of all withdrawals, 18 decimals.
* @param _dailyUserDepositCap new daily limit on the sum of all per-address deposits, 18 decimals.
* @param _depositCap new limit on the amount of a single deposit, 18 decimals.
* @param _dailyUserDirectDepositCap new daily limit on the sum of all per-address direct deposits, 18 decimals.
* @param _directDepositCap new limit on the amount of a single direct deposit, 18 decimals.
*/
function setLimits(
uint8 _tier,
uint256 _tvlCap,
uint256 _dailyDepositCap,
uint256 _dailyWithdrawalCap,
uint256 _dailyUserDepositCap,
uint256 _depositCap,
uint256 _dailyUserDirectDepositCap,
uint256 _directDepositCap
)
external
onlyOwner
{
_setLimits(
_tier,
_tvlCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyWithdrawalCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyUserDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_depositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_dailyUserDirectDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR,
_directDepositCap / TOKEN_DENOMINATOR * TOKEN_NUMERATOR
);
}
/**
* @dev Resets daily limit usage for the current day.
* Callable only by the contract owner / proxy admin.
* @param _tier tier id to reset daily limits for.
*/
function resetDailyLimits(uint8 _tier) external onlyOwner {
_resetDailyLimits(_tier);
}
/**
* @dev Updates users limit tiers.
* Callable only by the contract owner / proxy admin.
* @param _tier pool limits tier (0-255).
* 0 is the default tier.
* 1-254 are custom pool limit tiers, configured at runtime.
* 255 is the special tier with zero limits, used to effectively prevent some address from accessing the pool.
* @param _users list of user account addresses to assign a tier for.
*/
function setUsersTier(uint8 _tier, address[] memory _users) external onlyOwner {
_setUsersTier(_tier, _users);
}
/**
* @dev Tells if caller is the contract owner.
* Gives ownership rights to the proxy admin as well.
* @return true, if caller is the contract owner or proxy admin.
*/
function _isOwner() internal view override returns (bool) {
return super._isOwner() || _admin() == _msgSender();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "./ZkBobPool.sol";
/**
* @title ZkBobTokenSellerMixin
*/
abstract contract ZkBobTokenSellerMixin is ZkBobPool {
using SafeERC20 for IERC20;
ITokenSeller public tokenSeller;
event UpdateTokenSeller(address seller);
/**
* @dev Updates token seller contract used for native coin withdrawals.
* Callable only by the contract owner / proxy admin.
* @param _seller new token seller contract implementation. address(0) will deactivate native withdrawals.
*/
function setTokenSeller(address _seller) external onlyOwner {
tokenSeller = ITokenSeller(_seller);
emit UpdateTokenSeller(_seller);
}
// @inheritdoc ZkBobPool
function _withdrawNative(address _user, uint256 _tokenAmount) internal override returns (uint256) {
ITokenSeller seller = tokenSeller;
if (address(seller) != address(0)) {
IERC20(token).safeTransfer(address(seller), _tokenAmount);
(, uint256 refunded) = seller.sellForETH(_user, _tokenAmount);
return _tokenAmount - refunded;
}
return 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "../interfaces/IUSDCPermit.sol";
import "./ZkBobPool.sol";
/**
* @title ZkBobUSDCPermitMixin
*/
abstract contract ZkBobUSDCPermitMixin is ZkBobPool {
// @inheritdoc ZkBobPool
function _transferFromByPermit(address _user, uint256 _nullifier, int256 _tokenAmount) internal override {
(uint8 v, bytes32 r, bytes32 s) = _permittable_deposit_signature();
IUSDCPermit(token).transferWithAuthorization(
_user,
address(this),
uint256(_tokenAmount) * TOKEN_DENOMINATOR / TOKEN_NUMERATOR,
0,
_memo_permit_deadline(),
bytes32(_nullifier),
v,
r,
s
);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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
* ====
*
* [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://diligence.consensys.net/posts/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.5.11/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
// OpenZeppelin Contracts (last updated v4.6.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 v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-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;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
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));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
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");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Immutable state
/// @notice Functions that return immutable state of the router
interface IPeripheryImmutableState {
/// @return Returns the address of the Uniswap V3 factory
function factory() external view returns (address);
/// @return Returns the address of WETH9
function WETH9() external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.8.15;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
/// @title Interface for WETH9
interface IWETH9 is IERC20 {
/// @notice Deposit ether to get wrapped ether
function deposit() external payable;
/// @notice Withdraw wrapped ether to get ether
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface ITransferVerifier {
function verifyProof(uint256[5] memory input, uint256[8] memory p) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface ITreeVerifier {
function verifyProof(uint256[3] memory input, uint256[8] memory p) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface IBatchDepositVerifier {
function verifyProof(uint256[1] memory input, uint256[8] memory p) external view returns (bool);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
interface IMintableERC20 {
function mint(address to, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface IOperatorManager {
function isOperator(address _addr) external view returns (bool);
function isOperatorFeeReceiver(address _operator, address _addr) external view returns (bool);
function operatorURI() external view returns (string memory);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
)
external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external view returns (bytes32);
function SALTED_PERMIT_TYPEHASH() external view returns (bytes32);
function receiveWithPermit(
address _holder,
uint256 _value,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
)
external;
function receiveWithSaltedPermit(
address _holder,
uint256 _value,
uint256 _deadline,
bytes32 _salt,
uint8 _v,
bytes32 _r,
bytes32 _s
)
external;
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
interface ITokenSeller {
/**
* @dev Sells tokens for ETH.
* Prior to calling this function, contract balance of token0 should be greater than or equal to the sold amount.
* @param _receiver native ETH receiver.
* @param _amount amount of tokens to sell.
* @return (received eth amount, refunded token amount).
*/
function sellForETH(address _receiver, uint256 _amount) external returns (uint256, uint256);
/**
* @dev Estimates amount of received ETH, when selling given amount of tokens via sellForETH function.
* @param _amount amount of tokens to sell.
* @return received eth amount.
*/
function quoteSellForETH(uint256 _amount) external returns (uint256);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
interface IZkBobDirectDepositQueue {
/**
* @dev Collects aggregated info about submitted direct deposits and marks them as completed.
* Callable only by the zkBOB pool contract.
* @param _indices list of direct deposit indices to process, max of 16 indices are allowed.
* @param _out_commit pre-calculated out commitment associated with the given deposits.
* @return total sum of deposit amounts, not counting fees.
* @return totalFee sum of deposit fees.
* @return hashsum hashsum over all retrieved direct deposits.
* @return message memo message to record into the tree.
*/
function collect(
uint256[] calldata _indices,
uint256 _out_commit
)
external
returns (uint256 total, uint256 totalFee, uint256 hashsum, bytes memory message);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
interface IZkBobPool {
function pool_id() external view returns (uint256);
function recordDirectDeposit(address _sender, uint256 _amount) external;
}// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;
interface IBobVault {
function buy(address _token, uint256 _amount) external returns (uint256);
function sell(address _token, uint256 _amount) external returns (uint256);
function swap(address _inToken, address _outToken, uint256 _amount) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./CustomABIDecoder.sol";
abstract contract Parameters is CustomABIDecoder {
uint256 constant R = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
bytes32 constant S_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
function _root() internal view virtual returns (uint256);
function _pool_id() internal view virtual returns (uint256);
function _transfer_pub() internal view returns (uint256[5] memory r) {
r[0] = _root();
r[1] = _transfer_nullifier();
r[2] = _transfer_out_commit();
r[3] = _transfer_delta() + (_pool_id() << (transfer_delta_size * 8));
r[4] = uint256(keccak256(_memo_data())) % R;
}
function _tree_pub(uint256 _root_before) internal view returns (uint256[3] memory r) {
r[0] = _root_before;
r[1] = _tree_root_after();
r[2] = _transfer_out_commit();
}
// NOTE only valid in the context of normal deposit (tx_type=0)
function _deposit_spender() internal pure returns (address) {
(bytes32 r, bytes32 vs) = _sign_r_vs();
return ECDSA.recover(ECDSA.toEthSignedMessageHash(bytes32(_transfer_nullifier())), r, vs);
}
// NOTE only valid in the context of permittable token deposit (tx_type=3)
function _permittable_deposit_signature() internal pure returns (uint8, bytes32, bytes32) {
(bytes32 r, bytes32 vs) = _sign_r_vs();
return (uint8((uint256(vs) >> 255) + 27), r, vs & S_MASK);
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
import "../../interfaces/IKycProvidersManager.sol";
import "./KycProvidersManagerStorage.sol";
/**
* @title ZkBobAccounting
* @dev On chain accounting for zkBob operations, limits and stats.
* Units: 1 BOB = 1e18 wei = 1e9 zkBOB units
* Limitations: Contract will only work correctly as long as pool tvl does not exceed 4.7e12 BOB (4.7 trillion)
* and overall transaction count does not exceed 4.3e9 (4.3 billion). Pool usage limits cannot exceed 4.3e9 BOB (4.3 billion) per day.
*/
contract ZkBobAccounting is KycProvidersManagerStorage {
uint256 internal constant SLOT_DURATION = 1 hours;
uint256 internal constant DAY_SLOTS = 1 days / SLOT_DURATION;
uint256 internal constant WEEK_SLOTS = 1 weeks / SLOT_DURATION;
uint256 internal immutable PRECISION;
struct Slot0 {
// max seen average tvl over period of at least 1 week (granularity of 1e9), might not be precise
// max possible tvl - type(uint56).max * 1e9 zkBOB units ~= 7.2e16 BOB
uint56 maxWeeklyAvgTvl;
// max number of pool interactions over 1 week, might not be precise
// max possible tx count - type(uint32).max ~= 4.3e9 transactions
uint32 maxWeeklyTxCount;
// 1 week behind snapshot time slot (granularity of 1 hour)
// max possible timestamp - Dec 08 3883
uint24 tailSlot;
// active snapshot time slot (granularity of 1 hour)
// max possible timestamp - Dec 08 3883
uint24 headSlot;
// cumulative sum of tvl over txCount interactions (granularity of 1e9)
// max possible cumulative tvl ~= type(uint32).max * type(uint56).max = 4.3e9 transactions * 7.2e16 BOB
uint88 cumTvl;
// number of successful pool interactions since launch
// max possible tx count - type(uint32).max ~= 4.3e9 transactions
uint32 txCount;
}
struct Slot1 {
// current pool tvl (granularity of 1)
// max possible tvl - type(uint72).max * 1 zkBOB units ~= 4.7e21 zkBOB units ~= 4.7e12 BOB
uint72 tvl;
}
struct Tier {
TierLimits limits;
TierStats stats;
}
struct TierLimits {
// max cap on the entire pool tvl (granularity of 1e9)
// max possible cap - type(uint56).max * 1e9 zkBOB units ~= 7.2e16 BOB
uint56 tvlCap;
// max cap on the daily deposits sum (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 dailyDepositCap;
// max cap on the daily withdrawal sum (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 dailyWithdrawalCap;
// max cap on the daily deposits sum for single user (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 dailyUserDepositCap;
// max cap on a single deposit (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 depositCap;
// max cap on a single direct deposit (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 directDepositCap;
// max cap on the daily direct deposits sum for single user (granularity of 1e9)
// max possible cap - type(uint32).max * 1e9 zkBOB units ~= 4.3e9 BOB
uint32 dailyUserDirectDepositCap;
}
struct TierStats {
uint16 day; // last update day number
uint72 dailyDeposit; // sum of all deposits during given day
uint72 dailyWithdrawal; // sum of all withdrawals during given day
}
struct Snapshot {
uint24 nextSlot; // next slot to from the queue
uint32 txCount; // number of successful pool interactions since launch at the time of the snapshot
uint88 cumTvl; // cumulative sum of tvl over txCount interactions (granularity of 1e9)
}
struct UserStats {
uint16 day; // last update day number
uint72 dailyDeposit; // sum of user deposits during given day
uint8 tier; // user limits tier, 0 being the default tier
uint72 dailyDirectDeposit; // sum of user direct deposits during given day
}
struct Limits {
uint256 tvlCap;
uint256 tvl;
uint256 dailyDepositCap;
uint256 dailyDepositCapUsage;
uint256 dailyWithdrawalCap;
uint256 dailyWithdrawalCapUsage;
uint256 dailyUserDepositCap;
uint256 dailyUserDepositCapUsage;
uint256 depositCap;
uint8 tier;
uint256 dailyUserDirectDepositCap;
uint256 dailyUserDirectDepositCapUsage;
uint256 directDepositCap;
}
Slot0 private slot0;
Slot1 private slot1;
mapping(uint256 => Tier) private tiers; // pool limits and usage per tier
mapping(uint256 => Snapshot) private snapshots; // single linked list of hourly snapshots
mapping(address => UserStats) private userStats;
event UpdateLimits(uint8 indexed tier, TierLimits limits);
event UpdateTier(address user, uint8 tier);
constructor(uint256 _precision) {
PRECISION = _precision;
}
/**
* @dev Returns currently configured limits and remaining quotas for the given user as of the current block.
* @param _user user for which to retrieve limits.
* @return limits (denominated in zkBOB units = 1e-9 BOB)
*/
function getLimitsFor(address _user) external view returns (Limits memory) {
Slot1 memory s1 = slot1;
UserStats memory us = userStats[_user];
uint8 tier = _adjustConfiguredTierForUser(_user, us.tier);
Tier storage t = tiers[tier];
TierLimits memory tl = t.limits;
TierStats memory ts = t.stats;
uint24 curSlot = uint24(block.timestamp / SLOT_DURATION);
uint24 today = curSlot / uint24(DAY_SLOTS);
return Limits({
tvlCap: tl.tvlCap * PRECISION,
tvl: s1.tvl,
dailyDepositCap: tl.dailyDepositCap * PRECISION,
dailyDepositCapUsage: (ts.day == today) ? ts.dailyDeposit : 0,
dailyWithdrawalCap: tl.dailyWithdrawalCap * PRECISION,
dailyWithdrawalCapUsage: (ts.day == today) ? ts.dailyWithdrawal : 0,
dailyUserDepositCap: tl.dailyUserDepositCap * PRECISION,
dailyUserDepositCapUsage: (us.day == today) ? us.dailyDeposit : 0,
depositCap: tl.depositCap * PRECISION,
tier: tier,
dailyUserDirectDepositCap: tl.dailyUserDirectDepositCap * PRECISION,
dailyUserDirectDepositCapUsage: (us.day == today) ? us.dailyDirectDeposit : 0,
directDepositCap: tl.directDepositCap * PRECISION
});
}
function _recordOperation(
address _user,
int256 _txAmount
)
internal
returns (uint56 maxWeeklyAvgTvl, uint32 maxWeeklyTxCount, uint256 txCount)
{
Slot0 memory s0 = slot0;
Slot1 memory s1 = slot1;
uint24 curSlot = uint24(block.timestamp / SLOT_DURATION);
txCount = uint256(s0.txCount);
// for full correctness, next line should use "while" instead of "if"
// however, in order to keep constant gas usage, "if" is being used
// this can lead to a longer sliding window (> 1 week) in some cases,
// but eventually it will converge back to the 1 week target
if (s0.txCount > 0 && curSlot - s0.tailSlot > WEEK_SLOTS) {
// if tail is more than 1 week behind, we move tail pointer to the next snapshot
Snapshot memory sn = snapshots[s0.tailSlot];
delete snapshots[s0.tailSlot];
s0.tailSlot = sn.nextSlot;
uint32 weeklyTxCount = s0.txCount - sn.txCount;
if (weeklyTxCount > s0.maxWeeklyTxCount) {
s0.maxWeeklyTxCount = weeklyTxCount;
}
uint56 avgTvl = uint56((s0.cumTvl - sn.cumTvl) / weeklyTxCount);
if (avgTvl > s0.maxWeeklyAvgTvl) {
s0.maxWeeklyAvgTvl = avgTvl;
}
}
if (s0.headSlot < curSlot) {
snapshots[s0.headSlot] = Snapshot(curSlot, s0.txCount, s0.cumTvl);
s0.headSlot = curSlot;
}
// update head stats
s0.cumTvl += s1.tvl / uint72(PRECISION);
s0.txCount++;
if (_txAmount != 0) {
_processTVLChange(s1, _user, _txAmount);
}
slot0 = s0;
return (s0.maxWeeklyAvgTvl, s0.maxWeeklyTxCount, txCount);
}
function _processTVLChange(Slot1 memory s1, address _user, int256 _txAmount) internal {
// short path for direct deposits batch processing
if (_user == address(0) && _txAmount > 0) {
slot1.tvl += uint72(uint256(_txAmount));
return;
}
uint16 curDay = uint16(block.timestamp / SLOT_DURATION / DAY_SLOTS);
UserStats memory us = userStats[_user];
Tier storage t = tiers[_adjustConfiguredTierForUser(_user, us.tier)];
TierLimits memory tl = t.limits;
TierStats memory ts = t.stats;
if (_txAmount > 0) {
uint256 depositAmount = uint256(_txAmount);
s1.tvl += uint72(depositAmount);
// check all sorts of limits when processing a deposit
require(depositAmount <= uint256(tl.depositCap) * PRECISION, "ZkBobAccounting: single deposit cap exceeded");
require(uint256(s1.tvl) <= uint256(tl.tvlCap) * PRECISION, "ZkBobAccounting: tvl cap exceeded");
if (curDay > us.day) {
// user snapshot is outdated, day number and daily sum could be reset
// original user's tier (0) is preserved
userStats[_user] =
UserStats({day: curDay, dailyDeposit: uint72(depositAmount), tier: us.tier, dailyDirectDeposit: 0});
} else {
us.dailyDeposit += uint72(depositAmount);
require(
uint256(us.dailyDeposit) <= uint256(tl.dailyUserDepositCap) * PRECISION,
"ZkBobAccounting: daily user deposit cap exceeded"
);
userStats[_user] = us;
}
if (curDay > ts.day) {
// latest deposit was on an earlier day, reset daily withdrawal sum
ts = TierStats({day: curDay, dailyDeposit: uint72(depositAmount), dailyWithdrawal: 0});
} else {
ts.dailyDeposit += uint72(depositAmount);
require(
uint256(ts.dailyDeposit) <= uint256(tl.dailyDepositCap) * PRECISION,
"ZkBobAccounting: daily deposit cap exceeded"
);
}
} else {
uint256 withdrawAmount = uint256(-_txAmount);
require(withdrawAmount <= type(uint32).max * PRECISION, "ZkBobAccounting: withdrawal amount too large");
s1.tvl -= uint72(withdrawAmount);
if (curDay > ts.day) {
// latest withdrawal was on an earlier day, reset daily deposit sum
ts = TierStats({day: curDay, dailyDeposit: 0, dailyWithdrawal: uint72(withdrawAmount)});
} else {
ts.dailyWithdrawal += uint72(withdrawAmount);
require(
uint256(ts.dailyWithdrawal) <= uint256(tl.dailyWithdrawalCap) * PRECISION,
"ZkBobAccounting: daily withdrawal cap exceeded"
);
}
}
slot1 = s1;
t.stats = ts;
}
function _checkDirectDepositLimits(address _user, uint256 _amount) internal {
uint16 curDay = uint16(block.timestamp / SLOT_DURATION / DAY_SLOTS);
UserStats memory us = userStats[_user];
TierLimits memory tl = tiers[_adjustConfiguredTierForUser(_user, us.tier)].limits;
// check all sorts of limits when processing a deposit
require(
_amount <= uint256(tl.directDepositCap) * PRECISION, "ZkBobAccounting: single direct deposit cap exceeded"
);
if (curDay > us.day) {
// user snapshot is outdated, day number and daily sum could be reset
// original user's tier (0) is preserved
us = UserStats({day: curDay, dailyDeposit: 0, tier: us.tier, dailyDirectDeposit: uint72(_amount)});
} else {
us.dailyDirectDeposit += uint72(_amount);
require(
uint256(us.dailyDirectDeposit) <= uint256(tl.dailyUserDirectDepositCap) * PRECISION,
"ZkBobAccounting: daily user direct deposit cap exceeded"
);
}
userStats[_user] = us;
}
function _resetDailyLimits(uint8 _tier) internal {
delete tiers[_tier].stats;
}
function _setLimits(
uint8 _tier,
uint256 _tvlCap,
uint256 _dailyDepositCap,
uint256 _dailyWithdrawalCap,
uint256 _dailyUserDepositCap,
uint256 _depositCap,
uint256 _dailyUserDirectDepositCap,
uint256 _directDepositCap
)
internal
{
require(_tier < 255, "ZkBobAccounting: invalid limit tier");
require(_depositCap > 0, "ZkBobAccounting: zero deposit cap");
require(_tvlCap <= type(uint56).max * PRECISION, "ZkBobAccounting: tvl cap too large");
require(_dailyDepositCap <= type(uint32).max * PRECISION, "ZkBobAccounting: daily deposit cap too large");
require(_dailyWithdrawalCap <= type(uint32).max * PRECISION, "ZkBobAccounting: daily withdrawal cap too large");
require(_dailyUserDepositCap >= _depositCap, "ZkBobAccounting: daily user deposit cap too low");
require(_dailyDepositCap >= _dailyUserDepositCap, "ZkBobAccounting: daily deposit cap too low");
require(_tvlCap >= _dailyDepositCap, "ZkBobAccounting: tvl cap too low");
require(_dailyWithdrawalCap > 0, "ZkBobAccounting: zero daily withdrawal cap");
require(
_dailyUserDirectDepositCap >= _directDepositCap, "ZkBobAccounting: daily user direct deposit cap too low"
);
TierLimits memory tl = TierLimits({
tvlCap: uint56(_tvlCap / PRECISION),
dailyDepositCap: uint32(_dailyDepositCap / PRECISION),
dailyWithdrawalCap: uint32(_dailyWithdrawalCap / PRECISION),
dailyUserDepositCap: uint32(_dailyUserDepositCap / PRECISION),
depositCap: uint32(_depositCap / PRECISION),
dailyUserDirectDepositCap: uint32(_dailyUserDirectDepositCap / PRECISION),
directDepositCap: uint32(_directDepositCap / PRECISION)
});
tiers[_tier].limits = tl;
emit UpdateLimits(_tier, tl);
}
// Tier is set as per the KYC Providers Manager recommendation only in the case if no
// specific tier assigned to the user
function _adjustConfiguredTierForUser(address _user, uint8 _configuredTier) internal view returns (uint8) {
IKycProvidersManager kycProvidersMgr = kycProvidersManager();
if (_configuredTier == 0 && address(kycProvidersMgr) != address(0)) {
(bool kycPassed, uint8 tier) = kycProvidersMgr.getIfKYCpassedAndTier(_user);
if (kycPassed && tiers[tier].limits.tvlCap > 0) {
return tier;
}
}
return _configuredTier;
}
function _setUsersTier(uint8 _tier, address[] memory _users) internal {
require(
_tier == 255 || tiers[uint256(_tier)].limits.tvlCap > 0, "ZkBobAccounting: non-existing pool limits tier"
);
for (uint256 i = 0; i < _users.length; ++i) {
address user = _users[i];
userStats[user].tier = _tier;
emit UpdateTier(user, _tier);
}
}
function _txCount() internal view returns (uint256) {
return slot0.txCount;
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
import "@openzeppelin/contracts/access/Ownable.sol" as OZOwnable;
/**
* @title Ownable
*/
contract Ownable is OZOwnable.Ownable {
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view override {
require(_isOwner(), "Ownable: caller is not the owner");
}
/**
* @dev Tells if caller is the contract owner.
* @return true, if caller is the contract owner.
*/
function _isOwner() internal view virtual returns (bool) {
return owner() == _msgSender();
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
/**
* @title EIP1967Admin
* @dev Upgradeable proxy pattern implementation according to minimalistic EIP1967.
*/
contract EIP1967Admin {
// EIP 1967
// bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)
uint256 internal constant EIP1967_ADMIN_STORAGE = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
modifier onlyAdmin() {
require(msg.sender == _admin(), "EIP1967Admin: not an admin");
_;
}
function _admin() internal view returns (address res) {
assembly {
res := sload(EIP1967_ADMIN_STORAGE)
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
interface IUSDCPermit {
function transferWithAuthorization(
address from,
address to,
uint256 value,
uint256 validAfter,
uint256 validBefore,
bytes32 nonce,
uint8 v,
bytes32 r,
bytes32 s
)
external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-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: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @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) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract CustomABIDecoder {
uint256 constant transfer_nullifier_pos = 4;
uint256 constant transfer_nullifier_size = 32;
uint256 constant uint256_size = 32;
function _loaduint256(uint256 pos) internal pure returns (uint256 r) {
assembly {
r := calldataload(pos)
}
}
function _transfer_nullifier() internal pure returns (uint256 r) {
r = _loaduint256(transfer_nullifier_pos);
}
uint256 constant transfer_out_commit_pos = transfer_nullifier_pos + transfer_nullifier_size;
uint256 constant transfer_out_commit_size = 32;
function _transfer_out_commit() internal pure returns (uint256 r) {
r = _loaduint256(transfer_out_commit_pos);
}
uint256 constant transfer_index_pos = transfer_out_commit_pos + transfer_out_commit_size;
uint256 constant transfer_index_size = 6;
function _transfer_index() internal pure returns (uint48 r) {
r = uint48(_loaduint256(transfer_index_pos + transfer_index_size - uint256_size));
}
uint256 constant transfer_energy_amount_pos = transfer_index_pos + transfer_index_size;
uint256 constant transfer_energy_amount_size = 14;
function _transfer_energy_amount() internal pure returns (int112 r) {
r = int112(uint112(_loaduint256(transfer_energy_amount_pos + transfer_energy_amount_size - uint256_size)));
}
uint256 constant transfer_token_amount_pos = transfer_energy_amount_pos + transfer_energy_amount_size;
uint256 constant transfer_token_amount_size = 8;
function _transfer_token_amount() internal pure returns (int64 r) {
r = int64(uint64(_loaduint256(transfer_token_amount_pos + transfer_token_amount_size - uint256_size)));
}
uint256 constant transfer_proof_pos = transfer_token_amount_pos + transfer_token_amount_size;
uint256 constant transfer_proof_size = 256;
function _transfer_proof() internal pure returns (uint256[8] calldata r) {
uint256 pos = transfer_proof_pos;
assembly {
r := pos
}
}
uint256 constant tree_root_after_pos = transfer_proof_pos + transfer_proof_size;
uint256 constant tree_root_after_size = 32;
function _tree_root_after() internal pure returns (uint256 r) {
r = _loaduint256(tree_root_after_pos);
}
uint256 constant tree_proof_pos = tree_root_after_pos + tree_root_after_size;
uint256 constant tree_proof_size = 256;
function _tree_proof() internal pure returns (uint256[8] calldata r) {
uint256 pos = tree_proof_pos;
assembly {
r := pos
}
}
uint256 constant tx_type_pos = tree_proof_pos + tree_proof_size;
uint256 constant tx_type_size = 2;
uint256 constant tx_type_mask = (1 << (tx_type_size * 8)) - 1;
function _tx_type() internal pure returns (uint256 r) {
r = _loaduint256(tx_type_pos + tx_type_size - uint256_size) & tx_type_mask;
}
uint256 constant memo_data_size_pos = tx_type_pos + tx_type_size;
uint256 constant memo_data_size_size = 2;
uint256 constant memo_data_size_mask = (1 << (memo_data_size_size * 8)) - 1;
uint256 constant memo_data_pos = memo_data_size_pos + memo_data_size_size;
function _memo_data_size() internal pure returns (uint256 r) {
r = _loaduint256(memo_data_size_pos + memo_data_size_size - uint256_size) & memo_data_size_mask;
}
function _memo_data() internal pure returns (bytes calldata r) {
uint256 offset = memo_data_pos;
uint256 length = _memo_data_size();
assembly {
r.offset := offset
r.length := length
}
}
function _sign_r_vs_pos() internal pure returns (uint256) {
return memo_data_pos + _memo_data_size();
}
uint256 constant sign_r_vs_size = 64;
function _sign_r_vs() internal pure returns (bytes32 r, bytes32 vs) {
uint256 offset = _sign_r_vs_pos();
assembly {
r := calldataload(offset)
vs := calldataload(add(offset, 32))
}
}
uint256 constant transfer_delta_size =
transfer_index_size + transfer_energy_amount_size + transfer_token_amount_size;
uint256 constant transfer_delta_mask = (1 << (transfer_delta_size * 8)) - 1;
function _transfer_delta() internal pure returns (uint256 r) {
r = _loaduint256(transfer_index_pos + transfer_delta_size - uint256_size) & transfer_delta_mask;
}
function _memo_fixed_size() internal pure returns (uint256 r) {
uint256 t = _tx_type();
if (t == 0 || t == 1) {
// fee
// 8
r = 8;
} else if (t == 2) {
// fee + native amount + recipient
// 8 + 8 + 20
r = 36;
} else if (t == 3) {
// fee + deadline + address
// 8 + 8 + 20
r = 36;
} else {
revert();
}
}
function _memo_message() internal pure returns (bytes calldata r) {
uint256 memo_fixed_size = _memo_fixed_size();
uint256 offset = memo_data_pos + memo_fixed_size;
uint256 length = _memo_data_size() - memo_fixed_size;
assembly {
r.offset := offset
r.length := length
}
}
uint256 constant memo_fee_pos = memo_data_pos;
uint256 constant memo_fee_size = 8;
uint256 constant memo_fee_mask = (1 << (memo_fee_size * 8)) - 1;
function _memo_fee() internal pure returns (uint256 r) {
r = _loaduint256(memo_fee_pos + memo_fee_size - uint256_size) & memo_fee_mask;
}
// Withdraw specific data
uint256 constant memo_native_amount_pos = memo_fee_pos + memo_fee_size;
uint256 constant memo_native_amount_size = 8;
uint256 constant memo_native_amount_mask = (1 << (memo_native_amount_size * 8)) - 1;
function _memo_native_amount() internal pure returns (uint256 r) {
r = _loaduint256(memo_native_amount_pos + memo_native_amount_size - uint256_size) & memo_native_amount_mask;
}
uint256 constant memo_receiver_pos = memo_native_amount_pos + memo_native_amount_size;
uint256 constant memo_receiver_size = 20;
function _memo_receiver() internal pure returns (address r) {
r = address(uint160(_loaduint256(memo_receiver_pos + memo_receiver_size - uint256_size)));
}
// Permittable token deposit specific data
uint256 constant memo_permit_deadline_pos = memo_fee_pos + memo_fee_size;
uint256 constant memo_permit_deadline_size = 8;
function _memo_permit_deadline() internal pure returns (uint64 r) {
r = uint64(_loaduint256(memo_permit_deadline_pos + memo_permit_deadline_size - uint256_size));
}
uint256 constant memo_permit_holder_pos = memo_permit_deadline_pos + memo_permit_deadline_size;
uint256 constant memo_permit_holder_size = 20;
function _memo_permit_holder() internal pure returns (address r) {
r = address(uint160(_loaduint256(memo_permit_holder_pos + memo_permit_holder_size - uint256_size)));
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
interface IKycProvidersManager {
function getIfKYCpassedAndTier(address _user) external view returns (bool, uint8);
}// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.15;
import "@openzeppelin/contracts/utils/Address.sol";
import "../../interfaces/IKycProvidersManager.sol";
import "../../utils/Ownable.sol";
contract KycProvidersManagerStorage is Ownable {
// In order to avoid shifting storage slots by defining a new variable in
// the contract, KYC Providers Manager will be accessed through specifying
// a free slot explicitly. Similar approach is used in EIP1967.
//
// bytes32(uint256(keccak256('zkBob.ZkBobAccounting.kycProvidersManager')) - 1)
uint256 internal constant KYC_PROVIDER_MANAGER_STORAGE =
0x06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f64;
event UpdateKYCProvidersManager(address manager);
/**
* @dev Tells the KYC Providers Manager contract address.
* @return res the manager address.
*/
function kycProvidersManager() public view returns (IKycProvidersManager res) {
assembly {
res := sload(KYC_PROVIDER_MANAGER_STORAGE)
}
}
/**
* @dev Updates kyc providers manager contract.
* Callable only by the contract owner / proxy admin.
* @param _kycProvidersManager new operator manager implementation.
*/
function setKycProvidersManager(IKycProvidersManager _kycProvidersManager) external onlyOwner {
require(Address.isContract(address(_kycProvidersManager)), "KycProvidersManagerStorage: not a contract");
assembly {
sstore(KYC_PROVIDER_MANAGER_STORAGE, _kycProvidersManager)
}
emit UpdateKYCProvidersManager(address(_kycProvidersManager));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.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 `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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 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 10, 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 * 8) < value ? 1 : 0);
}
}
}{
"remappings": [
"@base58-solidity/=lib/base58-solidity/contracts/",
"@gnosis/=lib/@gnosis/",
"@gnosis/auction/=lib/@gnosis/auction/contracts/",
"@openzeppelin/=lib/@openzeppelin/contracts/",
"@openzeppelin/contracts/=lib/@openzeppelin/contracts/contracts/",
"@uniswap/=lib/@uniswap/",
"base58-solidity/=lib/base58-solidity/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {
"lib/base58-solidity/contracts/Base58.sol": {
"Base58": "0xcb11bf4543efeb83d7d2fb99f6b9dd040d7a6eaa"
},
"src/libraries/ZkAddress.sol": {
"ZkAddress": "0x43830a424783657b92913bef78ec839d2085fcf9"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"__pool_id","type":"uint256"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"contract ITransferVerifier","name":"_transfer_verifier","type":"address"},{"internalType":"contract ITreeVerifier","name":"_tree_verifier","type":"address"},{"internalType":"contract IBatchDepositVerifier","name":"_batch_deposit_verifier","type":"address"},{"internalType":"address","name":"_direct_deposit_queue","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"Message","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"UpdateKYCProvidersManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"tier","type":"uint8"},{"components":[{"internalType":"uint56","name":"tvlCap","type":"uint56"},{"internalType":"uint32","name":"dailyDepositCap","type":"uint32"},{"internalType":"uint32","name":"dailyWithdrawalCap","type":"uint32"},{"internalType":"uint32","name":"dailyUserDepositCap","type":"uint32"},{"internalType":"uint32","name":"depositCap","type":"uint32"},{"internalType":"uint32","name":"directDepositCap","type":"uint32"},{"internalType":"uint32","name":"dailyUserDirectDepositCap","type":"uint32"}],"indexed":false,"internalType":"struct ZkBobAccounting.TierLimits","name":"limits","type":"tuple"}],"name":"UpdateLimits","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"UpdateOperatorManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint8","name":"tier","type":"uint8"}],"name":"UpdateTier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"seller","type":"address"}],"name":"UpdateTokenSeller","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"WithdrawFee","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accumulatedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"all_messages_hash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_root_after","type":"uint256"},{"internalType":"uint256[]","name":"_indices","type":"uint256[]"},{"internalType":"uint256","name":"_out_commit","type":"uint256"},{"internalType":"uint256[8]","name":"_batch_deposit_proof","type":"uint256[8]"},{"internalType":"uint256[8]","name":"_tree_proof","type":"uint256[8]"}],"name":"appendDirectDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batch_deposit_verifier","outputs":[{"internalType":"contract IBatchDepositVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"denominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"direct_deposit_queue","outputs":[{"internalType":"contract IZkBobDirectDepositQueue","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getLimitsFor","outputs":[{"components":[{"internalType":"uint256","name":"tvlCap","type":"uint256"},{"internalType":"uint256","name":"tvl","type":"uint256"},{"internalType":"uint256","name":"dailyDepositCap","type":"uint256"},{"internalType":"uint256","name":"dailyDepositCapUsage","type":"uint256"},{"internalType":"uint256","name":"dailyWithdrawalCap","type":"uint256"},{"internalType":"uint256","name":"dailyWithdrawalCapUsage","type":"uint256"},{"internalType":"uint256","name":"dailyUserDepositCap","type":"uint256"},{"internalType":"uint256","name":"dailyUserDepositCapUsage","type":"uint256"},{"internalType":"uint256","name":"depositCap","type":"uint256"},{"internalType":"uint8","name":"tier","type":"uint8"},{"internalType":"uint256","name":"dailyUserDirectDepositCap","type":"uint256"},{"internalType":"uint256","name":"dailyUserDirectDepositCapUsage","type":"uint256"},{"internalType":"uint256","name":"directDepositCap","type":"uint256"}],"internalType":"struct ZkBobAccounting.Limits","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_root","type":"uint256"},{"internalType":"uint256","name":"_tvlCap","type":"uint256"},{"internalType":"uint256","name":"_dailyDepositCap","type":"uint256"},{"internalType":"uint256","name":"_dailyWithdrawalCap","type":"uint256"},{"internalType":"uint256","name":"_dailyUserDepositCap","type":"uint256"},{"internalType":"uint256","name":"_depositCap","type":"uint256"},{"internalType":"uint256","name":"_dailyUserDirectDepositCap","type":"uint256"},{"internalType":"uint256","name":"_directDepositCap","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kycProvidersManager","outputs":[{"internalType":"contract IKycProvidersManager","name":"res","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrationToUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nullifiers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorManager","outputs":[{"internalType":"contract IOperatorManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool_id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool_index","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recordDirectDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_tier","type":"uint8"}],"name":"resetDailyLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roots","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IKycProvidersManager","name":"_kycProvidersManager","type":"address"}],"name":"setKycProvidersManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_tier","type":"uint8"},{"internalType":"uint256","name":"_tvlCap","type":"uint256"},{"internalType":"uint256","name":"_dailyDepositCap","type":"uint256"},{"internalType":"uint256","name":"_dailyWithdrawalCap","type":"uint256"},{"internalType":"uint256","name":"_dailyUserDepositCap","type":"uint256"},{"internalType":"uint256","name":"_depositCap","type":"uint256"},{"internalType":"uint256","name":"_dailyUserDirectDepositCap","type":"uint256"},{"internalType":"uint256","name":"_directDepositCap","type":"uint256"}],"name":"setLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOperatorManager","name":"_operatorManager","type":"address"}],"name":"setOperatorManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_seller","type":"address"}],"name":"setTokenSeller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_tier","type":"uint8"},{"internalType":"address[]","name":"_users","type":"address[]"}],"name":"setUsersTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenSeller","outputs":[{"internalType":"contract ITokenSeller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transact","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transfer_verifier","outputs":[{"internalType":"contract ITransferVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tree_verifier","outputs":[{"internalType":"contract ITreeVerifier","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101806040523480156200001257600080fd5b506040516200608338038062006083833981016040819052620000359162000351565b8585858585856001633b9aca00806200004e33620002d9565b60805262ffffff881115620000aa5760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a2065786365656473206d617820706f6f6c206964000060448201526064015b60405180910390fd5b620000c0876200032960201b6200249e1760201c565b620000fd5760405162461bcd60e51b81526020600482015260196024820152600080516020620060638339815191526044820152606401620000a1565b62000113866200032960201b6200249e1760201c565b620001505760405162461bcd60e51b81526020600482015260196024820152600080516020620060638339815191526044820152606401620000a1565b62000166856200032960201b6200249e1760201c565b620001a35760405162461bcd60e51b81526020600482015260196024820152600080516020620060638339815191526044820152606401620000a1565b620001b9846200032960201b6200249e1760201c565b620001f65760405162461bcd60e51b81526020600482015260196024820152600080516020620060638339815191526044820152606401620000a1565b6200020c836200032960201b6200249e1760201c565b620002495760405162461bcd60e51b81526020600482015260196024820152600080516020620060638339815191526044820152606401620000a1565b816001146200029b5760405162461bcd60e51b815260206004820181905260248201527f5a6b426f62506f6f6c3a20696e636f72726563742064656e6f6d696e61746f726044820152606401620000a1565b5060c0969096526001600160a01b039485166101405292841660e05290831661010052821661012052166101605260a05250620003d9945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03163b151590565b6001600160a01b03811681146200034e57600080fd5b50565b60008060008060008060c087890312156200036b57600080fd5b8651955060208701516200037f8162000338565b6040880151909550620003928162000338565b6060880151909450620003a58162000338565b6080880151909350620003b88162000338565b60a0880151909250620003cb8162000338565b809150509295509295509295565b60805160a05160c05160e05161010051610120516101405161016051615ab1620005b2600039600081816102a7015281816104ed01526106370152600081816104c00152818161191901528181611ae101528181611d3501528181611e9801528181611fc10152818161211c0152818161235c01528181613ad80152613be901526000818161039c015261070e0152600081816102e10152818161081b01526115a301526000818161024101526114a30152600081816103ea0152613723015260008181610fa601528181610fdd015281816110140152818161104b01528181611082015281816110b9015281816110f0015281816118e001528181611a2f01528181611a73015281816122ce015281816124030152613c18015260008181610baa01528181610bfb01528181610c6501528181610ccf01528181610d3901528181610d7d01528181610de7015281816125e0015281816126e401528181612ae101528181612e3b01528181612ec601528181612f58015281816131e401528181613221015281816132560152818161328b015281816132c0015281816132f50152818161332a01528181614029015281816140c00152818161429801528181614444015281816144f701526146150152615ab16000f3fe608060405234801561001057600080fd5b50600436106101e45760003560e01c80637a22393b1161010f578063c41100fa116100a2578063e0ec037411610071578063e0ec037414610482578063e8fd02e414610495578063f2fde38b146104a8578063fc0c546a146104bb57600080fd5b8063c41100fa14610434578063c4a688b814610447578063c879c6d81461044f578063d21e82ab1461046257600080fd5b806396ce0795116100de57806396ce0795146103d75780639d8ad6e4146103e5578063af9890831461040c578063c2b40ae41461041457600080fd5b80637a22393b1461038457806383f26e3b146103975780638da5cb5b146103be5780638fff4676146103cf57600080fd5b80632f84c96f11610187578063508400401161015657806350840040146103365780636d55160c14610356578063715018a614610369578063790c3a331461037157600080fd5b80632f84c96f146102c95780633701f979146102dc5780634279a99e1461030357806346adf6ce1461032357600080fd5b80631cbec711116101c35780631cbec711146102635780631dc4cb33146102785780631dd69d061461028b5780632747f41d146102a257600080fd5b80622befce146101e95780630c6248de14610229578063171ef3001461023c575b600080fd5b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f64545b6040516001600160a01b0390911681526020015b60405180910390f35b600b5461020c906001600160a01b031681565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b610276610271366004614eee565b6104e2565b005b610276610286366004614fcf565b610569565b61029460095481565b604051908152602001610220565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b60065461020c906001600160a01b031681565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b61031661031136600461507c565b6109c0565b6040516102209190615099565b610276610331366004615146565b610e2b565b61029461034436600461507c565b600a6020526000908152604090205481565b610276610364366004615163565b610e5e565b61027661112e565b61027661037f36600461507c565b611142565b61027661039236600461507c565b611218565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031661020c565b61029461126e565b6103e8600160ff1b01610294565b6102947f000000000000000000000000000000000000000000000000000000000000000081565b610276611295565b6102946104223660046151b8565b60086020526000908152604090205481565b61027661044236600461507c565b611c39565b610276611cf0565b61027661045d3660046151d1565b6121dd565b6102946104703660046151b8565b60076020526000908152604090205481565b61027661049036600461520a565b6123dd565b6102766104a33660046152d1565b6123ef565b6102766104b636600461507c565b612428565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461055b5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b60448201526064015b60405180910390fd5b61056582826124ad565b5050565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190615344565b61062f5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e24546f28a8a8a6040518463ffffffff1660e01b81526004016106859392919061535f565b6000604051808303816000875af11580156106a4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106cc91908101906153d1565b935093509350935060006106e160008661282f565b604080516020810182528781529051633cac775b60e01b8152919450600785901b93506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250633cac775b9161074591908c906004016154a5565b602060405180830381865afa158015610762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107869190615344565b6107dd5760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a20626164206261746368206465706f7369742070726f60448201526137b360f11b6064820152608401610552565b604080516060810182526000838152600860209081529083902054825281018e90528082018b905290516345bb94c160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906345bb94c1906108529084908c90600401615501565b602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108939190615344565b6108db5760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6108e6608083615533565b91508c600860008481526020019081526020016000208190555060008480519060200120905060006009548260405160200161092c929190918252602082015260400190565b60408051601f19818403018152919052805160209091012060098190559050871561097657336000908152600a6020526040812080548a9290610970908490615533565b90915550505b80847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536886040516109a79190615577565b60405180910390a3505050505050505050505050505050565b610a2e604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff1681526020016000815260200160008152602001600081525090565b60408051602080820183526002546001600160481b0390811683526001600160a01b0386166000908152600583528481208551608081018752905461ffff8116825262010000810484169482019490945260ff600160581b850416958101869052600160601b90930490911660608301529192909190610aaf908690612c28565b60ff81166000908152600360209081526040808320815160e081018352815466ffffffffffffff8116825263ffffffff600160381b8204811683870152600160581b808304821684870152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015284519182018552600184015461ffff811683526001600160481b03620100008204811697840197909752049094169284019290925293945091610b7d610e10426155a0565b90506000610b90610e10620151806155a0565b610b9a90836155b4565b9050604051806101a001604052807f0000000000000000000000000000000000000000000000000000000000000000866000015166ffffffffffffff16610be191906155d6565b815260200189600001516001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866020015163ffffffff16610c2f91906155d6565b81526020018262ffffff16856000015161ffff1614610c4f576000610c55565b84602001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866040015163ffffffff16610c9991906155d6565b81526020018262ffffff16856000015161ffff1614610cb9576000610cbf565b84604001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866060015163ffffffff16610d0391906155d6565b81526020018262ffffff16896000015161ffff1614610d23576000610d29565b88602001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866080015163ffffffff16610d6d91906155d6565b81526020018760ff1681526020017f00000000000000000000000000000000000000000000000000000000000000008660c0015163ffffffff16610db191906155d6565b81526020018262ffffff16896000015161ffff1614610dd1576000610dd7565b88606001515b6001600160481b031681526020017f00000000000000000000000000000000000000000000000000000000000000008660a0015163ffffffff16610e1b91906155d6565b90529a9950505050505050505050565b610e33612d29565b610e5b8160ff16600090815260036020526040902060010180546001600160a01b0319169055565b50565b333014610ead5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420696e697469616c697a65720000000000006044820152606401610552565b6000805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c75415610f255760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a20616c726561647920696e697469616c697a656400006044820152606401610552565b87600003610f6c5760405162461bcd60e51b8152602060048201526014602482015273169ad09bd8941bdbdb0e881e995c9bc81c9bdbdd60621b6044820152606401610552565b600080805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c7899055611124906103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b610fd591906155d6565b6103e86110027f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b61100c91906155d6565b6103e86110397f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b61104391906155d6565b6103e86110707f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b61107a91906155d6565b6103e86110a77f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b6110b191906155d6565b6103e86110de7f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b6110e891906155d6565b6103e86111157f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b61111f91906155d6565b612d7d565b5050505050505050565b611136612d29565b61114060006134eb565b565b61114a612d29565b6001600160a01b0381163b6111b45760405162461bcd60e51b815260206004820152602a60248201527f4b796350726f7669646572734d616e6167657253746f726167653a206e6f7420604482015269184818dbdb9d1c9858dd60b21b6064820152608401610552565b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f648190556040516001600160a01b03821681527fcfca215f2134266880a5d2c68d2f52493a9d57fe6dd1245086a201e78871348e906020015b60405180910390a150565b611220612d29565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fdf71641930ea322cb32f687f4d292a0af694c81216254f204c930092593d82829060200161120d565b6000600761128960015463ffffffff600160e01b9091041690565b901b905090565b905090565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f9190615344565b61135b5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b33600061136661353b565b90508060000361137f576113786135db565b91506113a2565b8060020361138f5761137861365c565b806003036113a25761139f61365c565b91505b60006113ac6136a9565b60070b905060006113bd848361282f565b9250505060006113cc60043590565b60008181526007602081905260409091205491925083901b90156114325760405162461bcd60e51b815260206004820152601f60248201527f5a6b426f62506f6f6c3a20646f75626c657370656e64206465746563746564006044820152606401610552565b8061143b6136c2565b65ffffffffffff1611156114a15760405162461bcd60e51b815260206004820152602760248201527f5a6b426f62506f6f6c3a207472616e7366657220696e646578206f7574206f6660448201526620626f756e647360c81b6064820152608401610552565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368444dc76114d86136d7565b6114e06137ad565b6040518363ffffffff1660e01b81526004016114fd9291906155f5565b602060405180830381865afa15801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e9190615344565b61158a5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164207472616e736665722070726f6f660000006044820152606401610552565b6000818152600860205260409020546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906345bb94c1906115d3906137eb565b6115db613815565b6040518363ffffffff1660e01b81526004016115f8929190615635565b602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190615344565b6116815760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b611689613843565b611691613854565b60408051602081019390935282015260600160408051601f198184030181529181528151602092830120600085815260079093529120556116d3608082615533565b90506116dd6138b3565b6000828152600860205260408120919091556116f7613900565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945061173992508491506156589050565b61ffff60e01b161461178d5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164206d657373616765207072656669780000006044820152606401610552565b6000818051906020012090506000600954826040516020016117b9929190918252602082015260400190565b6040516020818303038152906040528051906020012090508060098190555080847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536856040516118099190615577565b60405180910390a350505050600061181f6139b3565b9050600061182d828661568f565b905060006118396139f0565b600d0b905061184a6103e8836156d0565b156118a15760405162461bcd60e51b815260206004820152602160248201527f5a6b426f62506f6f6c3a20696e636f727265637420746f6b656e20616d6f756e6044820152601d60fa1b6064820152608401610552565b86600003611946576000861380156118b7575080155b6118d35760405162461bcd60e51b8152600401610552906156e4565b61194188306103e86119057f0000000000000000000000000000000000000000000000000000000000000000876155d6565b61190f91906155a0565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016929190613a07565b611c05565b866001036119b4578115801561195a575080155b6119415760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f7272656374207472616e7366657220616d6044820152646f756e747360d81b6064820152608401610552565b86600203611b7257600082131580156119ce575060008113155b611a285760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f727265637420776974686472617720616d6044820152646f756e747360d81b6064820152608401610552565b60006103e87f0000000000000000000000000000000000000000000000000000000000000000611a56613a78565b611a6091906155d6565b611a6a91906155a0565b905060006103e87f0000000000000000000000000000000000000000000000000000000000000000611a9b86615728565b611aa591906155d6565b611aaf91906155a0565b90508115611ace57611ac18a83613ab6565b611acb9082615744565b90505b8015611b0857611b086001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b83613b96565b6000831215611b6b5760405162461bcd60e51b815260206004820152602960248201527f5a6b426f62506f6f6c3a20585020636c61696d696e67206973206e6f742079656044820152681d08195b98589b195960ba1b6064820152608401610552565b5050611c05565b86600303611baf57600086138015611b88575080155b611ba45760405162461bcd60e51b8152600401610552906156e4565b611941888584613bcb565b60405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20496e636f7272656374207472616e73616374696f6e604482015264207479706560d81b6064820152608401610552565b821561112457336000908152600a602052604081208054859290611c2a908490615533565b90915550505050505050505050565b611c41612d29565b6001600160a01b038116611ca25760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a206d616e61676572206973207a65726f206164647265604482015261737360f01b6064820152608401610552565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f267052ecaebdd552dc1b20904f59d83d51ae7add7514165322a7da9ef6cf543b9060200161120d565b333014611d335760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba1034b73b37b5b2b960791b6044820152606401610552565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316732791bca1f2de4661ed88a30c99a7a9449aa8417414611db15760405162461bcd60e51b815260206004820152600f60248201526e24b731b7b93932b1ba103a37b5b2b760891b6044820152606401610552565b6040516370a0823160e01b815230600482015273b0b195aefa3650a6908f15cdac7d92f8a5791b0b9060009082906370a0823190602401602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e29919061575b565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f9190615774565b60ff16905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f189190615774565b60405163095ea7b360e01b81527325e6505297b44f4817538fb2d91b88e1cf841b54600482018190526024820186905260ff9290921692506000906001600160a01b0387169063095ea7b3906044016020604051808303816000875af1158015611f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611faa9190615344565b604051636c197ff560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201889052919250600091841690636c197ff5906044016020604051808303816000875af115801561201f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612043919061575b565b6040516370a0823160e01b81523060048201529091506001600160a01b038816906370a0823190602401602060405180830381865afa15801561208a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ae919061575b565b156120ec5760405162461bcd60e51b815260206004820152600e60248201526d0496e636f727265637420737761760941b6044820152606401610552565b6000816120f98688615744565b61210490600a615875565b61210e90896155a0565b6121189190615744565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd61215b6000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af11580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d29190615344565b505050505050505050565b6001600160a01b0382163314806122635750600654604051632bb6fe4d60e21b81526001600160a01b0384811660048301523360248301529091169063aedbf93490604401602060405180830381865afa15801561223f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122639190615344565b6122ab5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b6044820152606401610552565b6001600160a01b0382166000908152600a60205260408120546103e8906122f3907f0000000000000000000000000000000000000000000000000000000000000000906155d6565b6122fd91906155a0565b90506000811161234f5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a206e6f2066656520746f2077697468647261770000006044820152606401610552565b6123836001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383613b96565b6001600160a01b0383166000818152600a602052604080822091909155517f66bf9186b00db666fc37aaffbb95a050c66e599e000c785c1dff0467d868f1b1906123d09084815260200190565b60405180910390a2505050565b6123e5612d29565b6105658282613cf7565b6123f7612d29565b611124886103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000008b6155a0565b612430612d29565b6001600160a01b0381166124955760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610552565b610e5b816134eb565b6001600160a01b03163b151590565b60006124be610e10620151806155a0565b6124ca610e10426155a0565b6124d491906155a0565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b9004909216606083015292935091600390829061254a908890612c28565b60ff1681526020808201929092526040908101600020815160e081018352905466ffffffffffffff8116825263ffffffff600160381b8204811694830194909452600160581b8104841692820192909252600160781b820483166060820152600160981b820483166080820152600160b81b8204831660a08201819052600160d81b90920490921660c0830152909150612605907f0000000000000000000000000000000000000000000000000000000000000000906155d6565b8411156126705760405162461bcd60e51b815260206004820152603360248201527f5a6b426f624163636f756e74696e673a2073696e676c65206469726563742064604482015272195c1bdcda5d0818d85c08195e18d959591959606a1b6064820152608401610552565b816000015161ffff168361ffff1611156126bb576040805160808101825261ffff85168152600060208201529281015160ff16908301526001600160481b0384166060830152612791565b83826060018181516126cd9190615881565b6001600160481b031690525060c081015161270f907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff166155d6565b82606001516001600160481b031611156127915760405162461bcd60e51b815260206004820152603760248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206469726560448201527f6374206465706f736974206361702065786365656465640000000000000000006064820152608401610552565b506001600160a01b039390931660009081526005602090815260409182902085518154928701519387015160609097015161ffff9091166001600160581b031990931692909217620100006001600160481b03948516021769ffffffffffffffffffff60581b1916600160581b60ff9097169690960268ffffffffffffffffff60601b191695909517600160601b9290911691909102179092555050565b6040805160c08101825260015466ffffffffffffff8116825263ffffffff600160381b8204811660208085019190915262ffffff600160581b8404811685870152600160701b84041660608501526001600160581b03600160881b8404166080850152600160e01b9092041660a083015282519081019092526002546001600160481b0316825260009182918291826128ca610e10426155a0565b60a084015163ffffffff1694509050831580159061290857506128f2610e1062093a806155a0565b604084015161290190836158ac565b62ffffff16115b15612a1e576040838101805162ffffff9081166000908152600460208181528583208651606081018852905480861682526301000000810463ffffffff16828401908152600160381b9091046001600160581b03168289015286518616855292909152948220805471ffffffffffffffffffffffffffffffffffff1916905584519092169092525160a086015161299f91906158d0565b9050846020015163ffffffff168163ffffffff1611156129c65763ffffffff811660208601525b60008163ffffffff16836040015187608001516129e391906158ed565b6129ed919061590d565b9050856000015166ffffffffffffff168166ffffffffffffff161115612a1a5766ffffffffffffff811686525b5050505b8062ffffff16836060015162ffffff161015612ad957604080516060808201835262ffffff80851680845260a088015163ffffffff908116602080870191825260808b01516001600160581b03908116888a01908152968c018051871660009081526004909352989091209651875492519651909116600160381b0271ffffffffffffffffffffff00000000000000199690931663010000000266ffffffffffffff1990921694169390931792909217929092161790915590525b8151612b06907f000000000000000000000000000000000000000000000000000000000000000090615927565b6001600160481b031683608001818151612b209190615941565b6001600160581b031690525060a08301805190612b3c82615963565b63ffffffff169052508615612b5657612b56828989613e32565b5050805160018054602084015160408501516060860151608087015160a09097015166ffffffffffffff87166001600160581b031990951694909417600160381b63ffffffff808616919091029190911765ffffffffffff60581b1916600160581b62ffffff9485160262ffffff60701b191617600160701b93909216929092021770ffffffffffffffffffffffffffffffffff16600160881b6001600160581b03909716969096026001600160e01b031695909517600160e01b959092169490940217905596909550909350915050565b600080612c537f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f645490565b905060ff8316158015612c6e57506001600160a01b03811615155b15612d1e57604051630a364e7560e41b81526001600160a01b038581166004830152600091829184169063a364e750906024016040805180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190615986565b91509150818015612d0c575060ff811660009081526003602052604090205466ffffffffffffff1615155b15612d1b579250612d23915050565b50505b829150505b92915050565b612d31614736565b6111405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610552565b60ff8860ff1610612ddc5760405162461bcd60e51b815260206004820152602360248201527f5a6b426f624163636f756e74696e673a20696e76616c6964206c696d6974207460448201526234b2b960e91b6064820152608401610552565b60008311612e365760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a207a65726f206465706f7369742063616044820152600760fc1b6064820152608401610552565b612e677f000000000000000000000000000000000000000000000000000000000000000066ffffffffffffff6155d6565b871115612ec15760405162461bcd60e51b815260206004820152602260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6172604482015261676560f01b6064820152608401610552565b612eef7f000000000000000000000000000000000000000000000000000000000000000063ffffffff6155d6565b861115612f535760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526b617020746f6f206c6172676560a01b6064820152608401610552565b612f817f000000000000000000000000000000000000000000000000000000000000000063ffffffff6155d6565b851115612fe85760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526e6c2063617020746f6f206c6172676560881b6064820152608401610552565b828410156130505760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526e7369742063617020746f6f206c6f7760881b6064820152608401610552565b838610156130b35760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f7369742063604482015269617020746f6f206c6f7760b01b6064820152608401610552565b858710156131035760405162461bcd60e51b815260206004820181905260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6f776044820152606401610552565b600085116131665760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a207a65726f206461696c792077697468604482015269064726177616c206361760b41b6064820152608401610552565b808210156131d55760405162461bcd60e51b815260206004820152603660248201527f5a6b426f624163636f756e74696e673a206461696c79207573657220646972656044820152756374206465706f7369742063617020746f6f206c6f7760501b6064820152608401610552565b60006040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000008a61320e91906155a0565b66ffffffffffffff1681526020016132467f00000000000000000000000000000000000000000000000000000000000000008a6155a0565b63ffffffff16815260200161327b7f0000000000000000000000000000000000000000000000000000000000000000896155a0565b63ffffffff1681526020016132b07f0000000000000000000000000000000000000000000000000000000000000000886155a0565b63ffffffff1681526020016132e57f0000000000000000000000000000000000000000000000000000000000000000876155a0565b63ffffffff16815260200161331a7f0000000000000000000000000000000000000000000000000000000000000000856155a0565b63ffffffff16815260200161334f7f0000000000000000000000000000000000000000000000000000000000000000866155a0565b63ffffffff90811690915260ff8b16600081815260036020908152604091829020855181549287015184880151606089015160808a015160a08b015160c08c01518b16600160d81b0263ffffffff60d81b19918c16600160b81b0263ffffffff60b81b19938d16600160981b029390931667ffffffffffffffff60981b19948d16600160781b0263ffffffff60781b19968e16600160581b029690961667ffffffffffffffff60581b1997909d16600160381b026001600160581b0319909a1666ffffffffffffff909816979097179890981794909416999099179190911716919091179590951794909416179092559051919250907f3cb26612e7105331adad836a65ae9b7f1d30a9e469ec70510a7c7ea36b0185ed906134d8908490600060e08201905066ffffffffffffff8351168252602083015163ffffffff80821660208501528060408601511660408501528060608601511660608501528060808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60405180910390a2505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000600161354b600260086155d6565b6001901b6135599190615744565b6135d56020600261010082816008600e600684613577816004615533565b6135819190615533565b61358b9190615533565b6135959190615533565b61359f9190615533565b6135a99190615533565b6135b39190615533565b6135bd9190615533565b6135c79190615533565b6135d19190615744565b3590565b16905090565b60008060006135e861477a565b9150915061365561364e6135fb60043590565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b8383614797565b9250505090565b600061129060206014600880600280610100868185600e600684613681816004615533565b61368b9190615533565b6136959190615533565b61369f9190615533565b6135779190615533565b600061129060206008600e60068361359f816004615533565b600061129060206006816135b3816004615533565b6136df614e9d565b6136e76147bf565b815260043560208201526136f9613843565b6040820152600861370c600e6006615533565b6137169190615533565b6137219060086155d6565b7f0000000000000000000000000000000000000000000000000000000000000000901b61374c613854565b6137569190615533565b60608201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016137846147e9565b6040516137929291906159c8565b6040519081900390206137a591906159d8565b608082015290565b3660006008600e600660206137c3816004615533565b6137cd9190615533565b6137d79190615533565b6137e19190615533565b612d239190615533565b6137f3614ebb565b8181526137fe6138b3565b602082015261380b613843565b6040820152919050565b36600060206101006008600e60068461382f816004615533565b6138399190615533565b6137c39190615533565b60006112906135d160206004615533565b600060016008613866600e6006615533565b6138709190615533565b61387b9060086155d6565b6001901b6138899190615744565b6135d56020600861389c600e6006615533565b6138a69190615533565b60206135b3816004615533565b60006112906101006008600e600660206138ce816004615533565b6138d89190615533565b6138e29190615533565b6138ec9190615533565b6138f69190615533565b6135d19190615533565b3660008061390c614879565b90506000816002806101006020816008600e60068461392c816004615533565b6139369190615533565b6139409190615533565b61394a9190615533565b6139549190615533565b61395e9190615533565b6139689190615533565b6139729190615533565b61397c9190615533565b6139869190615533565b6139909190615533565b905060008261399d6148c0565b6139a79190615744565b91959194509092505050565b600060016139c26008806155d6565b6001901b6139d09190615744565b6135d560206008600280610100848185600e600684613695816004615533565b60006112906020600e6006826135a9816004615533565b6040516001600160a01b0380851660248301528316604482015260648101829052613a729085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148fd565b50505050565b60006001613a876008806155d6565b6001901b613a959190615744565b6135d56020600880600280610100858185600e60068461368b816004615533565b600b546000906001600160a01b03168015613b8c57613aff6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168285613b96565b604051630802e33b60e41b81526001600160a01b038581166004830152602482018590526000919083169063802e33b09060440160408051808303816000875af1158015613b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7591906159ec565b9150613b8390508185615744565b92505050612d23565b5060009392505050565b6040516001600160a01b038316602482015260448101829052613bc690849063a9059cbb60e01b90606401613a3b565b505050565b6000806000613bd86149cf565b919450925090506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e3ee160e87306103e8613c3d7f00000000000000000000000000000000000000000000000000000000000000008a6155d6565b613c4791906155a0565b6000613c51614a06565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201529490931660248501526044840191909152606483015267ffffffffffffffff16608482015260a4810188905260ff861660c482015260e48101859052610104810184905261012401600060405180830381600087803b158015613cd757600080fd5b505af1158015613ceb573d6000803e3d6000fd5b50505050505050505050565b8160ff1660ff1480613d23575060ff821660009081526003602052604090205466ffffffffffffff1615155b613d865760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206e6f6e2d6578697374696e6720706f60448201526d37b6103634b6b4ba39903a34b2b960911b6064820152608401610552565b60005b8151811015613bc6576000828281518110613da657613da66159b2565b6020908102919091018101516001600160a01b038116600081815260058452604090819020805460ff60581b1916600160581b60ff8b16908102919091179091558151928352938201939093529092507f1283ebeb150dffd4da976f64c81e074fd4dc895cb64995dc46f13c9fd96a9551910160405180910390a150613e2b81615a10565b9050613d89565b6001600160a01b038216158015613e495750600081135b15613e955760028054829190600090613e6c9084906001600160481b0316615881565b92506101000a8154816001600160481b0302191690836001600160481b03160217905550505050565b6000613ea6610e10620151806155a0565b613eb2610e10426155a0565b613ebc91906155a0565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b90049092166060830152929350916003908290613f32908890612c28565b60ff16815260208082019290925260409081016000908120825160e081018452815466ffffffffffffff8116825263ffffffff600160381b8204811683880152600160581b808304821684880152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015285519182018652600184015461ffff811683526001600160481b03620100008204811698840198909852049095169385019390935293509091908613156144e5578751869081908a90614012908390615881565b6001600160481b03169052506080830151614054907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff166155d6565b8111156140b85760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a2073696e676c65206465706f7369742060448201526b18d85c08195e18d95959195960a21b6064820152608401610552565b82516140ee907f00000000000000000000000000000000000000000000000000000000000000009066ffffffffffffff166155d6565b89516001600160481b031611156141515760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a2074766c2063617020657863656564656044820152601960fa1b6064820152608401610552565b846000015161ffff168661ffff16111561426f5760405180608001604052808761ffff168152602001826001600160481b03168152602001866040015160ff16815260200160006001600160481b0316815250600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160481b0302191690836001600160481b03160217905550604082015181600001600b6101000a81548160ff021916908360ff160217905550606082015181600001600c6101000a8154816001600160481b0302191690836001600160481b031602179055509050506143ce565b80856020018181516142819190615881565b6001600160481b031690525060608301516142c3907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff166155d6565b85602001516001600160481b031611156143385760405162461bcd60e51b815260206004820152603060248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526f1cda5d0818d85c08195e18d95959195960821b6064820152608401610552565b6001600160a01b03881660009081526005602090815260409182902087518154928901519389015160608a01516001600160481b03908116600160601b0268ffffffffffffffffff60601b1960ff909316600160581b029290921669ffffffffffffffffffff60581b199190961662010000026001600160581b031990951661ffff909316929092179390931716929092171790555b816000015161ffff168661ffff16111561441b5760405180606001604052808761ffff168152602001826001600160481b0316815260200160006001600160481b031681525091506144df565b808260200181815161442d9190615881565b6001600160481b0316905250602083015161446f907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff166155d6565b82602001516001600160481b031611156144df5760405162461bcd60e51b815260206004820152602b60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526a185c08195e18d95959195960aa1b6064820152608401610552565b506146b5565b60006144f087615728565b90506145207f000000000000000000000000000000000000000000000000000000000000000063ffffffff6155d6565b8111156145845760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a207769746864726177616c20616d6f7560448201526b6e7420746f6f206c6172676560a01b6064820152608401610552565b80896000018181516145969190615a29565b6001600160481b0316905250815161ffff90811690871611156145ec5760405180606001604052808761ffff16815260200160006001600160481b03168152602001826001600160481b031681525091506146b3565b80826040018181516145fe9190615881565b6001600160481b03169052506040830151614640907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff166155d6565b82604001516001600160481b031611156146b35760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526d1b0818d85c08195e18d95959195960921b6064820152608401610552565b505b9651600280546001600160481b0392831668ffffffffffffffffff199091161790558751600193909301805460208a01516040909a01518316600160581b0268ffffffffffffffffff60581b199a90931662010000026001600160581b031990911661ffff9095169490941793909317979097169690961790555050505050565b6000614740614a29565b8061129057507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035433905b6001600160a01b031614905090565b6000806000614787614a3d565b8035946020909101359350915050565b60008060006147a7868686614ac6565b915091506147b481614aff565b5090505b9392505050565b6000600860006147cd6136c2565b65ffffffffffff16815260200190815260200160002054905090565b366000806002806101006020816008600e600684614808816004615533565b6148129190615533565b61481c9190615533565b6148269190615533565b6148309190615533565b61483a9190615533565b6148449190615533565b61484e9190615533565b6148589190615533565b6148629190615533565b9050600061486e6148c0565b919491935090915050565b60008061488461353b565b90508015806148935750806001145b156148a057600891505090565b806002036148b057602491505090565b806003036101e457602491505090565b600060016148d0600260086155d6565b6001901b6148de9190615744565b6135d5602060028061010083816008600e60068461369f816004615533565b6000614952826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c499092919063ffffffff16565b805190915015613bc657808060200190518101906149709190615344565b613bc65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b60008060008060006149df61477a565b90925090506149f360ff82901c601b615533565b959194506001600160ff1b031692509050565b60006112906020600880600280610100858185600e60068461368b816004615533565b6000805433906001600160a01b031661476b565b6000614a476148c0565b6002806101006020816008600e600684614a62816004615533565b614a6c9190615533565b614a769190615533565b614a809190615533565b614a8a9190615533565b614a949190615533565b614a9e9190615533565b614aa89190615533565b614ab29190615533565b614abc9190615533565b6112909190615533565b6000806001600160ff1b03831681614ae360ff86901c601b615533565b9050614af187828885614c60565b935093505050935093915050565b6000816004811115614b1357614b13615a49565b03614b1b5750565b6001816004811115614b2f57614b2f615a49565b03614b7c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610552565b6002816004811115614b9057614b90615a49565b03614bdd5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610552565b6003816004811115614bf157614bf1615a49565b03610e5b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610552565b6060614c588484600085614d24565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614c975750600090506003614d1b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614ceb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614d1457600060019250925050614d1b565b9150600090505b94509492505050565b606082471015614d855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b600080866001600160a01b03168587604051614da19190615a5f565b60006040518083038185875af1925050503d8060008114614dde576040519150601f19603f3d011682016040523d82523d6000602084013e614de3565b606091505b5091509150614df487838387614dff565b979650505050505050565b60608315614e6e578251600003614e67576001600160a01b0385163b614e675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b5081614c58565b614c588383815115614e835781518083602001fd5b8060405162461bcd60e51b81526004016105529190615577565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b0381168114610e5b57600080fd5b60008060408385031215614f0157600080fd5b8235614f0c81614ed9565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614f5957614f59614f1a565b604052919050565b600082601f830112614f7257600080fd5b60405161010080820182811067ffffffffffffffff82111715614f9757614f97614f1a565b60405283018185821115614faa57600080fd5b845b82811015614fc4578035825260209182019101614fac565b509195945050505050565b6000806000806000806102608789031215614fe957600080fd5b86359550602087013567ffffffffffffffff8082111561500857600080fd5b818901915089601f83011261501c57600080fd5b81358181111561502b57600080fd5b8a60208260051b850101111561504057600080fd5b602083019750809650505050604087013592506150608860608901614f61565b9150615070886101608901614f61565b90509295509295509295565b60006020828403121561508e57600080fd5b81356147b881614ed9565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e08301526101008084015181840152506101208084015161510d8285018260ff169052565b50506101408381015190830152610160808401519083015261018092830151929091019190915290565b60ff81168114610e5b57600080fd5b60006020828403121561515857600080fd5b81356147b881615137565b600080600080600080600080610100898b03121561518057600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b6000602082840312156151ca57600080fd5b5035919050565b600080604083850312156151e457600080fd5b82356151ef81614ed9565b915060208301356151ff81614ed9565b809150509250929050565b6000806040838503121561521d57600080fd5b823561522881615137565b915060208381013567ffffffffffffffff8082111561524657600080fd5b818601915086601f83011261525a57600080fd5b81358181111561526c5761526c614f1a565b8060051b915061527d848301614f30565b818152918301840191848101908984111561529757600080fd5b938501935b838510156152c157843592506152b183614ed9565b828252938501939085019061529c565b8096505050505050509250929050565b600080600080600080600080610100898b0312156152ee57600080fd5b88356152f981615137565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b8051801515811461533f57600080fd5b919050565b60006020828403121561535657600080fd5b6147b88261532f565b6040808252810183905260006001600160fb1b0384111561537f57600080fd5b8360051b8086606085013760009083016060019081526020909201929092529392505050565b60005b838110156153c05781810151838201526020016153a8565b83811115613a725750506000910152565b600080600080608085870312156153e757600080fd5b845193506020850151925060408501519150606085015167ffffffffffffffff8082111561541457600080fd5b818701915087601f83011261542857600080fd5b81518181111561543a5761543a614f1a565b61544d601f8201601f1916602001614f30565b915080825288602082850101111561546457600080fd5b6154758160208401602086016153a5565b5094979396509194505050565b8060005b6008811015613a72578151845260209384019390910190600101615486565b6101208101818460005b60018110156154ce5781518352602092830192909101906001016154af565b5050506147b86020830184615482565b8060005b6003811015613a725781518452602093840193909101906001016154e2565b610160810161551082856154de565b6147b86060830184615482565b634e487b7160e01b600052601160045260246000fd5b600082198211156155465761554661551d565b500190565b600081518084526155638160208601602086016153a5565b601f01601f19169290920160200192915050565b6020815260006147b8602083018461554b565b634e487b7160e01b600052601260045260246000fd5b6000826155af576155af61558a565b500490565b600062ffffff808416806155ca576155ca61558a565b92169190910492915050565b60008160001904831182151516156155f0576155f061551d565b500290565b6101a08101818460005b600581101561561e5781518352602092830192909101906001016155ff565b5050506101008360a0840137600081529392505050565b610160810161564482856154de565b610100836060840137600081529392505050565b805160208201516001600160e01b031980821692919060048310156156875780818460040360031b1b83161693505b505050919050565b600080821280156001600160ff1b03849003851316156156b1576156b161551d565b600160ff1b83900384128116156156ca576156ca61551d565b50500190565b6000826156df576156df61558a565b500790565b60208082526024908201527f5a6b426f62506f6f6c3a20696e636f7272656374206465706f73697420616d6f604082015263756e747360e01b606082015260800190565b6000600160ff1b820161573d5761573d61551d565b5060000390565b6000828210156157565761575661551d565b500390565b60006020828403121561576d57600080fd5b5051919050565b60006020828403121561578657600080fd5b81516147b881615137565b600181815b808511156157cc5781600019048211156157b2576157b261551d565b808516156157bf57918102915b93841c9390800290615796565b509250929050565b6000826157e357506001612d23565b816157f057506000612d23565b816001811461580657600281146158105761582c565b6001915050612d23565b60ff8411156158215761582161551d565b50506001821b612d23565b5060208310610133831016604e8410600b841016171561584f575081810a612d23565b6158598383615791565b806000190482111561586d5761586d61551d565b029392505050565b60006147b883836157d4565b60006001600160481b038083168185168083038211156158a3576158a361551d565b01949350505050565b600062ffffff838116908316818110156158c8576158c861551d565b039392505050565b600063ffffffff838116908316818110156158c8576158c861551d565b60006001600160581b03838116908316818110156158c8576158c861551d565b60006001600160581b03808416806155ca576155ca61558a565b60006001600160481b03808416806155ca576155ca61558a565b60006001600160581b038083168185168083038211156158a3576158a361551d565b600063ffffffff80831681810361597c5761597c61551d565b6001019392505050565b6000806040838503121561599957600080fd5b6159a28361532f565b915060208301516151ff81615137565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b6000826159e7576159e761558a565b500690565b600080604083850312156159ff57600080fd5b505080516020909101519092909150565b600060018201615a2257615a2261551d565b5060010190565b60006001600160481b03838116908316818110156158c8576158c861551d565b634e487b7160e01b600052602160045260246000fd5b60008251615a718184602087016153a5565b919091019291505056fea2646970667358221220fa7609678ac81c6da4f63b538c6ee0aad8ce3e88b670453eb9eb6fac1d4dfaa364736f6c634300080f00335a6b426f62506f6f6c3a206e6f74206120636f6e74726163740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000a86c511832ead78d30ad49711874a9f3a1dfb84000000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d0000000000000000000000009a7b4198065efe631a962e737bdfe1f44f2cb3ee000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf289
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101e45760003560e01c80637a22393b1161010f578063c41100fa116100a2578063e0ec037411610071578063e0ec037414610482578063e8fd02e414610495578063f2fde38b146104a8578063fc0c546a146104bb57600080fd5b8063c41100fa14610434578063c4a688b814610447578063c879c6d81461044f578063d21e82ab1461046257600080fd5b806396ce0795116100de57806396ce0795146103d75780639d8ad6e4146103e5578063af9890831461040c578063c2b40ae41461041457600080fd5b80637a22393b1461038457806383f26e3b146103975780638da5cb5b146103be5780638fff4676146103cf57600080fd5b80632f84c96f11610187578063508400401161015657806350840040146103365780636d55160c14610356578063715018a614610369578063790c3a331461037157600080fd5b80632f84c96f146102c95780633701f979146102dc5780634279a99e1461030357806346adf6ce1461032357600080fd5b80631cbec711116101c35780631cbec711146102635780631dc4cb33146102785780631dd69d061461028b5780632747f41d146102a257600080fd5b80622befce146101e95780630c6248de14610229578063171ef3001461023c575b600080fd5b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f64545b6040516001600160a01b0390911681526020015b60405180910390f35b600b5461020c906001600160a01b031681565b61020c7f000000000000000000000000a86c511832ead78d30ad49711874a9f3a1dfb84081565b610276610271366004614eee565b6104e2565b005b610276610286366004614fcf565b610569565b61029460095481565b604051908152602001610220565b61020c7f000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf28981565b60065461020c906001600160a01b031681565b61020c7f00000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d81565b61031661031136600461507c565b6109c0565b6040516102209190615099565b610276610331366004615146565b610e2b565b61029461034436600461507c565b600a6020526000908152604090205481565b610276610364366004615163565b610e5e565b61027661112e565b61027661037f36600461507c565b611142565b61027661039236600461507c565b611218565b61020c7f0000000000000000000000009a7b4198065efe631a962e737bdfe1f44f2cb3ee81565b6000546001600160a01b031661020c565b61029461126e565b6103e8600160ff1b01610294565b6102947f000000000000000000000000000000000000000000000000000000000000000081565b610276611295565b6102946104223660046151b8565b60086020526000908152604090205481565b61027661044236600461507c565b611c39565b610276611cf0565b61027661045d3660046151d1565b6121dd565b6102946104703660046151b8565b60076020526000908152604090205481565b61027661049036600461520a565b6123dd565b6102766104a33660046152d1565b6123ef565b6102766104b636600461507c565b612428565b61020c7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417481565b336001600160a01b037f000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf289161461055b5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b60448201526064015b60405180910390fd5b61056582826124ad565b5050565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e39190615344565b61062f5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b6000806000807f000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf2896001600160a01b031663e24546f28a8a8a6040518463ffffffff1660e01b81526004016106859392919061535f565b6000604051808303816000875af11580156106a4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106cc91908101906153d1565b935093509350935060006106e160008661282f565b604080516020810182528781529051633cac775b60e01b8152919450600785901b93506001600160a01b037f0000000000000000000000009a7b4198065efe631a962e737bdfe1f44f2cb3ee169250633cac775b9161074591908c906004016154a5565b602060405180830381865afa158015610762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107869190615344565b6107dd5760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a20626164206261746368206465706f7369742070726f60448201526137b360f11b6064820152608401610552565b604080516060810182526000838152600860209081529083902054825281018e90528082018b905290516345bb94c160e01b81526001600160a01b037f00000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d16906345bb94c1906108529084908c90600401615501565b602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108939190615344565b6108db5760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6108e6608083615533565b91508c600860008481526020019081526020016000208190555060008480519060200120905060006009548260405160200161092c929190918252602082015260400190565b60408051601f19818403018152919052805160209091012060098190559050871561097657336000908152600a6020526040812080548a9290610970908490615533565b90915550505b80847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536886040516109a79190615577565b60405180910390a3505050505050505050505050505050565b610a2e604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff1681526020016000815260200160008152602001600081525090565b60408051602080820183526002546001600160481b0390811683526001600160a01b0386166000908152600583528481208551608081018752905461ffff8116825262010000810484169482019490945260ff600160581b850416958101869052600160601b90930490911660608301529192909190610aaf908690612c28565b60ff81166000908152600360209081526040808320815160e081018352815466ffffffffffffff8116825263ffffffff600160381b8204811683870152600160581b808304821684870152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015284519182018552600184015461ffff811683526001600160481b03620100008204811697840197909752049094169284019290925293945091610b7d610e10426155a0565b90506000610b90610e10620151806155a0565b610b9a90836155b4565b9050604051806101a001604052807f000000000000000000000000000000000000000000000000000000003b9aca00866000015166ffffffffffffff16610be191906155d6565b815260200189600001516001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866020015163ffffffff16610c2f91906155d6565b81526020018262ffffff16856000015161ffff1614610c4f576000610c55565b84602001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866040015163ffffffff16610c9991906155d6565b81526020018262ffffff16856000015161ffff1614610cb9576000610cbf565b84604001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866060015163ffffffff16610d0391906155d6565b81526020018262ffffff16896000015161ffff1614610d23576000610d29565b88602001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866080015163ffffffff16610d6d91906155d6565b81526020018760ff1681526020017f000000000000000000000000000000000000000000000000000000003b9aca008660c0015163ffffffff16610db191906155d6565b81526020018262ffffff16896000015161ffff1614610dd1576000610dd7565b88606001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca008660a0015163ffffffff16610e1b91906155d6565b90529a9950505050505050505050565b610e33612d29565b610e5b8160ff16600090815260036020526040902060010180546001600160a01b0319169055565b50565b333014610ead5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420696e697469616c697a65720000000000006044820152606401610552565b6000805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c75415610f255760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a20616c726561647920696e697469616c697a656400006044820152606401610552565b87600003610f6c5760405162461bcd60e51b8152602060048201526014602482015273169ad09bd8941bdbdb0e881e995c9bc81c9bdbdd60621b6044820152606401610552565b600080805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c7899055611124906103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b610fd591906155d6565b6103e86110027f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b61100c91906155d6565b6103e86110397f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b61104391906155d6565b6103e86110707f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b61107a91906155d6565b6103e86110a77f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b6110b191906155d6565b6103e86110de7f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b6110e891906155d6565b6103e86111157f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b61111f91906155d6565b612d7d565b5050505050505050565b611136612d29565b61114060006134eb565b565b61114a612d29565b6001600160a01b0381163b6111b45760405162461bcd60e51b815260206004820152602a60248201527f4b796350726f7669646572734d616e6167657253746f726167653a206e6f7420604482015269184818dbdb9d1c9858dd60b21b6064820152608401610552565b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f648190556040516001600160a01b03821681527fcfca215f2134266880a5d2c68d2f52493a9d57fe6dd1245086a201e78871348e906020015b60405180910390a150565b611220612d29565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fdf71641930ea322cb32f687f4d292a0af694c81216254f204c930092593d82829060200161120d565b6000600761128960015463ffffffff600160e01b9091041690565b901b905090565b905090565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f9190615344565b61135b5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b33600061136661353b565b90508060000361137f576113786135db565b91506113a2565b8060020361138f5761137861365c565b806003036113a25761139f61365c565b91505b60006113ac6136a9565b60070b905060006113bd848361282f565b9250505060006113cc60043590565b60008181526007602081905260409091205491925083901b90156114325760405162461bcd60e51b815260206004820152601f60248201527f5a6b426f62506f6f6c3a20646f75626c657370656e64206465746563746564006044820152606401610552565b8061143b6136c2565b65ffffffffffff1611156114a15760405162461bcd60e51b815260206004820152602760248201527f5a6b426f62506f6f6c3a207472616e7366657220696e646578206f7574206f6660448201526620626f756e647360c81b6064820152608401610552565b7f000000000000000000000000a86c511832ead78d30ad49711874a9f3a1dfb8406001600160a01b03166368444dc76114d86136d7565b6114e06137ad565b6040518363ffffffff1660e01b81526004016114fd9291906155f5565b602060405180830381865afa15801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e9190615344565b61158a5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164207472616e736665722070726f6f660000006044820152606401610552565b6000818152600860205260409020546001600160a01b037f00000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d16906345bb94c1906115d3906137eb565b6115db613815565b6040518363ffffffff1660e01b81526004016115f8929190615635565b602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116399190615344565b6116815760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b611689613843565b611691613854565b60408051602081019390935282015260600160408051601f198184030181529181528151602092830120600085815260079093529120556116d3608082615533565b90506116dd6138b3565b6000828152600860205260408120919091556116f7613900565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945061173992508491506156589050565b61ffff60e01b161461178d5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164206d657373616765207072656669780000006044820152606401610552565b6000818051906020012090506000600954826040516020016117b9929190918252602082015260400190565b6040516020818303038152906040528051906020012090508060098190555080847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536856040516118099190615577565b60405180910390a350505050600061181f6139b3565b9050600061182d828661568f565b905060006118396139f0565b600d0b905061184a6103e8836156d0565b156118a15760405162461bcd60e51b815260206004820152602160248201527f5a6b426f62506f6f6c3a20696e636f727265637420746f6b656e20616d6f756e6044820152601d60fa1b6064820152608401610552565b86600003611946576000861380156118b7575080155b6118d35760405162461bcd60e51b8152600401610552906156e4565b61194188306103e86119057f0000000000000000000000000000000000000000000000000000000000000001876155d6565b61190f91906155a0565b6001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417416929190613a07565b611c05565b866001036119b4578115801561195a575080155b6119415760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f7272656374207472616e7366657220616d6044820152646f756e747360d81b6064820152608401610552565b86600203611b7257600082131580156119ce575060008113155b611a285760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f727265637420776974686472617720616d6044820152646f756e747360d81b6064820152608401610552565b60006103e87f0000000000000000000000000000000000000000000000000000000000000001611a56613a78565b611a6091906155d6565b611a6a91906155a0565b905060006103e87f0000000000000000000000000000000000000000000000000000000000000001611a9b86615728565b611aa591906155d6565b611aaf91906155a0565b90508115611ace57611ac18a83613ab6565b611acb9082615744565b90505b8015611b0857611b086001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174168b83613b96565b6000831215611b6b5760405162461bcd60e51b815260206004820152602960248201527f5a6b426f62506f6f6c3a20585020636c61696d696e67206973206e6f742079656044820152681d08195b98589b195960ba1b6064820152608401610552565b5050611c05565b86600303611baf57600086138015611b88575080155b611ba45760405162461bcd60e51b8152600401610552906156e4565b611941888584613bcb565b60405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20496e636f7272656374207472616e73616374696f6e604482015264207479706560d81b6064820152608401610552565b821561112457336000908152600a602052604081208054859290611c2a908490615533565b90915550505050505050505050565b611c41612d29565b6001600160a01b038116611ca25760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a206d616e61676572206973207a65726f206164647265604482015261737360f01b6064820152608401610552565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f267052ecaebdd552dc1b20904f59d83d51ae7add7514165322a7da9ef6cf543b9060200161120d565b333014611d335760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba1034b73b37b5b2b960791b6044820152606401610552565b7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841746001600160a01b0316732791bca1f2de4661ed88a30c99a7a9449aa8417414611db15760405162461bcd60e51b815260206004820152600f60248201526e24b731b7b93932b1ba103a37b5b2b760891b6044820152606401610552565b6040516370a0823160e01b815230600482015273b0b195aefa3650a6908f15cdac7d92f8a5791b0b9060009082906370a0823190602401602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e29919061575b565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f9190615774565b60ff16905060007f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841746001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f189190615774565b60405163095ea7b360e01b81527325e6505297b44f4817538fb2d91b88e1cf841b54600482018190526024820186905260ff9290921692506000906001600160a01b0387169063095ea7b3906044016020604051808303816000875af1158015611f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611faa9190615344565b604051636c197ff560e01b81526001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841748116600483015260248201889052919250600091841690636c197ff5906044016020604051808303816000875af115801561201f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612043919061575b565b6040516370a0823160e01b81523060048201529091506001600160a01b038816906370a0823190602401602060405180830381865afa15801561208a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120ae919061575b565b156120ec5760405162461bcd60e51b815260206004820152600e60248201526d0496e636f727265637420737761760941b6044820152606401610552565b6000816120f98688615744565b61210490600a615875565b61210e90896155a0565b6121189190615744565b90507f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841746001600160a01b03166323b872dd61215b6000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af11580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d29190615344565b505050505050505050565b6001600160a01b0382163314806122635750600654604051632bb6fe4d60e21b81526001600160a01b0384811660048301523360248301529091169063aedbf93490604401602060405180830381865afa15801561223f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122639190615344565b6122ab5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b6044820152606401610552565b6001600160a01b0382166000908152600a60205260408120546103e8906122f3907f0000000000000000000000000000000000000000000000000000000000000001906155d6565b6122fd91906155a0565b90506000811161234f5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a206e6f2066656520746f2077697468647261770000006044820152606401610552565b6123836001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174168383613b96565b6001600160a01b0383166000818152600a602052604080822091909155517f66bf9186b00db666fc37aaffbb95a050c66e599e000c785c1dff0467d868f1b1906123d09084815260200190565b60405180910390a2505050565b6123e5612d29565b6105658282613cf7565b6123f7612d29565b611124886103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000018b6155a0565b612430612d29565b6001600160a01b0381166124955760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610552565b610e5b816134eb565b6001600160a01b03163b151590565b60006124be610e10620151806155a0565b6124ca610e10426155a0565b6124d491906155a0565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b9004909216606083015292935091600390829061254a908890612c28565b60ff1681526020808201929092526040908101600020815160e081018352905466ffffffffffffff8116825263ffffffff600160381b8204811694830194909452600160581b8104841692820192909252600160781b820483166060820152600160981b820483166080820152600160b81b8204831660a08201819052600160d81b90920490921660c0830152909150612605907f000000000000000000000000000000000000000000000000000000003b9aca00906155d6565b8411156126705760405162461bcd60e51b815260206004820152603360248201527f5a6b426f624163636f756e74696e673a2073696e676c65206469726563742064604482015272195c1bdcda5d0818d85c08195e18d959591959606a1b6064820152608401610552565b816000015161ffff168361ffff1611156126bb576040805160808101825261ffff85168152600060208201529281015160ff16908301526001600160481b0384166060830152612791565b83826060018181516126cd9190615881565b6001600160481b031690525060c081015161270f907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff166155d6565b82606001516001600160481b031611156127915760405162461bcd60e51b815260206004820152603760248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206469726560448201527f6374206465706f736974206361702065786365656465640000000000000000006064820152608401610552565b506001600160a01b039390931660009081526005602090815260409182902085518154928701519387015160609097015161ffff9091166001600160581b031990931692909217620100006001600160481b03948516021769ffffffffffffffffffff60581b1916600160581b60ff9097169690960268ffffffffffffffffff60601b191695909517600160601b9290911691909102179092555050565b6040805160c08101825260015466ffffffffffffff8116825263ffffffff600160381b8204811660208085019190915262ffffff600160581b8404811685870152600160701b84041660608501526001600160581b03600160881b8404166080850152600160e01b9092041660a083015282519081019092526002546001600160481b0316825260009182918291826128ca610e10426155a0565b60a084015163ffffffff1694509050831580159061290857506128f2610e1062093a806155a0565b604084015161290190836158ac565b62ffffff16115b15612a1e576040838101805162ffffff9081166000908152600460208181528583208651606081018852905480861682526301000000810463ffffffff16828401908152600160381b9091046001600160581b03168289015286518616855292909152948220805471ffffffffffffffffffffffffffffffffffff1916905584519092169092525160a086015161299f91906158d0565b9050846020015163ffffffff168163ffffffff1611156129c65763ffffffff811660208601525b60008163ffffffff16836040015187608001516129e391906158ed565b6129ed919061590d565b9050856000015166ffffffffffffff168166ffffffffffffff161115612a1a5766ffffffffffffff811686525b5050505b8062ffffff16836060015162ffffff161015612ad957604080516060808201835262ffffff80851680845260a088015163ffffffff908116602080870191825260808b01516001600160581b03908116888a01908152968c018051871660009081526004909352989091209651875492519651909116600160381b0271ffffffffffffffffffffff00000000000000199690931663010000000266ffffffffffffff1990921694169390931792909217929092161790915590525b8151612b06907f000000000000000000000000000000000000000000000000000000003b9aca0090615927565b6001600160481b031683608001818151612b209190615941565b6001600160581b031690525060a08301805190612b3c82615963565b63ffffffff169052508615612b5657612b56828989613e32565b5050805160018054602084015160408501516060860151608087015160a09097015166ffffffffffffff87166001600160581b031990951694909417600160381b63ffffffff808616919091029190911765ffffffffffff60581b1916600160581b62ffffff9485160262ffffff60701b191617600160701b93909216929092021770ffffffffffffffffffffffffffffffffff16600160881b6001600160581b03909716969096026001600160e01b031695909517600160e01b959092169490940217905596909550909350915050565b600080612c537f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f645490565b905060ff8316158015612c6e57506001600160a01b03811615155b15612d1e57604051630a364e7560e41b81526001600160a01b038581166004830152600091829184169063a364e750906024016040805180830381865afa158015612cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ce19190615986565b91509150818015612d0c575060ff811660009081526003602052604090205466ffffffffffffff1615155b15612d1b579250612d23915050565b50505b829150505b92915050565b612d31614736565b6111405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610552565b60ff8860ff1610612ddc5760405162461bcd60e51b815260206004820152602360248201527f5a6b426f624163636f756e74696e673a20696e76616c6964206c696d6974207460448201526234b2b960e91b6064820152608401610552565b60008311612e365760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a207a65726f206465706f7369742063616044820152600760fc1b6064820152608401610552565b612e677f000000000000000000000000000000000000000000000000000000003b9aca0066ffffffffffffff6155d6565b871115612ec15760405162461bcd60e51b815260206004820152602260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6172604482015261676560f01b6064820152608401610552565b612eef7f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff6155d6565b861115612f535760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526b617020746f6f206c6172676560a01b6064820152608401610552565b612f817f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff6155d6565b851115612fe85760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526e6c2063617020746f6f206c6172676560881b6064820152608401610552565b828410156130505760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526e7369742063617020746f6f206c6f7760881b6064820152608401610552565b838610156130b35760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f7369742063604482015269617020746f6f206c6f7760b01b6064820152608401610552565b858710156131035760405162461bcd60e51b815260206004820181905260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6f776044820152606401610552565b600085116131665760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a207a65726f206461696c792077697468604482015269064726177616c206361760b41b6064820152608401610552565b808210156131d55760405162461bcd60e51b815260206004820152603660248201527f5a6b426f624163636f756e74696e673a206461696c79207573657220646972656044820152756374206465706f7369742063617020746f6f206c6f7760501b6064820152608401610552565b60006040518060e001604052807f000000000000000000000000000000000000000000000000000000003b9aca008a61320e91906155a0565b66ffffffffffffff1681526020016132467f000000000000000000000000000000000000000000000000000000003b9aca008a6155a0565b63ffffffff16815260200161327b7f000000000000000000000000000000000000000000000000000000003b9aca00896155a0565b63ffffffff1681526020016132b07f000000000000000000000000000000000000000000000000000000003b9aca00886155a0565b63ffffffff1681526020016132e57f000000000000000000000000000000000000000000000000000000003b9aca00876155a0565b63ffffffff16815260200161331a7f000000000000000000000000000000000000000000000000000000003b9aca00856155a0565b63ffffffff16815260200161334f7f000000000000000000000000000000000000000000000000000000003b9aca00866155a0565b63ffffffff90811690915260ff8b16600081815260036020908152604091829020855181549287015184880151606089015160808a015160a08b015160c08c01518b16600160d81b0263ffffffff60d81b19918c16600160b81b0263ffffffff60b81b19938d16600160981b029390931667ffffffffffffffff60981b19948d16600160781b0263ffffffff60781b19968e16600160581b029690961667ffffffffffffffff60581b1997909d16600160381b026001600160581b0319909a1666ffffffffffffff909816979097179890981794909416999099179190911716919091179590951794909416179092559051919250907f3cb26612e7105331adad836a65ae9b7f1d30a9e469ec70510a7c7ea36b0185ed906134d8908490600060e08201905066ffffffffffffff8351168252602083015163ffffffff80821660208501528060408601511660408501528060608601511660608501528060808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60405180910390a2505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000600161354b600260086155d6565b6001901b6135599190615744565b6135d56020600261010082816008600e600684613577816004615533565b6135819190615533565b61358b9190615533565b6135959190615533565b61359f9190615533565b6135a99190615533565b6135b39190615533565b6135bd9190615533565b6135c79190615533565b6135d19190615744565b3590565b16905090565b60008060006135e861477a565b9150915061365561364e6135fb60043590565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b8383614797565b9250505090565b600061129060206014600880600280610100868185600e600684613681816004615533565b61368b9190615533565b6136959190615533565b61369f9190615533565b6135779190615533565b600061129060206008600e60068361359f816004615533565b600061129060206006816135b3816004615533565b6136df614e9d565b6136e76147bf565b815260043560208201526136f9613843565b6040820152600861370c600e6006615533565b6137169190615533565b6137219060086155d6565b7f0000000000000000000000000000000000000000000000000000000000000000901b61374c613854565b6137569190615533565b60608201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016137846147e9565b6040516137929291906159c8565b6040519081900390206137a591906159d8565b608082015290565b3660006008600e600660206137c3816004615533565b6137cd9190615533565b6137d79190615533565b6137e19190615533565b612d239190615533565b6137f3614ebb565b8181526137fe6138b3565b602082015261380b613843565b6040820152919050565b36600060206101006008600e60068461382f816004615533565b6138399190615533565b6137c39190615533565b60006112906135d160206004615533565b600060016008613866600e6006615533565b6138709190615533565b61387b9060086155d6565b6001901b6138899190615744565b6135d56020600861389c600e6006615533565b6138a69190615533565b60206135b3816004615533565b60006112906101006008600e600660206138ce816004615533565b6138d89190615533565b6138e29190615533565b6138ec9190615533565b6138f69190615533565b6135d19190615533565b3660008061390c614879565b90506000816002806101006020816008600e60068461392c816004615533565b6139369190615533565b6139409190615533565b61394a9190615533565b6139549190615533565b61395e9190615533565b6139689190615533565b6139729190615533565b61397c9190615533565b6139869190615533565b6139909190615533565b905060008261399d6148c0565b6139a79190615744565b91959194509092505050565b600060016139c26008806155d6565b6001901b6139d09190615744565b6135d560206008600280610100848185600e600684613695816004615533565b60006112906020600e6006826135a9816004615533565b6040516001600160a01b0380851660248301528316604482015260648101829052613a729085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148fd565b50505050565b60006001613a876008806155d6565b6001901b613a959190615744565b6135d56020600880600280610100858185600e60068461368b816004615533565b600b546000906001600160a01b03168015613b8c57613aff6001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174168285613b96565b604051630802e33b60e41b81526001600160a01b038581166004830152602482018590526000919083169063802e33b09060440160408051808303816000875af1158015613b51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7591906159ec565b9150613b8390508185615744565b92505050612d23565b5060009392505050565b6040516001600160a01b038316602482015260448101829052613bc690849063a9059cbb60e01b90606401613a3b565b505050565b6000806000613bd86149cf565b919450925090506001600160a01b037f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841741663e3ee160e87306103e8613c3d7f00000000000000000000000000000000000000000000000000000000000000018a6155d6565b613c4791906155a0565b6000613c51614a06565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201529490931660248501526044840191909152606483015267ffffffffffffffff16608482015260a4810188905260ff861660c482015260e48101859052610104810184905261012401600060405180830381600087803b158015613cd757600080fd5b505af1158015613ceb573d6000803e3d6000fd5b50505050505050505050565b8160ff1660ff1480613d23575060ff821660009081526003602052604090205466ffffffffffffff1615155b613d865760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206e6f6e2d6578697374696e6720706f60448201526d37b6103634b6b4ba39903a34b2b960911b6064820152608401610552565b60005b8151811015613bc6576000828281518110613da657613da66159b2565b6020908102919091018101516001600160a01b038116600081815260058452604090819020805460ff60581b1916600160581b60ff8b16908102919091179091558151928352938201939093529092507f1283ebeb150dffd4da976f64c81e074fd4dc895cb64995dc46f13c9fd96a9551910160405180910390a150613e2b81615a10565b9050613d89565b6001600160a01b038216158015613e495750600081135b15613e955760028054829190600090613e6c9084906001600160481b0316615881565b92506101000a8154816001600160481b0302191690836001600160481b03160217905550505050565b6000613ea6610e10620151806155a0565b613eb2610e10426155a0565b613ebc91906155a0565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b90049092166060830152929350916003908290613f32908890612c28565b60ff16815260208082019290925260409081016000908120825160e081018452815466ffffffffffffff8116825263ffffffff600160381b8204811683880152600160581b808304821684880152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015285519182018652600184015461ffff811683526001600160481b03620100008204811698840198909852049095169385019390935293509091908613156144e5578751869081908a90614012908390615881565b6001600160481b03169052506080830151614054907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff166155d6565b8111156140b85760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a2073696e676c65206465706f7369742060448201526b18d85c08195e18d95959195960a21b6064820152608401610552565b82516140ee907f000000000000000000000000000000000000000000000000000000003b9aca009066ffffffffffffff166155d6565b89516001600160481b031611156141515760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a2074766c2063617020657863656564656044820152601960fa1b6064820152608401610552565b846000015161ffff168661ffff16111561426f5760405180608001604052808761ffff168152602001826001600160481b03168152602001866040015160ff16815260200160006001600160481b0316815250600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160481b0302191690836001600160481b03160217905550604082015181600001600b6101000a81548160ff021916908360ff160217905550606082015181600001600c6101000a8154816001600160481b0302191690836001600160481b031602179055509050506143ce565b80856020018181516142819190615881565b6001600160481b031690525060608301516142c3907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff166155d6565b85602001516001600160481b031611156143385760405162461bcd60e51b815260206004820152603060248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526f1cda5d0818d85c08195e18d95959195960821b6064820152608401610552565b6001600160a01b03881660009081526005602090815260409182902087518154928901519389015160608a01516001600160481b03908116600160601b0268ffffffffffffffffff60601b1960ff909316600160581b029290921669ffffffffffffffffffff60581b199190961662010000026001600160581b031990951661ffff909316929092179390931716929092171790555b816000015161ffff168661ffff16111561441b5760405180606001604052808761ffff168152602001826001600160481b0316815260200160006001600160481b031681525091506144df565b808260200181815161442d9190615881565b6001600160481b0316905250602083015161446f907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff166155d6565b82602001516001600160481b031611156144df5760405162461bcd60e51b815260206004820152602b60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526a185c08195e18d95959195960aa1b6064820152608401610552565b506146b5565b60006144f087615728565b90506145207f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff6155d6565b8111156145845760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a207769746864726177616c20616d6f7560448201526b6e7420746f6f206c6172676560a01b6064820152608401610552565b80896000018181516145969190615a29565b6001600160481b0316905250815161ffff90811690871611156145ec5760405180606001604052808761ffff16815260200160006001600160481b03168152602001826001600160481b031681525091506146b3565b80826040018181516145fe9190615881565b6001600160481b03169052506040830151614640907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff166155d6565b82604001516001600160481b031611156146b35760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526d1b0818d85c08195e18d95959195960921b6064820152608401610552565b505b9651600280546001600160481b0392831668ffffffffffffffffff199091161790558751600193909301805460208a01516040909a01518316600160581b0268ffffffffffffffffff60581b199a90931662010000026001600160581b031990911661ffff9095169490941793909317979097169690961790555050505050565b6000614740614a29565b8061129057507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035433905b6001600160a01b031614905090565b6000806000614787614a3d565b8035946020909101359350915050565b60008060006147a7868686614ac6565b915091506147b481614aff565b5090505b9392505050565b6000600860006147cd6136c2565b65ffffffffffff16815260200190815260200160002054905090565b366000806002806101006020816008600e600684614808816004615533565b6148129190615533565b61481c9190615533565b6148269190615533565b6148309190615533565b61483a9190615533565b6148449190615533565b61484e9190615533565b6148589190615533565b6148629190615533565b9050600061486e6148c0565b919491935090915050565b60008061488461353b565b90508015806148935750806001145b156148a057600891505090565b806002036148b057602491505090565b806003036101e457602491505090565b600060016148d0600260086155d6565b6001901b6148de9190615744565b6135d5602060028061010083816008600e60068461369f816004615533565b6000614952826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c499092919063ffffffff16565b805190915015613bc657808060200190518101906149709190615344565b613bc65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b60008060008060006149df61477a565b90925090506149f360ff82901c601b615533565b959194506001600160ff1b031692509050565b60006112906020600880600280610100858185600e60068461368b816004615533565b6000805433906001600160a01b031661476b565b6000614a476148c0565b6002806101006020816008600e600684614a62816004615533565b614a6c9190615533565b614a769190615533565b614a809190615533565b614a8a9190615533565b614a949190615533565b614a9e9190615533565b614aa89190615533565b614ab29190615533565b614abc9190615533565b6112909190615533565b6000806001600160ff1b03831681614ae360ff86901c601b615533565b9050614af187828885614c60565b935093505050935093915050565b6000816004811115614b1357614b13615a49565b03614b1b5750565b6001816004811115614b2f57614b2f615a49565b03614b7c5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610552565b6002816004811115614b9057614b90615a49565b03614bdd5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610552565b6003816004811115614bf157614bf1615a49565b03610e5b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610552565b6060614c588484600085614d24565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614c975750600090506003614d1b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614ceb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614d1457600060019250925050614d1b565b9150600090505b94509492505050565b606082471015614d855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b600080866001600160a01b03168587604051614da19190615a5f565b60006040518083038185875af1925050503d8060008114614dde576040519150601f19603f3d011682016040523d82523d6000602084013e614de3565b606091505b5091509150614df487838387614dff565b979650505050505050565b60608315614e6e578251600003614e67576001600160a01b0385163b614e675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b5081614c58565b614c588383815115614e835781518083602001fd5b8060405162461bcd60e51b81526004016105529190615577565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b0381168114610e5b57600080fd5b60008060408385031215614f0157600080fd5b8235614f0c81614ed9565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715614f5957614f59614f1a565b604052919050565b600082601f830112614f7257600080fd5b60405161010080820182811067ffffffffffffffff82111715614f9757614f97614f1a565b60405283018185821115614faa57600080fd5b845b82811015614fc4578035825260209182019101614fac565b509195945050505050565b6000806000806000806102608789031215614fe957600080fd5b86359550602087013567ffffffffffffffff8082111561500857600080fd5b818901915089601f83011261501c57600080fd5b81358181111561502b57600080fd5b8a60208260051b850101111561504057600080fd5b602083019750809650505050604087013592506150608860608901614f61565b9150615070886101608901614f61565b90509295509295509295565b60006020828403121561508e57600080fd5b81356147b881614ed9565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e08301526101008084015181840152506101208084015161510d8285018260ff169052565b50506101408381015190830152610160808401519083015261018092830151929091019190915290565b60ff81168114610e5b57600080fd5b60006020828403121561515857600080fd5b81356147b881615137565b600080600080600080600080610100898b03121561518057600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b6000602082840312156151ca57600080fd5b5035919050565b600080604083850312156151e457600080fd5b82356151ef81614ed9565b915060208301356151ff81614ed9565b809150509250929050565b6000806040838503121561521d57600080fd5b823561522881615137565b915060208381013567ffffffffffffffff8082111561524657600080fd5b818601915086601f83011261525a57600080fd5b81358181111561526c5761526c614f1a565b8060051b915061527d848301614f30565b818152918301840191848101908984111561529757600080fd5b938501935b838510156152c157843592506152b183614ed9565b828252938501939085019061529c565b8096505050505050509250929050565b600080600080600080600080610100898b0312156152ee57600080fd5b88356152f981615137565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b8051801515811461533f57600080fd5b919050565b60006020828403121561535657600080fd5b6147b88261532f565b6040808252810183905260006001600160fb1b0384111561537f57600080fd5b8360051b8086606085013760009083016060019081526020909201929092529392505050565b60005b838110156153c05781810151838201526020016153a8565b83811115613a725750506000910152565b600080600080608085870312156153e757600080fd5b845193506020850151925060408501519150606085015167ffffffffffffffff8082111561541457600080fd5b818701915087601f83011261542857600080fd5b81518181111561543a5761543a614f1a565b61544d601f8201601f1916602001614f30565b915080825288602082850101111561546457600080fd5b6154758160208401602086016153a5565b5094979396509194505050565b8060005b6008811015613a72578151845260209384019390910190600101615486565b6101208101818460005b60018110156154ce5781518352602092830192909101906001016154af565b5050506147b86020830184615482565b8060005b6003811015613a725781518452602093840193909101906001016154e2565b610160810161551082856154de565b6147b86060830184615482565b634e487b7160e01b600052601160045260246000fd5b600082198211156155465761554661551d565b500190565b600081518084526155638160208601602086016153a5565b601f01601f19169290920160200192915050565b6020815260006147b8602083018461554b565b634e487b7160e01b600052601260045260246000fd5b6000826155af576155af61558a565b500490565b600062ffffff808416806155ca576155ca61558a565b92169190910492915050565b60008160001904831182151516156155f0576155f061551d565b500290565b6101a08101818460005b600581101561561e5781518352602092830192909101906001016155ff565b5050506101008360a0840137600081529392505050565b610160810161564482856154de565b610100836060840137600081529392505050565b805160208201516001600160e01b031980821692919060048310156156875780818460040360031b1b83161693505b505050919050565b600080821280156001600160ff1b03849003851316156156b1576156b161551d565b600160ff1b83900384128116156156ca576156ca61551d565b50500190565b6000826156df576156df61558a565b500790565b60208082526024908201527f5a6b426f62506f6f6c3a20696e636f7272656374206465706f73697420616d6f604082015263756e747360e01b606082015260800190565b6000600160ff1b820161573d5761573d61551d565b5060000390565b6000828210156157565761575661551d565b500390565b60006020828403121561576d57600080fd5b5051919050565b60006020828403121561578657600080fd5b81516147b881615137565b600181815b808511156157cc5781600019048211156157b2576157b261551d565b808516156157bf57918102915b93841c9390800290615796565b509250929050565b6000826157e357506001612d23565b816157f057506000612d23565b816001811461580657600281146158105761582c565b6001915050612d23565b60ff8411156158215761582161551d565b50506001821b612d23565b5060208310610133831016604e8410600b841016171561584f575081810a612d23565b6158598383615791565b806000190482111561586d5761586d61551d565b029392505050565b60006147b883836157d4565b60006001600160481b038083168185168083038211156158a3576158a361551d565b01949350505050565b600062ffffff838116908316818110156158c8576158c861551d565b039392505050565b600063ffffffff838116908316818110156158c8576158c861551d565b60006001600160581b03838116908316818110156158c8576158c861551d565b60006001600160581b03808416806155ca576155ca61558a565b60006001600160481b03808416806155ca576155ca61558a565b60006001600160581b038083168185168083038211156158a3576158a361551d565b600063ffffffff80831681810361597c5761597c61551d565b6001019392505050565b6000806040838503121561599957600080fd5b6159a28361532f565b915060208301516151ff81615137565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b6000826159e7576159e761558a565b500690565b600080604083850312156159ff57600080fd5b505080516020909101519092909150565b600060018201615a2257615a2261551d565b5060010190565b60006001600160481b03838116908316818110156158c8576158c861551d565b634e487b7160e01b600052602160045260246000fd5b60008251615a718184602087016153a5565b919091019291505056fea2646970667358221220fa7609678ac81c6da4f63b538c6ee0aad8ce3e88b670453eb9eb6fac1d4dfaa364736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000a86c511832ead78d30ad49711874a9f3a1dfb84000000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d0000000000000000000000009a7b4198065efe631a962e737bdfe1f44f2cb3ee000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf289
-----Decoded View---------------
Arg [0] : __pool_id (uint256): 0
Arg [1] : _token (address): 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
Arg [2] : _transfer_verifier (address): 0xA86C511832eAd78d30ad49711874a9F3a1dfb840
Arg [3] : _tree_verifier (address): 0x82907eAeB25D248dC82033E45b00A3E012Ba2d0D
Arg [4] : _batch_deposit_verifier (address): 0x9a7B4198065efE631a962e737bDfE1f44f2CB3EE
Arg [5] : _direct_deposit_queue (address): 0x668c5286eAD26fAC5fa944887F9D2F20f7DDF289
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174
Arg [2] : 000000000000000000000000a86c511832ead78d30ad49711874a9f3a1dfb840
Arg [3] : 00000000000000000000000082907eaeb25d248dc82033e45b00a3e012ba2d0d
Arg [4] : 0000000000000000000000009a7b4198065efe631a962e737bdfe1f44f2cb3ee
Arg [5] : 000000000000000000000000668c5286ead26fac5fa944887f9d2f20f7ddf289
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in POL
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.