Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ZkBobPoolUSDCMigrated
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "./ZkBobPool.sol";
import "./ZkBobTokenSellerMixin.sol";
import "./ZkBobUSDCPermitMixin.sol";
/**
* @title ZkBobPoolUSDCMigrated
* Shielded transactions pool for USDC tokens supporting USDC transfer authorizations
* It is intended to be deployed as implemenation of the pool for BOB tokens that is
* why it supports the same nomination
*/
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, // Make sure that TOKEN_NUMERATOR is set in 1000 in ZkBobPool and ZkBobDirectDepositQueue
1_000_000_000
)
{}
function migrationToUSDC() external {
require(msg.sender == address(this), "Incorrect invoker");
require(token == address(0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85), "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 usdc_decimals = IERC20Metadata(token).decimals();
ISwapRouter swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
bool retval = IERC20(bob_addr).approve(address(swapRouter), cur_bob_balance);
uint256 usdc_received = swapRouter.exactInput(
ISwapRouter.ExactInputParams({
path: abi.encodePacked(
bob_addr, uint24(100), 0x7F5c764cBc14f9669B88837ca1490cCa17c31607, uint24(100), token
),
recipient: address(this),
deadline: block.timestamp,
amountIn: cur_bob_balance,
amountOutMinimum: cur_bob_balance * 995 / 1e15
})
);
require(IERC20(bob_addr).balanceOf(address(this)) == 0, "Incorrect swap");
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: 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: 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 "./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: 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/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.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: 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: 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": [
"@openzeppelin/contracts/=lib/@openzeppelin/contracts/contracts/",
"@gnosis/auction/=lib/@gnosis/auction/contracts/",
"@base58-solidity/=lib/base58-solidity/contracts/",
"forge-std/=lib/forge-std/src/",
"@uniswap/=lib/@uniswap/",
"base58-solidity/=lib/base58-solidity/contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {
"lib/base58-solidity/contracts/Base58.sol": {
"Base58": "0x5eef7f755ff1a6e9ddd33e75c84a6888f6f43ed4"
},
"src/libraries/ZkAddress.sol": {
"ZkAddress": "0x5524e24bd944480def40cc69120cab066121e9fc"
}
}
}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
6101806040523480156200001257600080fd5b506040516200618338038062006183833981016040819052620000359162000351565b8585858585856001633b9aca00806200004e33620002d9565b60805262ffffff881115620000aa5760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a2065786365656473206d617820706f6f6c206964000060448201526064015b60405180910390fd5b620000c0876200032960201b620025461760201c565b620000fd5760405162461bcd60e51b81526020600482015260196024820152600080516020620061638339815191526044820152606401620000a1565b62000113866200032960201b620025461760201c565b620001505760405162461bcd60e51b81526020600482015260196024820152600080516020620061638339815191526044820152606401620000a1565b62000166856200032960201b620025461760201c565b620001a35760405162461bcd60e51b81526020600482015260196024820152600080516020620061638339815191526044820152606401620000a1565b620001b9846200032960201b620025461760201c565b620001f65760405162461bcd60e51b81526020600482015260196024820152600080516020620061638339815191526044820152606401620000a1565b6200020c836200032960201b620025461760201c565b620002495760405162461bcd60e51b81526020600482015260196024820152600080516020620061638339815191526044820152606401620000a1565b816001146200029b5760405162461bcd60e51b815260206004820181905260248201527f5a6b426f62506f6f6c3a20696e636f72726563742064656e6f6d696e61746f726044820152606401620000a1565b5060c0969096526001600160a01b039485166101405292841660e05290831661010052821661012052166101605260a05250620003d9945050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03163b151590565b6001600160a01b03811681146200034e57600080fd5b50565b60008060008060008060c087890312156200036b57600080fd5b8651955060208701516200037f8162000338565b6040880151909550620003928162000338565b6060880151909450620003a58162000338565b6080880151909350620003b88162000338565b60a0880151909250620003cb8162000338565b809150509295509295509295565b60805160a05160c05160e05161010051610120516101405161016051615bb1620005b2600039600081816102a7015281816104ed01526106370152600081816104c00152818161191901528181611ae101528181611d3501528181611e9801528181611fff015281816121c40152818161240401528181613b800152613c9101526000818161039c015261070e0152600081816102e10152818161081b01526115a301526000818161024101526114a30152600081816103ea01526137cb015260008181610fa601528181610fdd015281816110140152818161104b01528181611082015281816110b9015281816110f0015281816118e001528181611a2f01528181611a7301528181612376015281816124ab0152613cc0015260008181610baa01528181610bfb01528181610c6501528181610ccf01528181610d3901528181610d7d01528181610de7015281816126880152818161278c01528181612b8901528181612ee301528181612f6e015281816130000152818161328c015281816132c9015281816132fe01528181613333015281816133680152818161339d015281816133d2015281816140d10152818161416801528181614340015281816144ec0152818161459f01526146bd0152615bb16000f3fe608060405234801561001057600080fd5b50600436106101e45760003560e01c80637a22393b1161010f578063c41100fa116100a2578063e0ec037411610071578063e0ec037414610482578063e8fd02e414610495578063f2fde38b146104a8578063fc0c546a146104bb57600080fd5b8063c41100fa14610434578063c4a688b814610447578063c879c6d81461044f578063d21e82ab1461046257600080fd5b806396ce0795116100de57806396ce0795146103d75780639d8ad6e4146103e5578063af9890831461040c578063c2b40ae41461041457600080fd5b80637a22393b1461038457806383f26e3b146103975780638da5cb5b146103be5780638fff4676146103cf57600080fd5b80632f84c96f11610187578063508400401161015657806350840040146103365780636d55160c14610356578063715018a614610369578063790c3a331461037157600080fd5b80632f84c96f146102c95780633701f979146102dc5780634279a99e1461030357806346adf6ce1461032357600080fd5b80631cbec711116101c35780631cbec711146102635780631dc4cb33146102785780631dd69d061461028b5780632747f41d146102a257600080fd5b80622befce146101e95780630c6248de14610229578063171ef3001461023c575b600080fd5b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f64545b6040516001600160a01b0390911681526020015b60405180910390f35b600b5461020c906001600160a01b031681565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b610276610271366004614f96565b6104e2565b005b610276610286366004615077565b610569565b61029460095481565b604051908152602001610220565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b60065461020c906001600160a01b031681565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b610316610311366004615124565b6109c0565b6040516102209190615141565b6102766103313660046151ee565b610e2b565b610294610344366004615124565b600a6020526000908152604090205481565b61027661036436600461520b565b610e5e565b61027661112e565b61027661037f366004615124565b611142565b610276610392366004615124565b611218565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031661020c565b61029461126e565b6103e8600160ff1b01610294565b6102947f000000000000000000000000000000000000000000000000000000000000000081565b610276611295565b610294610422366004615260565b60086020526000908152604090205481565b610276610442366004615124565b611c39565b610276611cf0565b61027661045d366004615279565b612285565b610294610470366004615260565b60076020526000908152604090205481565b6102766104903660046152b2565b612485565b6102766104a3366004615379565b612497565b6102766104b6366004615124565b6124d0565b61020c7f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461055b5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b60448201526064015b60405180910390fd5b6105658282612555565b5050565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e391906153ec565b61062f5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e24546f28a8a8a6040518463ffffffff1660e01b815260040161068593929190615407565b6000604051808303816000875af11580156106a4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106cc9190810190615479565b935093509350935060006106e16000866128d7565b604080516020810182528781529051633cac775b60e01b8152919450600785901b93506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169250633cac775b9161074591908c9060040161554d565b602060405180830381865afa158015610762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078691906153ec565b6107dd5760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a20626164206261746368206465706f7369742070726f60448201526137b360f11b6064820152608401610552565b604080516060810182526000838152600860209081529083902054825281018e90528082018b905290516345bb94c160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906345bb94c1906108529084908c906004016155a9565b602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089391906153ec565b6108db5760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6108e66080836155db565b91508c600860008481526020019081526020016000208190555060008480519060200120905060006009548260405160200161092c929190918252602082015260400190565b60408051601f19818403018152919052805160209091012060098190559050871561097657336000908152600a6020526040812080548a92906109709084906155db565b90915550505b80847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536886040516109a7919061561f565b60405180910390a3505050505050505050505050505050565b610a2e604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff1681526020016000815260200160008152602001600081525090565b60408051602080820183526002546001600160481b0390811683526001600160a01b0386166000908152600583528481208551608081018752905461ffff8116825262010000810484169482019490945260ff600160581b850416958101869052600160601b90930490911660608301529192909190610aaf908690612cd0565b60ff81166000908152600360209081526040808320815160e081018352815466ffffffffffffff8116825263ffffffff600160381b8204811683870152600160581b808304821684870152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015284519182018552600184015461ffff811683526001600160481b03620100008204811697840197909752049094169284019290925293945091610b7d610e1042615648565b90506000610b90610e1062015180615648565b610b9a908361565c565b9050604051806101a001604052807f0000000000000000000000000000000000000000000000000000000000000000866000015166ffffffffffffff16610be1919061567e565b815260200189600001516001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866020015163ffffffff16610c2f919061567e565b81526020018262ffffff16856000015161ffff1614610c4f576000610c55565b84602001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866040015163ffffffff16610c99919061567e565b81526020018262ffffff16856000015161ffff1614610cb9576000610cbf565b84604001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866060015163ffffffff16610d03919061567e565b81526020018262ffffff16896000015161ffff1614610d23576000610d29565b88602001515b6001600160481b031681526020017f0000000000000000000000000000000000000000000000000000000000000000866080015163ffffffff16610d6d919061567e565b81526020018760ff1681526020017f00000000000000000000000000000000000000000000000000000000000000008660c0015163ffffffff16610db1919061567e565b81526020018262ffffff16896000015161ffff1614610dd1576000610dd7565b88606001515b6001600160481b031681526020017f00000000000000000000000000000000000000000000000000000000000000008660a0015163ffffffff16610e1b919061567e565b90529a9950505050505050505050565b610e33612dd1565b610e5b8160ff16600090815260036020526040902060010180546001600160a01b0319169055565b50565b333014610ead5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420696e697469616c697a65720000000000006044820152606401610552565b6000805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c75415610f255760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a20616c726561647920696e697469616c697a656400006044820152606401610552565b87600003610f6c5760405162461bcd60e51b8152602060048201526014602482015273169ad09bd8941bdbdb0e881e995c9bc81c9bdbdd60621b6044820152606401610552565b600080805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c7899055611124906103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000008b615648565b610fd5919061567e565b6103e86110027f00000000000000000000000000000000000000000000000000000000000000008b615648565b61100c919061567e565b6103e86110397f00000000000000000000000000000000000000000000000000000000000000008b615648565b611043919061567e565b6103e86110707f00000000000000000000000000000000000000000000000000000000000000008b615648565b61107a919061567e565b6103e86110a77f00000000000000000000000000000000000000000000000000000000000000008b615648565b6110b1919061567e565b6103e86110de7f00000000000000000000000000000000000000000000000000000000000000008b615648565b6110e8919061567e565b6103e86111157f00000000000000000000000000000000000000000000000000000000000000008b615648565b61111f919061567e565b612e25565b5050505050505050565b611136612dd1565b6111406000613593565b565b61114a612dd1565b6001600160a01b0381163b6111b45760405162461bcd60e51b815260206004820152602a60248201527f4b796350726f7669646572734d616e6167657253746f726167653a206e6f7420604482015269184818dbdb9d1c9858dd60b21b6064820152608401610552565b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f648190556040516001600160a01b03821681527fcfca215f2134266880a5d2c68d2f52493a9d57fe6dd1245086a201e78871348e906020015b60405180910390a150565b611220612dd1565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fdf71641930ea322cb32f687f4d292a0af694c81216254f204c930092593d82829060200161120d565b6000600761128960015463ffffffff600160e01b9091041690565b901b905090565b905090565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f91906153ec565b61135b5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b3360006113666135e3565b90508060000361137f57611378613683565b91506113a2565b8060020361138f57611378613704565b806003036113a25761139f613704565b91505b60006113ac613751565b60070b905060006113bd84836128d7565b9250505060006113cc60043590565b60008181526007602081905260409091205491925083901b90156114325760405162461bcd60e51b815260206004820152601f60248201527f5a6b426f62506f6f6c3a20646f75626c657370656e64206465746563746564006044820152606401610552565b8061143b61376a565b65ffffffffffff1611156114a15760405162461bcd60e51b815260206004820152602760248201527f5a6b426f62506f6f6c3a207472616e7366657220696e646578206f7574206f6660448201526620626f756e647360c81b6064820152608401610552565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368444dc76114d861377f565b6114e0613855565b6040518363ffffffff1660e01b81526004016114fd92919061569d565b602060405180830381865afa15801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e91906153ec565b61158a5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164207472616e736665722070726f6f660000006044820152606401610552565b6000818152600860205260409020546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906345bb94c1906115d390613893565b6115db6138bd565b6040518363ffffffff1660e01b81526004016115f89291906156dd565b602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163991906153ec565b6116815760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6116896138eb565b6116916138fc565b60408051602081019390935282015260600160408051601f198184030181529181528151602092830120600085815260079093529120556116d36080826155db565b90506116dd61395b565b6000828152600860205260408120919091556116f76139a8565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945061173992508491506157009050565b61ffff60e01b161461178d5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164206d657373616765207072656669780000006044820152606401610552565b6000818051906020012090506000600954826040516020016117b9929190918252602082015260400190565b6040516020818303038152906040528051906020012090508060098190555080847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c737353685604051611809919061561f565b60405180910390a350505050600061181f613a5b565b9050600061182d8286615737565b90506000611839613a98565b600d0b905061184a6103e883615778565b156118a15760405162461bcd60e51b815260206004820152602160248201527f5a6b426f62506f6f6c3a20696e636f727265637420746f6b656e20616d6f756e6044820152601d60fa1b6064820152608401610552565b86600003611946576000861380156118b7575080155b6118d35760405162461bcd60e51b81526004016105529061578c565b61194188306103e86119057f00000000000000000000000000000000000000000000000000000000000000008761567e565b61190f9190615648565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016929190613aaf565b611c05565b866001036119b4578115801561195a575080155b6119415760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f7272656374207472616e7366657220616d6044820152646f756e747360d81b6064820152608401610552565b86600203611b7257600082131580156119ce575060008113155b611a285760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f727265637420776974686472617720616d6044820152646f756e747360d81b6064820152608401610552565b60006103e87f0000000000000000000000000000000000000000000000000000000000000000611a56613b20565b611a60919061567e565b611a6a9190615648565b905060006103e87f0000000000000000000000000000000000000000000000000000000000000000611a9b866157d0565b611aa5919061567e565b611aaf9190615648565b90508115611ace57611ac18a83613b5e565b611acb90826157ec565b90505b8015611b0857611b086001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b83613c3e565b6000831215611b6b5760405162461bcd60e51b815260206004820152602960248201527f5a6b426f62506f6f6c3a20585020636c61696d696e67206973206e6f742079656044820152681d08195b98589b195960ba1b6064820152608401610552565b5050611c05565b86600303611baf57600086138015611b88575080155b611ba45760405162461bcd60e51b81526004016105529061578c565b611941888584613c73565b60405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20496e636f7272656374207472616e73616374696f6e604482015264207479706560d81b6064820152608401610552565b821561112457336000908152600a602052604081208054859290611c2a9084906155db565b90915550505050505050505050565b611c41612dd1565b6001600160a01b038116611ca25760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a206d616e61676572206973207a65726f206164647265604482015261737360f01b6064820152608401610552565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f267052ecaebdd552dc1b20904f59d83d51ae7add7514165322a7da9ef6cf543b9060200161120d565b333014611d335760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba1034b73b37b5b2b960791b6044820152606401610552565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316730b2c639c533813f4aa9d7837caf62653d097ff8514611db15760405162461bcd60e51b815260206004820152600f60248201526e24b731b7b93932b1ba103a37b5b2b760891b6044820152606401610552565b6040516370a0823160e01b815230600482015273b0b195aefa3650a6908f15cdac7d92f8a5791b0b9060009082906370a0823190602401602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190615803565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061581c565b60ff16905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f18919061581c565b60405163095ea7b360e01b815273e592427a0aece92de3edee1f18e0157c05861564600482018190526024820186905260ff9290921692506000906001600160a01b0387169063095ea7b3906044016020604051808303816000875af1158015611f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611faa91906153ec565b6040805160a081019091526bffffffffffffffffffffffff19606089811b821660c0840152601960ea1b60d48401819052737f5c764cbc14f9669b88837ca1490cca17c3160760601b60d785015260eb8401527f0000000000000000000000000000000000000000000000000000000000000000901b1660ee8201529091506000906001600160a01b0384169063c04b8d599080610102810160408051601f198184030181529181529082523060208301524290820152606081018a905260800166038d7ea4c6800061207f8b6103e361567e565b6120899190615648565b8152506040518263ffffffff1660e01b81526004016120a89190615839565b6020604051808303816000875af11580156120c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120eb9190615803565b6040516370a0823160e01b81523060048201529091506001600160a01b038816906370a0823190602401602060405180830381865afa158015612132573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121569190615803565b156121945760405162461bcd60e51b815260206004820152600e60248201526d0496e636f727265637420737761760941b6044820152606401610552565b6000816121a186886157ec565b6121ac90600a615975565b6121b69089615648565b6121c091906157ec565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd6122036000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015612256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227a91906153ec565b505050505050505050565b6001600160a01b03821633148061230b5750600654604051632bb6fe4d60e21b81526001600160a01b0384811660048301523360248301529091169063aedbf93490604401602060405180830381865afa1580156122e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230b91906153ec565b6123535760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b6044820152606401610552565b6001600160a01b0382166000908152600a60205260408120546103e89061239b907f00000000000000000000000000000000000000000000000000000000000000009061567e565b6123a59190615648565b9050600081116123f75760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a206e6f2066656520746f2077697468647261770000006044820152606401610552565b61242b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168383613c3e565b6001600160a01b0383166000818152600a602052604080822091909155517f66bf9186b00db666fc37aaffbb95a050c66e599e000c785c1dff0467d868f1b1906124789084815260200190565b60405180910390a2505050565b61248d612dd1565b6105658282613d9f565b61249f612dd1565b611124886103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000008b615648565b6124d8612dd1565b6001600160a01b03811661253d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610552565b610e5b81613593565b6001600160a01b03163b151590565b6000612566610e1062015180615648565b612572610e1042615648565b61257c9190615648565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b900490921660608301529293509160039082906125f2908890612cd0565b60ff1681526020808201929092526040908101600020815160e081018352905466ffffffffffffff8116825263ffffffff600160381b8204811694830194909452600160581b8104841692820192909252600160781b820483166060820152600160981b820483166080820152600160b81b8204831660a08201819052600160d81b90920490921660c08301529091506126ad907f00000000000000000000000000000000000000000000000000000000000000009061567e565b8411156127185760405162461bcd60e51b815260206004820152603360248201527f5a6b426f624163636f756e74696e673a2073696e676c65206469726563742064604482015272195c1bdcda5d0818d85c08195e18d959591959606a1b6064820152608401610552565b816000015161ffff168361ffff161115612763576040805160808101825261ffff85168152600060208201529281015160ff16908301526001600160481b0384166060830152612839565b83826060018181516127759190615981565b6001600160481b031690525060c08101516127b7907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff1661567e565b82606001516001600160481b031611156128395760405162461bcd60e51b815260206004820152603760248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206469726560448201527f6374206465706f736974206361702065786365656465640000000000000000006064820152608401610552565b506001600160a01b039390931660009081526005602090815260409182902085518154928701519387015160609097015161ffff9091166001600160581b031990931692909217620100006001600160481b03948516021769ffffffffffffffffffff60581b1916600160581b60ff9097169690960268ffffffffffffffffff60601b191695909517600160601b9290911691909102179092555050565b6040805160c08101825260015466ffffffffffffff8116825263ffffffff600160381b8204811660208085019190915262ffffff600160581b8404811685870152600160701b84041660608501526001600160581b03600160881b8404166080850152600160e01b9092041660a083015282519081019092526002546001600160481b031682526000918291829182612972610e1042615648565b60a084015163ffffffff169450905083158015906129b0575061299a610e1062093a80615648565b60408401516129a990836159ac565b62ffffff16115b15612ac6576040838101805162ffffff9081166000908152600460208181528583208651606081018852905480861682526301000000810463ffffffff16828401908152600160381b9091046001600160581b03168289015286518616855292909152948220805471ffffffffffffffffffffffffffffffffffff1916905584519092169092525160a0860151612a4791906159d0565b9050846020015163ffffffff168163ffffffff161115612a6e5763ffffffff811660208601525b60008163ffffffff1683604001518760800151612a8b91906159ed565b612a959190615a0d565b9050856000015166ffffffffffffff168166ffffffffffffff161115612ac25766ffffffffffffff811686525b5050505b8062ffffff16836060015162ffffff161015612b8157604080516060808201835262ffffff80851680845260a088015163ffffffff908116602080870191825260808b01516001600160581b03908116888a01908152968c018051871660009081526004909352989091209651875492519651909116600160381b0271ffffffffffffffffffffff00000000000000199690931663010000000266ffffffffffffff1990921694169390931792909217929092161790915590525b8151612bae907f000000000000000000000000000000000000000000000000000000000000000090615a27565b6001600160481b031683608001818151612bc89190615a41565b6001600160581b031690525060a08301805190612be482615a63565b63ffffffff169052508615612bfe57612bfe828989613eda565b5050805160018054602084015160408501516060860151608087015160a09097015166ffffffffffffff87166001600160581b031990951694909417600160381b63ffffffff808616919091029190911765ffffffffffff60581b1916600160581b62ffffff9485160262ffffff60701b191617600160701b93909216929092021770ffffffffffffffffffffffffffffffffff16600160881b6001600160581b03909716969096026001600160e01b031695909517600160e01b959092169490940217905596909550909350915050565b600080612cfb7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f645490565b905060ff8316158015612d1657506001600160a01b03811615155b15612dc657604051630a364e7560e41b81526001600160a01b038581166004830152600091829184169063a364e750906024016040805180830381865afa158015612d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d899190615a86565b91509150818015612db4575060ff811660009081526003602052604090205466ffffffffffffff1615155b15612dc3579250612dcb915050565b50505b829150505b92915050565b612dd96147de565b6111405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610552565b60ff8860ff1610612e845760405162461bcd60e51b815260206004820152602360248201527f5a6b426f624163636f756e74696e673a20696e76616c6964206c696d6974207460448201526234b2b960e91b6064820152608401610552565b60008311612ede5760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a207a65726f206465706f7369742063616044820152600760fc1b6064820152608401610552565b612f0f7f000000000000000000000000000000000000000000000000000000000000000066ffffffffffffff61567e565b871115612f695760405162461bcd60e51b815260206004820152602260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6172604482015261676560f01b6064820152608401610552565b612f977f000000000000000000000000000000000000000000000000000000000000000063ffffffff61567e565b861115612ffb5760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526b617020746f6f206c6172676560a01b6064820152608401610552565b6130297f000000000000000000000000000000000000000000000000000000000000000063ffffffff61567e565b8511156130905760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526e6c2063617020746f6f206c6172676560881b6064820152608401610552565b828410156130f85760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526e7369742063617020746f6f206c6f7760881b6064820152608401610552565b8386101561315b5760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f7369742063604482015269617020746f6f206c6f7760b01b6064820152608401610552565b858710156131ab5760405162461bcd60e51b815260206004820181905260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6f776044820152606401610552565b6000851161320e5760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a207a65726f206461696c792077697468604482015269064726177616c206361760b41b6064820152608401610552565b8082101561327d5760405162461bcd60e51b815260206004820152603660248201527f5a6b426f624163636f756e74696e673a206461696c79207573657220646972656044820152756374206465706f7369742063617020746f6f206c6f7760501b6064820152608401610552565b60006040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000008a6132b69190615648565b66ffffffffffffff1681526020016132ee7f00000000000000000000000000000000000000000000000000000000000000008a615648565b63ffffffff1681526020016133237f000000000000000000000000000000000000000000000000000000000000000089615648565b63ffffffff1681526020016133587f000000000000000000000000000000000000000000000000000000000000000088615648565b63ffffffff16815260200161338d7f000000000000000000000000000000000000000000000000000000000000000087615648565b63ffffffff1681526020016133c27f000000000000000000000000000000000000000000000000000000000000000085615648565b63ffffffff1681526020016133f77f000000000000000000000000000000000000000000000000000000000000000086615648565b63ffffffff90811690915260ff8b16600081815260036020908152604091829020855181549287015184880151606089015160808a015160a08b015160c08c01518b16600160d81b0263ffffffff60d81b19918c16600160b81b0263ffffffff60b81b19938d16600160981b029390931667ffffffffffffffff60981b19948d16600160781b0263ffffffff60781b19968e16600160581b029690961667ffffffffffffffff60581b1997909d16600160381b026001600160581b0319909a1666ffffffffffffff909816979097179890981794909416999099179190911716919091179590951794909416179092559051919250907f3cb26612e7105331adad836a65ae9b7f1d30a9e469ec70510a7c7ea36b0185ed90613580908490600060e08201905066ffffffffffffff8351168252602083015163ffffffff80821660208501528060408601511660408501528060608601511660608501528060808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60405180910390a2505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060016135f36002600861567e565b6001901b61360191906157ec565b61367d6020600261010082816008600e60068461361f8160046155db565b61362991906155db565b61363391906155db565b61363d91906155db565b61364791906155db565b61365191906155db565b61365b91906155db565b61366591906155db565b61366f91906155db565b61367991906157ec565b3590565b16905090565b6000806000613690614822565b915091506136fd6136f66136a360043590565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b838361483f565b9250505090565b600061129060206014600880600280610100868185600e6006846137298160046155db565b61373391906155db565b61373d91906155db565b61374791906155db565b61361f91906155db565b600061129060206008600e6006836136478160046155db565b6000611290602060068161365b8160046155db565b613787614f45565b61378f614867565b815260043560208201526137a16138eb565b604082015260086137b4600e60066155db565b6137be91906155db565b6137c990600861567e565b7f0000000000000000000000000000000000000000000000000000000000000000901b6137f46138fc565b6137fe91906155db565b60608201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161382c614891565b60405161383a929190615ac8565b60405190819003902061384d9190615ad8565b608082015290565b3660006008600e6006602061386b8160046155db565b61387591906155db565b61387f91906155db565b61388991906155db565b612dcb91906155db565b61389b614f63565b8181526138a661395b565b60208201526138b36138eb565b6040820152919050565b36600060206101006008600e6006846138d78160046155db565b6138e191906155db565b61386b91906155db565b6000611290613679602060046155db565b60006001600861390e600e60066155db565b61391891906155db565b61392390600861567e565b6001901b61393191906157ec565b61367d60206008613944600e60066155db565b61394e91906155db565b602061365b8160046155db565b60006112906101006008600e600660206139768160046155db565b61398091906155db565b61398a91906155db565b61399491906155db565b61399e91906155db565b61367991906155db565b366000806139b4614921565b90506000816002806101006020816008600e6006846139d48160046155db565b6139de91906155db565b6139e891906155db565b6139f291906155db565b6139fc91906155db565b613a0691906155db565b613a1091906155db565b613a1a91906155db565b613a2491906155db565b613a2e91906155db565b613a3891906155db565b9050600082613a45614968565b613a4f91906157ec565b91959194509092505050565b60006001613a6a60088061567e565b6001901b613a7891906157ec565b61367d60206008600280610100848185600e60068461373d8160046155db565b60006112906020600e6006826136518160046155db565b6040516001600160a01b0380851660248301528316604482015260648101829052613b1a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526149a5565b50505050565b60006001613b2f60088061567e565b6001901b613b3d91906157ec565b61367d6020600880600280610100858185600e6006846137338160046155db565b600b546000906001600160a01b03168015613c3457613ba76001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168285613c3e565b604051630802e33b60e41b81526001600160a01b038581166004830152602482018590526000919083169063802e33b09060440160408051808303816000875af1158015613bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1d9190615aec565b9150613c2b905081856157ec565b92505050612dcb565b5060009392505050565b6040516001600160a01b038316602482015260448101829052613c6e90849063a9059cbb60e01b90606401613ae3565b505050565b6000806000613c80614a77565b919450925090506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e3ee160e87306103e8613ce57f00000000000000000000000000000000000000000000000000000000000000008a61567e565b613cef9190615648565b6000613cf9614aae565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201529490931660248501526044840191909152606483015267ffffffffffffffff16608482015260a4810188905260ff861660c482015260e48101859052610104810184905261012401600060405180830381600087803b158015613d7f57600080fd5b505af1158015613d93573d6000803e3d6000fd5b50505050505050505050565b8160ff1660ff1480613dcb575060ff821660009081526003602052604090205466ffffffffffffff1615155b613e2e5760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206e6f6e2d6578697374696e6720706f60448201526d37b6103634b6b4ba39903a34b2b960911b6064820152608401610552565b60005b8151811015613c6e576000828281518110613e4e57613e4e615ab2565b6020908102919091018101516001600160a01b038116600081815260058452604090819020805460ff60581b1916600160581b60ff8b16908102919091179091558151928352938201939093529092507f1283ebeb150dffd4da976f64c81e074fd4dc895cb64995dc46f13c9fd96a9551910160405180910390a150613ed381615b10565b9050613e31565b6001600160a01b038216158015613ef15750600081135b15613f3d5760028054829190600090613f149084906001600160481b0316615981565b92506101000a8154816001600160481b0302191690836001600160481b03160217905550505050565b6000613f4e610e1062015180615648565b613f5a610e1042615648565b613f649190615648565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b90049092166060830152929350916003908290613fda908890612cd0565b60ff16815260208082019290925260409081016000908120825160e081018452815466ffffffffffffff8116825263ffffffff600160381b8204811683880152600160581b808304821684880152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015285519182018652600184015461ffff811683526001600160481b036201000082048116988401989098520490951693850193909352935090919086131561458d578751869081908a906140ba908390615981565b6001600160481b031690525060808301516140fc907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff1661567e565b8111156141605760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a2073696e676c65206465706f7369742060448201526b18d85c08195e18d95959195960a21b6064820152608401610552565b8251614196907f00000000000000000000000000000000000000000000000000000000000000009066ffffffffffffff1661567e565b89516001600160481b031611156141f95760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a2074766c2063617020657863656564656044820152601960fa1b6064820152608401610552565b846000015161ffff168661ffff1611156143175760405180608001604052808761ffff168152602001826001600160481b03168152602001866040015160ff16815260200160006001600160481b0316815250600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160481b0302191690836001600160481b03160217905550604082015181600001600b6101000a81548160ff021916908360ff160217905550606082015181600001600c6101000a8154816001600160481b0302191690836001600160481b03160217905550905050614476565b80856020018181516143299190615981565b6001600160481b0316905250606083015161436b907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff1661567e565b85602001516001600160481b031611156143e05760405162461bcd60e51b815260206004820152603060248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526f1cda5d0818d85c08195e18d95959195960821b6064820152608401610552565b6001600160a01b03881660009081526005602090815260409182902087518154928901519389015160608a01516001600160481b03908116600160601b0268ffffffffffffffffff60601b1960ff909316600160581b029290921669ffffffffffffffffffff60581b199190961662010000026001600160581b031990951661ffff909316929092179390931716929092171790555b816000015161ffff168661ffff1611156144c35760405180606001604052808761ffff168152602001826001600160481b0316815260200160006001600160481b03168152509150614587565b80826020018181516144d59190615981565b6001600160481b03169052506020830151614517907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff1661567e565b82602001516001600160481b031611156145875760405162461bcd60e51b815260206004820152602b60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526a185c08195e18d95959195960aa1b6064820152608401610552565b5061475d565b6000614598876157d0565b90506145c87f000000000000000000000000000000000000000000000000000000000000000063ffffffff61567e565b81111561462c5760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a207769746864726177616c20616d6f7560448201526b6e7420746f6f206c6172676560a01b6064820152608401610552565b808960000181815161463e9190615b29565b6001600160481b0316905250815161ffff90811690871611156146945760405180606001604052808761ffff16815260200160006001600160481b03168152602001826001600160481b0316815250915061475b565b80826040018181516146a69190615981565b6001600160481b031690525060408301516146e8907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff1661567e565b82604001516001600160481b0316111561475b5760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526d1b0818d85c08195e18d95959195960921b6064820152608401610552565b505b9651600280546001600160481b0392831668ffffffffffffffffff199091161790558751600193909301805460208a01516040909a01518316600160581b0268ffffffffffffffffff60581b199a90931662010000026001600160581b031990911661ffff9095169490941793909317979097169690961790555050505050565b60006147e8614ad1565b8061129057507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035433905b6001600160a01b031614905090565b600080600061482f614ae5565b8035946020909101359350915050565b600080600061484f868686614b6e565b9150915061485c81614ba7565b5090505b9392505050565b60006008600061487561376a565b65ffffffffffff16815260200190815260200160002054905090565b366000806002806101006020816008600e6006846148b08160046155db565b6148ba91906155db565b6148c491906155db565b6148ce91906155db565b6148d891906155db565b6148e291906155db565b6148ec91906155db565b6148f691906155db565b61490091906155db565b61490a91906155db565b90506000614916614968565b919491935090915050565b60008061492c6135e3565b905080158061493b5750806001145b1561494857600891505090565b8060020361495857602491505090565b806003036101e457602491505090565b600060016149786002600861567e565b6001901b61498691906157ec565b61367d602060028061010083816008600e6006846137478160046155db565b60006149fa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cf19092919063ffffffff16565b805190915015613c6e5780806020019051810190614a1891906153ec565b613c6e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b6000806000806000614a87614822565b9092509050614a9b60ff82901c601b6155db565b959194506001600160ff1b031692509050565b60006112906020600880600280610100858185600e6006846137338160046155db565b6000805433906001600160a01b0316614813565b6000614aef614968565b6002806101006020816008600e600684614b0a8160046155db565b614b1491906155db565b614b1e91906155db565b614b2891906155db565b614b3291906155db565b614b3c91906155db565b614b4691906155db565b614b5091906155db565b614b5a91906155db565b614b6491906155db565b61129091906155db565b6000806001600160ff1b03831681614b8b60ff86901c601b6155db565b9050614b9987828885614d08565b935093505050935093915050565b6000816004811115614bbb57614bbb615b49565b03614bc35750565b6001816004811115614bd757614bd7615b49565b03614c245760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610552565b6002816004811115614c3857614c38615b49565b03614c855760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610552565b6003816004811115614c9957614c99615b49565b03610e5b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610552565b6060614d008484600085614dcc565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614d3f5750600090506003614dc3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614d93573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614dbc57600060019250925050614dc3565b9150600090505b94509492505050565b606082471015614e2d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b600080866001600160a01b03168587604051614e499190615b5f565b60006040518083038185875af1925050503d8060008114614e86576040519150601f19603f3d011682016040523d82523d6000602084013e614e8b565b606091505b5091509150614e9c87838387614ea7565b979650505050505050565b60608315614f16578251600003614f0f576001600160a01b0385163b614f0f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b5081614d00565b614d008383815115614f2b5781518083602001fd5b8060405162461bcd60e51b8152600401610552919061561f565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b0381168114610e5b57600080fd5b60008060408385031215614fa957600080fd5b8235614fb481614f81565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561500157615001614fc2565b604052919050565b600082601f83011261501a57600080fd5b60405161010080820182811067ffffffffffffffff8211171561503f5761503f614fc2565b6040528301818582111561505257600080fd5b845b8281101561506c578035825260209182019101615054565b509195945050505050565b600080600080600080610260878903121561509157600080fd5b86359550602087013567ffffffffffffffff808211156150b057600080fd5b818901915089601f8301126150c457600080fd5b8135818111156150d357600080fd5b8a60208260051b85010111156150e857600080fd5b602083019750809650505050604087013592506151088860608901615009565b9150615118886101608901615009565b90509295509295509295565b60006020828403121561513657600080fd5b813561486081614f81565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516151b58285018260ff169052565b50506101408381015190830152610160808401519083015261018092830151929091019190915290565b60ff81168114610e5b57600080fd5b60006020828403121561520057600080fd5b8135614860816151df565b600080600080600080600080610100898b03121561522857600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b60006020828403121561527257600080fd5b5035919050565b6000806040838503121561528c57600080fd5b823561529781614f81565b915060208301356152a781614f81565b809150509250929050565b600080604083850312156152c557600080fd5b82356152d0816151df565b915060208381013567ffffffffffffffff808211156152ee57600080fd5b818601915086601f83011261530257600080fd5b81358181111561531457615314614fc2565b8060051b9150615325848301614fd8565b818152918301840191848101908984111561533f57600080fd5b938501935b83851015615369578435925061535983614f81565b8282529385019390850190615344565b8096505050505050509250929050565b600080600080600080600080610100898b03121561539657600080fd5b88356153a1816151df565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b805180151581146153e757600080fd5b919050565b6000602082840312156153fe57600080fd5b614860826153d7565b6040808252810183905260006001600160fb1b0384111561542757600080fd5b8360051b8086606085013760009083016060019081526020909201929092529392505050565b60005b83811015615468578181015183820152602001615450565b83811115613b1a5750506000910152565b6000806000806080858703121561548f57600080fd5b845193506020850151925060408501519150606085015167ffffffffffffffff808211156154bc57600080fd5b818701915087601f8301126154d057600080fd5b8151818111156154e2576154e2614fc2565b6154f5601f8201601f1916602001614fd8565b915080825288602082850101111561550c57600080fd5b61551d81602084016020860161544d565b5094979396509194505050565b8060005b6008811015613b1a57815184526020938401939091019060010161552e565b6101208101818460005b6001811015615576578151835260209283019290910190600101615557565b505050614860602083018461552a565b8060005b6003811015613b1a57815184526020938401939091019060010161558a565b61016081016155b88285615586565b614860606083018461552a565b634e487b7160e01b600052601160045260246000fd5b600082198211156155ee576155ee6155c5565b500190565b6000815180845261560b81602086016020860161544d565b601f01601f19169290920160200192915050565b60208152600061486060208301846155f3565b634e487b7160e01b600052601260045260246000fd5b60008261565757615657615632565b500490565b600062ffffff8084168061567257615672615632565b92169190910492915050565b6000816000190483118215151615615698576156986155c5565b500290565b6101a08101818460005b60058110156156c65781518352602092830192909101906001016156a7565b5050506101008360a0840137600081529392505050565b61016081016156ec8285615586565b610100836060840137600081529392505050565b805160208201516001600160e01b0319808216929190600483101561572f5780818460040360031b1b83161693505b505050919050565b600080821280156001600160ff1b0384900385131615615759576157596155c5565b600160ff1b8390038412811615615772576157726155c5565b50500190565b60008261578757615787615632565b500790565b60208082526024908201527f5a6b426f62506f6f6c3a20696e636f7272656374206465706f73697420616d6f604082015263756e747360e01b606082015260800190565b6000600160ff1b82016157e5576157e56155c5565b5060000390565b6000828210156157fe576157fe6155c5565b500390565b60006020828403121561581557600080fd5b5051919050565b60006020828403121561582e57600080fd5b8151614860816151df565b602081526000825160a0602084015261585560c08401826155f3565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600181815b808511156158cc5781600019048211156158b2576158b26155c5565b808516156158bf57918102915b93841c9390800290615896565b509250929050565b6000826158e357506001612dcb565b816158f057506000612dcb565b816001811461590657600281146159105761592c565b6001915050612dcb565b60ff841115615921576159216155c5565b50506001821b612dcb565b5060208310610133831016604e8410600b841016171561594f575081810a612dcb565b6159598383615891565b806000190482111561596d5761596d6155c5565b029392505050565b600061486083836158d4565b60006001600160481b038083168185168083038211156159a3576159a36155c5565b01949350505050565b600062ffffff838116908316818110156159c8576159c86155c5565b039392505050565b600063ffffffff838116908316818110156159c8576159c86155c5565b60006001600160581b03838116908316818110156159c8576159c86155c5565b60006001600160581b038084168061567257615672615632565b60006001600160481b038084168061567257615672615632565b60006001600160581b038083168185168083038211156159a3576159a36155c5565b600063ffffffff808316818103615a7c57615a7c6155c5565b6001019392505050565b60008060408385031215615a9957600080fd5b615aa2836153d7565b915060208301516152a7816151df565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b600082615ae757615ae7615632565b500690565b60008060408385031215615aff57600080fd5b505080516020909101519092909150565b600060018201615b2257615b226155c5565b5060010190565b60006001600160481b03838116908316818110156159c8576159c86155c5565b634e487b7160e01b600052602160045260246000fd5b60008251615b7181846020870161544d565b919091019291505056fea264697066735822122035fcf90b984b22baf1a1ee4e2dd25d0aee8f70e3af4bb53078623e0838dc6c2264736f6c634300080f00335a6b426f62506f6f6c3a206e6f74206120636f6e74726163740000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff850000000000000000000000007ad8d97c60bfb59e501e3b6c1d8e564b0bb8195d0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d00000000000000000000000085afa00f38ad5f353c2b80985407b8e8a27ea38f00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c0014
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101e45760003560e01c80637a22393b1161010f578063c41100fa116100a2578063e0ec037411610071578063e0ec037414610482578063e8fd02e414610495578063f2fde38b146104a8578063fc0c546a146104bb57600080fd5b8063c41100fa14610434578063c4a688b814610447578063c879c6d81461044f578063d21e82ab1461046257600080fd5b806396ce0795116100de57806396ce0795146103d75780639d8ad6e4146103e5578063af9890831461040c578063c2b40ae41461041457600080fd5b80637a22393b1461038457806383f26e3b146103975780638da5cb5b146103be5780638fff4676146103cf57600080fd5b80632f84c96f11610187578063508400401161015657806350840040146103365780636d55160c14610356578063715018a614610369578063790c3a331461037157600080fd5b80632f84c96f146102c95780633701f979146102dc5780634279a99e1461030357806346adf6ce1461032357600080fd5b80631cbec711116101c35780631cbec711146102635780631dc4cb33146102785780631dd69d061461028b5780632747f41d146102a257600080fd5b80622befce146101e95780630c6248de14610229578063171ef3001461023c575b600080fd5b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f64545b6040516001600160a01b0390911681526020015b60405180910390f35b600b5461020c906001600160a01b031681565b61020c7f0000000000000000000000007ad8d97c60bfb59e501e3b6c1d8e564b0bb8195d81565b610276610271366004614f96565b6104e2565b005b610276610286366004615077565b610569565b61029460095481565b604051908152602001610220565b61020c7f00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c001481565b60065461020c906001600160a01b031681565b61020c7f0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d81565b610316610311366004615124565b6109c0565b6040516102209190615141565b6102766103313660046151ee565b610e2b565b610294610344366004615124565b600a6020526000908152604090205481565b61027661036436600461520b565b610e5e565b61027661112e565b61027661037f366004615124565b611142565b610276610392366004615124565b611218565b61020c7f00000000000000000000000085afa00f38ad5f353c2b80985407b8e8a27ea38f81565b6000546001600160a01b031661020c565b61029461126e565b6103e8600160ff1b01610294565b6102947f000000000000000000000000000000000000000000000000000000000000000181565b610276611295565b610294610422366004615260565b60086020526000908152604090205481565b610276610442366004615124565b611c39565b610276611cf0565b61027661045d366004615279565b612285565b610294610470366004615260565b60076020526000908152604090205481565b6102766104903660046152b2565b612485565b6102766104a3366004615379565b612497565b6102766104b6366004615124565b6124d0565b61020c7f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff8581565b336001600160a01b037f00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c0014161461055b5760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b60448201526064015b60405180910390fd5b6105658282612555565b5050565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156105bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e391906153ec565b61062f5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b6000806000807f00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c00146001600160a01b031663e24546f28a8a8a6040518463ffffffff1660e01b815260040161068593929190615407565b6000604051808303816000875af11580156106a4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106cc9190810190615479565b935093509350935060006106e16000866128d7565b604080516020810182528781529051633cac775b60e01b8152919450600785901b93506001600160a01b037f00000000000000000000000085afa00f38ad5f353c2b80985407b8e8a27ea38f169250633cac775b9161074591908c9060040161554d565b602060405180830381865afa158015610762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078691906153ec565b6107dd5760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a20626164206261746368206465706f7369742070726f60448201526137b360f11b6064820152608401610552565b604080516060810182526000838152600860209081529083902054825281018e90528082018b905290516345bb94c160e01b81526001600160a01b037f0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d16906345bb94c1906108529084908c906004016155a9565b602060405180830381865afa15801561086f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089391906153ec565b6108db5760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6108e66080836155db565b91508c600860008481526020019081526020016000208190555060008480519060200120905060006009548260405160200161092c929190918252602082015260400190565b60408051601f19818403018152919052805160209091012060098190559050871561097657336000908152600a6020526040812080548a92906109709084906155db565b90915550505b80847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c7373536886040516109a7919061561f565b60405180910390a3505050505050505050505050505050565b610a2e604051806101a00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff1681526020016000815260200160008152602001600081525090565b60408051602080820183526002546001600160481b0390811683526001600160a01b0386166000908152600583528481208551608081018752905461ffff8116825262010000810484169482019490945260ff600160581b850416958101869052600160601b90930490911660608301529192909190610aaf908690612cd0565b60ff81166000908152600360209081526040808320815160e081018352815466ffffffffffffff8116825263ffffffff600160381b8204811683870152600160581b808304821684870152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015284519182018552600184015461ffff811683526001600160481b03620100008204811697840197909752049094169284019290925293945091610b7d610e1042615648565b90506000610b90610e1062015180615648565b610b9a908361565c565b9050604051806101a001604052807f000000000000000000000000000000000000000000000000000000003b9aca00866000015166ffffffffffffff16610be1919061567e565b815260200189600001516001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866020015163ffffffff16610c2f919061567e565b81526020018262ffffff16856000015161ffff1614610c4f576000610c55565b84602001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866040015163ffffffff16610c99919061567e565b81526020018262ffffff16856000015161ffff1614610cb9576000610cbf565b84604001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866060015163ffffffff16610d03919061567e565b81526020018262ffffff16896000015161ffff1614610d23576000610d29565b88602001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca00866080015163ffffffff16610d6d919061567e565b81526020018760ff1681526020017f000000000000000000000000000000000000000000000000000000003b9aca008660c0015163ffffffff16610db1919061567e565b81526020018262ffffff16896000015161ffff1614610dd1576000610dd7565b88606001515b6001600160481b031681526020017f000000000000000000000000000000000000000000000000000000003b9aca008660a0015163ffffffff16610e1b919061567e565b90529a9950505050505050505050565b610e33612dd1565b610e5b8160ff16600090815260036020526040902060010180546001600160a01b0319169055565b50565b333014610ead5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420696e697469616c697a65720000000000006044820152606401610552565b6000805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c75415610f255760405162461bcd60e51b815260206004820152601e60248201527f5a6b426f62506f6f6c3a20616c726561647920696e697469616c697a656400006044820152606401610552565b87600003610f6c5760405162461bcd60e51b8152602060048201526014602482015273169ad09bd8941bdbdb0e881e995c9bc81c9bdbdd60621b6044820152606401610552565b600080805260086020527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c7899055611124906103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000018b615648565b610fd5919061567e565b6103e86110027f00000000000000000000000000000000000000000000000000000000000000018b615648565b61100c919061567e565b6103e86110397f00000000000000000000000000000000000000000000000000000000000000018b615648565b611043919061567e565b6103e86110707f00000000000000000000000000000000000000000000000000000000000000018b615648565b61107a919061567e565b6103e86110a77f00000000000000000000000000000000000000000000000000000000000000018b615648565b6110b1919061567e565b6103e86110de7f00000000000000000000000000000000000000000000000000000000000000018b615648565b6110e8919061567e565b6103e86111157f00000000000000000000000000000000000000000000000000000000000000018b615648565b61111f919061567e565b612e25565b5050505050505050565b611136612dd1565b6111406000613593565b565b61114a612dd1565b6001600160a01b0381163b6111b45760405162461bcd60e51b815260206004820152602a60248201527f4b796350726f7669646572734d616e6167657253746f726167653a206e6f7420604482015269184818dbdb9d1c9858dd60b21b6064820152608401610552565b7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f648190556040516001600160a01b03821681527fcfca215f2134266880a5d2c68d2f52493a9d57fe6dd1245086a201e78871348e906020015b60405180910390a150565b611220612dd1565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fdf71641930ea322cb32f687f4d292a0af694c81216254f204c930092593d82829060200161120d565b6000600761128960015463ffffffff600160e01b9091041690565b901b905090565b905090565b6006546001600160a01b0316636d70f7ae336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156112eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130f91906153ec565b61135b5760405162461bcd60e51b815260206004820152601a60248201527f5a6b426f62506f6f6c3a206e6f7420616e206f70657261746f720000000000006044820152606401610552565b3360006113666135e3565b90508060000361137f57611378613683565b91506113a2565b8060020361138f57611378613704565b806003036113a25761139f613704565b91505b60006113ac613751565b60070b905060006113bd84836128d7565b9250505060006113cc60043590565b60008181526007602081905260409091205491925083901b90156114325760405162461bcd60e51b815260206004820152601f60248201527f5a6b426f62506f6f6c3a20646f75626c657370656e64206465746563746564006044820152606401610552565b8061143b61376a565b65ffffffffffff1611156114a15760405162461bcd60e51b815260206004820152602760248201527f5a6b426f62506f6f6c3a207472616e7366657220696e646578206f7574206f6660448201526620626f756e647360c81b6064820152608401610552565b7f0000000000000000000000007ad8d97c60bfb59e501e3b6c1d8e564b0bb8195d6001600160a01b03166368444dc76114d861377f565b6114e0613855565b6040518363ffffffff1660e01b81526004016114fd92919061569d565b602060405180830381865afa15801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e91906153ec565b61158a5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164207472616e736665722070726f6f660000006044820152606401610552565b6000818152600860205260409020546001600160a01b037f0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d16906345bb94c1906115d390613893565b6115db6138bd565b6040518363ffffffff1660e01b81526004016115f89291906156dd565b602060405180830381865afa158015611615573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163991906153ec565b6116815760405162461bcd60e51b81526020600482015260196024820152782d35a137b12837b7b61d103130b2103a3932b290383937b7b360391b6044820152606401610552565b6116896138eb565b6116916138fc565b60408051602081019390935282015260600160408051601f198184030181529181528151602092830120600085815260079093529120556116d36080826155db565b90506116dd61395b565b6000828152600860205260408120919091556116f76139a8565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945061173992508491506157009050565b61ffff60e01b161461178d5760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a20626164206d657373616765207072656669780000006044820152606401610552565b6000818051906020012090506000600954826040516020016117b9929190918252602082015260400190565b6040516020818303038152906040528051906020012090508060098190555080847f7d39f8a6bc8929456fba511441be7361aa014ac6f8e21b99990ce9e1c737353685604051611809919061561f565b60405180910390a350505050600061181f613a5b565b9050600061182d8286615737565b90506000611839613a98565b600d0b905061184a6103e883615778565b156118a15760405162461bcd60e51b815260206004820152602160248201527f5a6b426f62506f6f6c3a20696e636f727265637420746f6b656e20616d6f756e6044820152601d60fa1b6064820152608401610552565b86600003611946576000861380156118b7575080155b6118d35760405162461bcd60e51b81526004016105529061578c565b61194188306103e86119057f00000000000000000000000000000000000000000000000000000000000000018761567e565b61190f9190615648565b6001600160a01b037f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff8516929190613aaf565b611c05565b866001036119b4578115801561195a575080155b6119415760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f7272656374207472616e7366657220616d6044820152646f756e747360d81b6064820152608401610552565b86600203611b7257600082131580156119ce575060008113155b611a285760405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20696e636f727265637420776974686472617720616d6044820152646f756e747360d81b6064820152608401610552565b60006103e87f0000000000000000000000000000000000000000000000000000000000000001611a56613b20565b611a60919061567e565b611a6a9190615648565b905060006103e87f0000000000000000000000000000000000000000000000000000000000000001611a9b866157d0565b611aa5919061567e565b611aaf9190615648565b90508115611ace57611ac18a83613b5e565b611acb90826157ec565b90505b8015611b0857611b086001600160a01b037f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85168b83613c3e565b6000831215611b6b5760405162461bcd60e51b815260206004820152602960248201527f5a6b426f62506f6f6c3a20585020636c61696d696e67206973206e6f742079656044820152681d08195b98589b195960ba1b6064820152608401610552565b5050611c05565b86600303611baf57600086138015611b88575080155b611ba45760405162461bcd60e51b81526004016105529061578c565b611941888584613c73565b60405162461bcd60e51b815260206004820152602560248201527f5a6b426f62506f6f6c3a20496e636f7272656374207472616e73616374696f6e604482015264207479706560d81b6064820152608401610552565b821561112457336000908152600a602052604081208054859290611c2a9084906155db565b90915550505050505050505050565b611c41612dd1565b6001600160a01b038116611ca25760405162461bcd60e51b815260206004820152602260248201527f5a6b426f62506f6f6c3a206d616e61676572206973207a65726f206164647265604482015261737360f01b6064820152608401610552565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f267052ecaebdd552dc1b20904f59d83d51ae7add7514165322a7da9ef6cf543b9060200161120d565b333014611d335760405162461bcd60e51b815260206004820152601160248201527024b731b7b93932b1ba1034b73b37b5b2b960791b6044820152606401610552565b7f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff856001600160a01b0316730b2c639c533813f4aa9d7837caf62653d097ff8514611db15760405162461bcd60e51b815260206004820152600f60248201526e24b731b7b93932b1ba103a37b5b2b760891b6044820152606401610552565b6040516370a0823160e01b815230600482015273b0b195aefa3650a6908f15cdac7d92f8a5791b0b9060009082906370a0823190602401602060405180830381865afa158015611e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e299190615803565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e8f919061581c565b60ff16905060007f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ef4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f18919061581c565b60405163095ea7b360e01b815273e592427a0aece92de3edee1f18e0157c05861564600482018190526024820186905260ff9290921692506000906001600160a01b0387169063095ea7b3906044016020604051808303816000875af1158015611f86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611faa91906153ec565b6040805160a081019091526bffffffffffffffffffffffff19606089811b821660c0840152601960ea1b60d48401819052737f5c764cbc14f9669b88837ca1490cca17c3160760601b60d785015260eb8401527f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85901b1660ee8201529091506000906001600160a01b0384169063c04b8d599080610102810160408051601f198184030181529181529082523060208301524290820152606081018a905260800166038d7ea4c6800061207f8b6103e361567e565b6120899190615648565b8152506040518263ffffffff1660e01b81526004016120a89190615839565b6020604051808303816000875af11580156120c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120eb9190615803565b6040516370a0823160e01b81523060048201529091506001600160a01b038816906370a0823190602401602060405180830381865afa158015612132573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121569190615803565b156121945760405162461bcd60e51b815260206004820152600e60248201526d0496e636f727265637420737761760941b6044820152606401610552565b6000816121a186886157ec565b6121ac90600a615975565b6121b69089615648565b6121c091906157ec565b90507f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff856001600160a01b03166323b872dd6122036000546001600160a01b031690565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018490526064016020604051808303816000875af1158015612256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061227a91906153ec565b505050505050505050565b6001600160a01b03821633148061230b5750600654604051632bb6fe4d60e21b81526001600160a01b0384811660048301523360248301529091169063aedbf93490604401602060405180830381865afa1580156122e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061230b91906153ec565b6123535760405162461bcd60e51b8152602060048201526019602482015278169ad09bd8941bdbdb0e881b9bdd08185d5d1a1bdc9a5e9959603a1b6044820152606401610552565b6001600160a01b0382166000908152600a60205260408120546103e89061239b907f00000000000000000000000000000000000000000000000000000000000000019061567e565b6123a59190615648565b9050600081116123f75760405162461bcd60e51b815260206004820152601d60248201527f5a6b426f62506f6f6c3a206e6f2066656520746f2077697468647261770000006044820152606401610552565b61242b6001600160a01b037f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85168383613c3e565b6001600160a01b0383166000818152600a602052604080822091909155517f66bf9186b00db666fc37aaffbb95a050c66e599e000c785c1dff0467d868f1b1906124789084815260200190565b60405180910390a2505050565b61248d612dd1565b6105658282613d9f565b61249f612dd1565b611124886103e8610fcb7f00000000000000000000000000000000000000000000000000000000000000018b615648565b6124d8612dd1565b6001600160a01b03811661253d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610552565b610e5b81613593565b6001600160a01b03163b151590565b6000612566610e1062015180615648565b612572610e1042615648565b61257c9190615648565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b900490921660608301529293509160039082906125f2908890612cd0565b60ff1681526020808201929092526040908101600020815160e081018352905466ffffffffffffff8116825263ffffffff600160381b8204811694830194909452600160581b8104841692820192909252600160781b820483166060820152600160981b820483166080820152600160b81b8204831660a08201819052600160d81b90920490921660c08301529091506126ad907f000000000000000000000000000000000000000000000000000000003b9aca009061567e565b8411156127185760405162461bcd60e51b815260206004820152603360248201527f5a6b426f624163636f756e74696e673a2073696e676c65206469726563742064604482015272195c1bdcda5d0818d85c08195e18d959591959606a1b6064820152608401610552565b816000015161ffff168361ffff161115612763576040805160808101825261ffff85168152600060208201529281015160ff16908301526001600160481b0384166060830152612839565b83826060018181516127759190615981565b6001600160481b031690525060c08101516127b7907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff1661567e565b82606001516001600160481b031611156128395760405162461bcd60e51b815260206004820152603760248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206469726560448201527f6374206465706f736974206361702065786365656465640000000000000000006064820152608401610552565b506001600160a01b039390931660009081526005602090815260409182902085518154928701519387015160609097015161ffff9091166001600160581b031990931692909217620100006001600160481b03948516021769ffffffffffffffffffff60581b1916600160581b60ff9097169690960268ffffffffffffffffff60601b191695909517600160601b9290911691909102179092555050565b6040805160c08101825260015466ffffffffffffff8116825263ffffffff600160381b8204811660208085019190915262ffffff600160581b8404811685870152600160701b84041660608501526001600160581b03600160881b8404166080850152600160e01b9092041660a083015282519081019092526002546001600160481b031682526000918291829182612972610e1042615648565b60a084015163ffffffff169450905083158015906129b0575061299a610e1062093a80615648565b60408401516129a990836159ac565b62ffffff16115b15612ac6576040838101805162ffffff9081166000908152600460208181528583208651606081018852905480861682526301000000810463ffffffff16828401908152600160381b9091046001600160581b03168289015286518616855292909152948220805471ffffffffffffffffffffffffffffffffffff1916905584519092169092525160a0860151612a4791906159d0565b9050846020015163ffffffff168163ffffffff161115612a6e5763ffffffff811660208601525b60008163ffffffff1683604001518760800151612a8b91906159ed565b612a959190615a0d565b9050856000015166ffffffffffffff168166ffffffffffffff161115612ac25766ffffffffffffff811686525b5050505b8062ffffff16836060015162ffffff161015612b8157604080516060808201835262ffffff80851680845260a088015163ffffffff908116602080870191825260808b01516001600160581b03908116888a01908152968c018051871660009081526004909352989091209651875492519651909116600160381b0271ffffffffffffffffffffff00000000000000199690931663010000000266ffffffffffffff1990921694169390931792909217929092161790915590525b8151612bae907f000000000000000000000000000000000000000000000000000000003b9aca0090615a27565b6001600160481b031683608001818151612bc89190615a41565b6001600160581b031690525060a08301805190612be482615a63565b63ffffffff169052508615612bfe57612bfe828989613eda565b5050805160018054602084015160408501516060860151608087015160a09097015166ffffffffffffff87166001600160581b031990951694909417600160381b63ffffffff808616919091029190911765ffffffffffff60581b1916600160581b62ffffff9485160262ffffff60701b191617600160701b93909216929092021770ffffffffffffffffffffffffffffffffff16600160881b6001600160581b03909716969096026001600160e01b031695909517600160e01b959092169490940217905596909550909350915050565b600080612cfb7f06c991646992b7f0f3fd0c832eac3f519e26682bcb82fbbcfd1ff8013d876f645490565b905060ff8316158015612d1657506001600160a01b03811615155b15612dc657604051630a364e7560e41b81526001600160a01b038581166004830152600091829184169063a364e750906024016040805180830381865afa158015612d65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d899190615a86565b91509150818015612db4575060ff811660009081526003602052604090205466ffffffffffffff1615155b15612dc3579250612dcb915050565b50505b829150505b92915050565b612dd96147de565b6111405760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610552565b60ff8860ff1610612e845760405162461bcd60e51b815260206004820152602360248201527f5a6b426f624163636f756e74696e673a20696e76616c6964206c696d6974207460448201526234b2b960e91b6064820152608401610552565b60008311612ede5760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a207a65726f206465706f7369742063616044820152600760fc1b6064820152608401610552565b612f0f7f000000000000000000000000000000000000000000000000000000003b9aca0066ffffffffffffff61567e565b871115612f695760405162461bcd60e51b815260206004820152602260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6172604482015261676560f01b6064820152608401610552565b612f977f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff61567e565b861115612ffb5760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526b617020746f6f206c6172676560a01b6064820152608401610552565b6130297f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff61567e565b8511156130905760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526e6c2063617020746f6f206c6172676560881b6064820152608401610552565b828410156130f85760405162461bcd60e51b815260206004820152602f60248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526e7369742063617020746f6f206c6f7760881b6064820152608401610552565b8386101561315b5760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f7369742063604482015269617020746f6f206c6f7760b01b6064820152608401610552565b858710156131ab5760405162461bcd60e51b815260206004820181905260248201527f5a6b426f624163636f756e74696e673a2074766c2063617020746f6f206c6f776044820152606401610552565b6000851161320e5760405162461bcd60e51b815260206004820152602a60248201527f5a6b426f624163636f756e74696e673a207a65726f206461696c792077697468604482015269064726177616c206361760b41b6064820152608401610552565b8082101561327d5760405162461bcd60e51b815260206004820152603660248201527f5a6b426f624163636f756e74696e673a206461696c79207573657220646972656044820152756374206465706f7369742063617020746f6f206c6f7760501b6064820152608401610552565b60006040518060e001604052807f000000000000000000000000000000000000000000000000000000003b9aca008a6132b69190615648565b66ffffffffffffff1681526020016132ee7f000000000000000000000000000000000000000000000000000000003b9aca008a615648565b63ffffffff1681526020016133237f000000000000000000000000000000000000000000000000000000003b9aca0089615648565b63ffffffff1681526020016133587f000000000000000000000000000000000000000000000000000000003b9aca0088615648565b63ffffffff16815260200161338d7f000000000000000000000000000000000000000000000000000000003b9aca0087615648565b63ffffffff1681526020016133c27f000000000000000000000000000000000000000000000000000000003b9aca0085615648565b63ffffffff1681526020016133f77f000000000000000000000000000000000000000000000000000000003b9aca0086615648565b63ffffffff90811690915260ff8b16600081815260036020908152604091829020855181549287015184880151606089015160808a015160a08b015160c08c01518b16600160d81b0263ffffffff60d81b19918c16600160b81b0263ffffffff60b81b19938d16600160981b029390931667ffffffffffffffff60981b19948d16600160781b0263ffffffff60781b19968e16600160581b029690961667ffffffffffffffff60581b1997909d16600160381b026001600160581b0319909a1666ffffffffffffff909816979097179890981794909416999099179190911716919091179590951794909416179092559051919250907f3cb26612e7105331adad836a65ae9b7f1d30a9e469ec70510a7c7ea36b0185ed90613580908490600060e08201905066ffffffffffffff8351168252602083015163ffffffff80821660208501528060408601511660408501528060608601511660608501528060808601511660808501528060a08601511660a08501528060c08601511660c0850152505092915050565b60405180910390a2505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060016135f36002600861567e565b6001901b61360191906157ec565b61367d6020600261010082816008600e60068461361f8160046155db565b61362991906155db565b61363391906155db565b61363d91906155db565b61364791906155db565b61365191906155db565b61365b91906155db565b61366591906155db565b61366f91906155db565b61367991906157ec565b3590565b16905090565b6000806000613690614822565b915091506136fd6136f66136a360043590565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b838361483f565b9250505090565b600061129060206014600880600280610100868185600e6006846137298160046155db565b61373391906155db565b61373d91906155db565b61374791906155db565b61361f91906155db565b600061129060206008600e6006836136478160046155db565b6000611290602060068161365b8160046155db565b613787614f45565b61378f614867565b815260043560208201526137a16138eb565b604082015260086137b4600e60066155db565b6137be91906155db565b6137c990600861567e565b7f0000000000000000000000000000000000000000000000000000000000000001901b6137f46138fc565b6137fe91906155db565b60608201527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161382c614891565b60405161383a929190615ac8565b60405190819003902061384d9190615ad8565b608082015290565b3660006008600e6006602061386b8160046155db565b61387591906155db565b61387f91906155db565b61388991906155db565b612dcb91906155db565b61389b614f63565b8181526138a661395b565b60208201526138b36138eb565b6040820152919050565b36600060206101006008600e6006846138d78160046155db565b6138e191906155db565b61386b91906155db565b6000611290613679602060046155db565b60006001600861390e600e60066155db565b61391891906155db565b61392390600861567e565b6001901b61393191906157ec565b61367d60206008613944600e60066155db565b61394e91906155db565b602061365b8160046155db565b60006112906101006008600e600660206139768160046155db565b61398091906155db565b61398a91906155db565b61399491906155db565b61399e91906155db565b61367991906155db565b366000806139b4614921565b90506000816002806101006020816008600e6006846139d48160046155db565b6139de91906155db565b6139e891906155db565b6139f291906155db565b6139fc91906155db565b613a0691906155db565b613a1091906155db565b613a1a91906155db565b613a2491906155db565b613a2e91906155db565b613a3891906155db565b9050600082613a45614968565b613a4f91906157ec565b91959194509092505050565b60006001613a6a60088061567e565b6001901b613a7891906157ec565b61367d60206008600280610100848185600e60068461373d8160046155db565b60006112906020600e6006826136518160046155db565b6040516001600160a01b0380851660248301528316604482015260648101829052613b1a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526149a5565b50505050565b60006001613b2f60088061567e565b6001901b613b3d91906157ec565b61367d6020600880600280610100858185600e6006846137338160046155db565b600b546000906001600160a01b03168015613c3457613ba76001600160a01b037f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85168285613c3e565b604051630802e33b60e41b81526001600160a01b038581166004830152602482018590526000919083169063802e33b09060440160408051808303816000875af1158015613bf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1d9190615aec565b9150613c2b905081856157ec565b92505050612dcb565b5060009392505050565b6040516001600160a01b038316602482015260448101829052613c6e90849063a9059cbb60e01b90606401613ae3565b505050565b6000806000613c80614a77565b919450925090506001600160a01b037f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff851663e3ee160e87306103e8613ce57f00000000000000000000000000000000000000000000000000000000000000018a61567e565b613cef9190615648565b6000613cf9614aae565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201529490931660248501526044840191909152606483015267ffffffffffffffff16608482015260a4810188905260ff861660c482015260e48101859052610104810184905261012401600060405180830381600087803b158015613d7f57600080fd5b505af1158015613d93573d6000803e3d6000fd5b50505050505050505050565b8160ff1660ff1480613dcb575060ff821660009081526003602052604090205466ffffffffffffff1615155b613e2e5760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206e6f6e2d6578697374696e6720706f60448201526d37b6103634b6b4ba39903a34b2b960911b6064820152608401610552565b60005b8151811015613c6e576000828281518110613e4e57613e4e615ab2565b6020908102919091018101516001600160a01b038116600081815260058452604090819020805460ff60581b1916600160581b60ff8b16908102919091179091558151928352938201939093529092507f1283ebeb150dffd4da976f64c81e074fd4dc895cb64995dc46f13c9fd96a9551910160405180910390a150613ed381615b10565b9050613e31565b6001600160a01b038216158015613ef15750600081135b15613f3d5760028054829190600090613f149084906001600160481b0316615981565b92506101000a8154816001600160481b0302191690836001600160481b03160217905550505050565b6000613f4e610e1062015180615648565b613f5a610e1042615648565b613f649190615648565b6001600160a01b03841660009081526005602090815260408083208151608081018352905461ffff811682526001600160481b0362010000820481169483019490945260ff600160581b820416928201839052600160601b90049092166060830152929350916003908290613fda908890612cd0565b60ff16815260208082019290925260409081016000908120825160e081018452815466ffffffffffffff8116825263ffffffff600160381b8204811683880152600160581b808304821684880152600160781b83048216606080860191909152600160981b840483166080860152600160b81b8404831660a0860152600160d81b90930490911660c084015285519182018652600184015461ffff811683526001600160481b036201000082048116988401989098520490951693850193909352935090919086131561458d578751869081908a906140ba908390615981565b6001600160481b031690525060808301516140fc907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff1661567e565b8111156141605760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a2073696e676c65206465706f7369742060448201526b18d85c08195e18d95959195960a21b6064820152608401610552565b8251614196907f000000000000000000000000000000000000000000000000000000003b9aca009066ffffffffffffff1661567e565b89516001600160481b031611156141f95760405162461bcd60e51b815260206004820152602160248201527f5a6b426f624163636f756e74696e673a2074766c2063617020657863656564656044820152601960fa1b6064820152608401610552565b846000015161ffff168661ffff1611156143175760405180608001604052808761ffff168152602001826001600160481b03168152602001866040015160ff16815260200160006001600160481b0316815250600560008a6001600160a01b03166001600160a01b0316815260200190815260200160002060008201518160000160006101000a81548161ffff021916908361ffff16021790555060208201518160000160026101000a8154816001600160481b0302191690836001600160481b03160217905550604082015181600001600b6101000a81548160ff021916908360ff160217905550606082015181600001600c6101000a8154816001600160481b0302191690836001600160481b03160217905550905050614476565b80856020018181516143299190615981565b6001600160481b0316905250606083015161436b907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff1661567e565b85602001516001600160481b031611156143e05760405162461bcd60e51b815260206004820152603060248201527f5a6b426f624163636f756e74696e673a206461696c792075736572206465706f60448201526f1cda5d0818d85c08195e18d95959195960821b6064820152608401610552565b6001600160a01b03881660009081526005602090815260409182902087518154928901519389015160608a01516001600160481b03908116600160601b0268ffffffffffffffffff60601b1960ff909316600160581b029290921669ffffffffffffffffffff60581b199190961662010000026001600160581b031990951661ffff909316929092179390931716929092171790555b816000015161ffff168661ffff1611156144c35760405180606001604052808761ffff168152602001826001600160481b0316815260200160006001600160481b03168152509150614587565b80826020018181516144d59190615981565b6001600160481b03169052506020830151614517907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff1661567e565b82602001516001600160481b031611156145875760405162461bcd60e51b815260206004820152602b60248201527f5a6b426f624163636f756e74696e673a206461696c79206465706f736974206360448201526a185c08195e18d95959195960aa1b6064820152608401610552565b5061475d565b6000614598876157d0565b90506145c87f000000000000000000000000000000000000000000000000000000003b9aca0063ffffffff61567e565b81111561462c5760405162461bcd60e51b815260206004820152602c60248201527f5a6b426f624163636f756e74696e673a207769746864726177616c20616d6f7560448201526b6e7420746f6f206c6172676560a01b6064820152608401610552565b808960000181815161463e9190615b29565b6001600160481b0316905250815161ffff90811690871611156146945760405180606001604052808761ffff16815260200160006001600160481b03168152602001826001600160481b0316815250915061475b565b80826040018181516146a69190615981565b6001600160481b031690525060408301516146e8907f000000000000000000000000000000000000000000000000000000003b9aca009063ffffffff1661567e565b82604001516001600160481b0316111561475b5760405162461bcd60e51b815260206004820152602e60248201527f5a6b426f624163636f756e74696e673a206461696c792077697468647261776160448201526d1b0818d85c08195e18d95959195960921b6064820152608401610552565b505b9651600280546001600160481b0392831668ffffffffffffffffff199091161790558751600193909301805460208a01516040909a01518316600160581b0268ffffffffffffffffff60581b199a90931662010000026001600160581b031990911661ffff9095169490941793909317979097169690961790555050505050565b60006147e8614ad1565b8061129057507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035433905b6001600160a01b031614905090565b600080600061482f614ae5565b8035946020909101359350915050565b600080600061484f868686614b6e565b9150915061485c81614ba7565b5090505b9392505050565b60006008600061487561376a565b65ffffffffffff16815260200190815260200160002054905090565b366000806002806101006020816008600e6006846148b08160046155db565b6148ba91906155db565b6148c491906155db565b6148ce91906155db565b6148d891906155db565b6148e291906155db565b6148ec91906155db565b6148f691906155db565b61490091906155db565b61490a91906155db565b90506000614916614968565b919491935090915050565b60008061492c6135e3565b905080158061493b5750806001145b1561494857600891505090565b8060020361495857602491505090565b806003036101e457602491505090565b600060016149786002600861567e565b6001901b61498691906157ec565b61367d602060028061010083816008600e6006846137478160046155db565b60006149fa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614cf19092919063ffffffff16565b805190915015613c6e5780806020019051810190614a1891906153ec565b613c6e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610552565b6000806000806000614a87614822565b9092509050614a9b60ff82901c601b6155db565b959194506001600160ff1b031692509050565b60006112906020600880600280610100858185600e6006846137338160046155db565b6000805433906001600160a01b0316614813565b6000614aef614968565b6002806101006020816008600e600684614b0a8160046155db565b614b1491906155db565b614b1e91906155db565b614b2891906155db565b614b3291906155db565b614b3c91906155db565b614b4691906155db565b614b5091906155db565b614b5a91906155db565b614b6491906155db565b61129091906155db565b6000806001600160ff1b03831681614b8b60ff86901c601b6155db565b9050614b9987828885614d08565b935093505050935093915050565b6000816004811115614bbb57614bbb615b49565b03614bc35750565b6001816004811115614bd757614bd7615b49565b03614c245760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610552565b6002816004811115614c3857614c38615b49565b03614c855760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610552565b6003816004811115614c9957614c99615b49565b03610e5b5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610552565b6060614d008484600085614dcc565b949350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614d3f5750600090506003614dc3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614d93573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614dbc57600060019250925050614dc3565b9150600090505b94509492505050565b606082471015614e2d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610552565b600080866001600160a01b03168587604051614e499190615b5f565b60006040518083038185875af1925050503d8060008114614e86576040519150601f19603f3d011682016040523d82523d6000602084013e614e8b565b606091505b5091509150614e9c87838387614ea7565b979650505050505050565b60608315614f16578251600003614f0f576001600160a01b0385163b614f0f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610552565b5081614d00565b614d008383815115614f2b5781518083602001fd5b8060405162461bcd60e51b8152600401610552919061561f565b6040518060a001604052806005906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b0381168114610e5b57600080fd5b60008060408385031215614fa957600080fd5b8235614fb481614f81565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561500157615001614fc2565b604052919050565b600082601f83011261501a57600080fd5b60405161010080820182811067ffffffffffffffff8211171561503f5761503f614fc2565b6040528301818582111561505257600080fd5b845b8281101561506c578035825260209182019101615054565b509195945050505050565b600080600080600080610260878903121561509157600080fd5b86359550602087013567ffffffffffffffff808211156150b057600080fd5b818901915089601f8301126150c457600080fd5b8135818111156150d357600080fd5b8a60208260051b85010111156150e857600080fd5b602083019750809650505050604087013592506151088860608901615009565b9150615118886101608901615009565b90509295509295509295565b60006020828403121561513657600080fd5b813561486081614f81565b60006101a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e0830152610100808401518184015250610120808401516151b58285018260ff169052565b50506101408381015190830152610160808401519083015261018092830151929091019190915290565b60ff81168114610e5b57600080fd5b60006020828403121561520057600080fd5b8135614860816151df565b600080600080600080600080610100898b03121561522857600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b60006020828403121561527257600080fd5b5035919050565b6000806040838503121561528c57600080fd5b823561529781614f81565b915060208301356152a781614f81565b809150509250929050565b600080604083850312156152c557600080fd5b82356152d0816151df565b915060208381013567ffffffffffffffff808211156152ee57600080fd5b818601915086601f83011261530257600080fd5b81358181111561531457615314614fc2565b8060051b9150615325848301614fd8565b818152918301840191848101908984111561533f57600080fd5b938501935b83851015615369578435925061535983614f81565b8282529385019390850190615344565b8096505050505050509250929050565b600080600080600080600080610100898b03121561539657600080fd5b88356153a1816151df565b9a60208a01359a5060408a013599606081013599506080810135985060a0810135975060c0810135965060e00135945092505050565b805180151581146153e757600080fd5b919050565b6000602082840312156153fe57600080fd5b614860826153d7565b6040808252810183905260006001600160fb1b0384111561542757600080fd5b8360051b8086606085013760009083016060019081526020909201929092529392505050565b60005b83811015615468578181015183820152602001615450565b83811115613b1a5750506000910152565b6000806000806080858703121561548f57600080fd5b845193506020850151925060408501519150606085015167ffffffffffffffff808211156154bc57600080fd5b818701915087601f8301126154d057600080fd5b8151818111156154e2576154e2614fc2565b6154f5601f8201601f1916602001614fd8565b915080825288602082850101111561550c57600080fd5b61551d81602084016020860161544d565b5094979396509194505050565b8060005b6008811015613b1a57815184526020938401939091019060010161552e565b6101208101818460005b6001811015615576578151835260209283019290910190600101615557565b505050614860602083018461552a565b8060005b6003811015613b1a57815184526020938401939091019060010161558a565b61016081016155b88285615586565b614860606083018461552a565b634e487b7160e01b600052601160045260246000fd5b600082198211156155ee576155ee6155c5565b500190565b6000815180845261560b81602086016020860161544d565b601f01601f19169290920160200192915050565b60208152600061486060208301846155f3565b634e487b7160e01b600052601260045260246000fd5b60008261565757615657615632565b500490565b600062ffffff8084168061567257615672615632565b92169190910492915050565b6000816000190483118215151615615698576156986155c5565b500290565b6101a08101818460005b60058110156156c65781518352602092830192909101906001016156a7565b5050506101008360a0840137600081529392505050565b61016081016156ec8285615586565b610100836060840137600081529392505050565b805160208201516001600160e01b0319808216929190600483101561572f5780818460040360031b1b83161693505b505050919050565b600080821280156001600160ff1b0384900385131615615759576157596155c5565b600160ff1b8390038412811615615772576157726155c5565b50500190565b60008261578757615787615632565b500790565b60208082526024908201527f5a6b426f62506f6f6c3a20696e636f7272656374206465706f73697420616d6f604082015263756e747360e01b606082015260800190565b6000600160ff1b82016157e5576157e56155c5565b5060000390565b6000828210156157fe576157fe6155c5565b500390565b60006020828403121561581557600080fd5b5051919050565b60006020828403121561582e57600080fd5b8151614860816151df565b602081526000825160a0602084015261585560c08401826155f3565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b600181815b808511156158cc5781600019048211156158b2576158b26155c5565b808516156158bf57918102915b93841c9390800290615896565b509250929050565b6000826158e357506001612dcb565b816158f057506000612dcb565b816001811461590657600281146159105761592c565b6001915050612dcb565b60ff841115615921576159216155c5565b50506001821b612dcb565b5060208310610133831016604e8410600b841016171561594f575081810a612dcb565b6159598383615891565b806000190482111561596d5761596d6155c5565b029392505050565b600061486083836158d4565b60006001600160481b038083168185168083038211156159a3576159a36155c5565b01949350505050565b600062ffffff838116908316818110156159c8576159c86155c5565b039392505050565b600063ffffffff838116908316818110156159c8576159c86155c5565b60006001600160581b03838116908316818110156159c8576159c86155c5565b60006001600160581b038084168061567257615672615632565b60006001600160481b038084168061567257615672615632565b60006001600160581b038083168185168083038211156159a3576159a36155c5565b600063ffffffff808316818103615a7c57615a7c6155c5565b6001019392505050565b60008060408385031215615a9957600080fd5b615aa2836153d7565b915060208301516152a7816151df565b634e487b7160e01b600052603260045260246000fd5b8183823760009101908152919050565b600082615ae757615ae7615632565b500690565b60008060408385031215615aff57600080fd5b505080516020909101519092909150565b600060018201615b2257615b226155c5565b5060010190565b60006001600160481b03838116908316818110156159c8576159c86155c5565b634e487b7160e01b600052602160045260246000fd5b60008251615b7181846020870161544d565b919091019291505056fea264697066735822122035fcf90b984b22baf1a1ee4e2dd25d0aee8f70e3af4bb53078623e0838dc6c2264736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff850000000000000000000000007ad8d97c60bfb59e501e3b6c1d8e564b0bb8195d0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d00000000000000000000000085afa00f38ad5f353c2b80985407b8e8a27ea38f00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c0014
-----Decoded View---------------
Arg [0] : __pool_id (uint256): 1
Arg [1] : _token (address): 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85
Arg [2] : _transfer_verifier (address): 0x7aD8d97c60BFb59e501e3b6C1d8E564b0bB8195d
Arg [3] : _tree_verifier (address): 0x2C34aFcB1c51796c3c0C7710c72a56Eb72E1E81D
Arg [4] : _batch_deposit_verifier (address): 0x85afa00f38aD5F353C2B80985407b8E8A27eA38f
Arg [5] : _direct_deposit_queue (address): 0x15B8C75c024acba8c114C21F42eb515A762c0014
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [1] : 0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85
Arg [2] : 0000000000000000000000007ad8d97c60bfb59e501e3b6c1d8e564b0bb8195d
Arg [3] : 0000000000000000000000002c34afcb1c51796c3c0c7710c72a56eb72e1e81d
Arg [4] : 00000000000000000000000085afa00f38ad5f353c2b80985407b8e8a27ea38f
Arg [5] : 00000000000000000000000015b8c75c024acba8c114c21f42eb515a762c0014
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.