Source Code
Latest 25 from a total of 1,471 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Redeem By Pairs ... | 25656856 | 109 days ago | IN | 0 ETH | 0.00000007 | ||||
| Redeem By Pairs ... | 19341621 | 255 days ago | IN | 0 ETH | 0.00000008 | ||||
| Redeem By Pairs ... | 15752786 | 338 days ago | IN | 0 ETH | 0.00000027 | ||||
| Redeem By Pairs ... | 14943543 | 357 days ago | IN | 0 ETH | 0.00000347 | ||||
| Redeem By Pairs ... | 12994394 | 402 days ago | IN | 0 ETH | 0.00000102 | ||||
| Redeem By Pairs ... | 12433282 | 415 days ago | IN | 0 ETH | 0.00000323 | ||||
| Redeem By Pairs ... | 11940167 | 426 days ago | IN | 0 ETH | 0.00000384 | ||||
| Redeem By Pairs ... | 11290207 | 441 days ago | IN | 0 ETH | 0.00000587 | ||||
| Redeem By Pairs ... | 11220357 | 443 days ago | IN | 0 ETH | 0.00000296 | ||||
| Usb To Margin To... | 11220154 | 443 days ago | IN | 0 ETH | 0.00000189 | ||||
| Redeem By Pairs ... | 9101767 | 492 days ago | IN | 0 ETH | 0.00000303 | ||||
| Redeem By Pairs ... | 9087453 | 492 days ago | IN | 0 ETH | 0.00000493 | ||||
| Redeem By Pairs ... | 8462441 | 507 days ago | IN | 0 ETH | 0.00000723 | ||||
| Redeem By Pairs ... | 7290801 | 534 days ago | IN | 0 ETH | 0.00000261 | ||||
| Redeem By Pairs ... | 6849607 | 544 days ago | IN | 0 ETH | 0.00000095 | ||||
| Redeem By Pairs ... | 6842579 | 544 days ago | IN | 0 ETH | 0.00000194 | ||||
| Redeem By Pairs ... | 6795838 | 545 days ago | IN | 0 ETH | 0.00000581 | ||||
| Redeem By Pairs ... | 6717505 | 547 days ago | IN | 0 ETH | 0.00000703 | ||||
| Redeem By Pairs ... | 6534567 | 552 days ago | IN | 0 ETH | 0.00000133 | ||||
| Redeem By Pairs ... | 6534541 | 552 days ago | IN | 0 ETH | 0.00000134 | ||||
| Redeem By Pairs ... | 6533962 | 552 days ago | IN | 0 ETH | 0.00000166 | ||||
| Redeem By Pairs ... | 6481386 | 553 days ago | IN | 0 ETH | 0.00000102 | ||||
| Redeem By Pairs ... | 6161837 | 560 days ago | IN | 0 ETH | 0.00000229 | ||||
| Redeem By Pairs ... | 5853790 | 567 days ago | IN | 0 ETH | 0.00000124 | ||||
| Redeem By Pairs ... | 5853587 | 567 days ago | IN | 0 ETH | 0.00000129 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 21692855 | 201 days ago | 0 ETH | ||||
| 21692855 | 201 days ago | 0 ETH | ||||
| 21691951 | 201 days ago | 0 ETH | ||||
| 21691951 | 201 days ago | 0 ETH | ||||
| 21691048 | 201 days ago | 0 ETH | ||||
| 21691048 | 201 days ago | 0 ETH | ||||
| 21690145 | 201 days ago | 0 ETH | ||||
| 21690145 | 201 days ago | 0 ETH | ||||
| 21689242 | 201 days ago | 0 ETH | ||||
| 21689242 | 201 days ago | 0 ETH | ||||
| 21688339 | 201 days ago | 0 ETH | ||||
| 21688339 | 201 days ago | 0 ETH | ||||
| 21687435 | 201 days ago | 0 ETH | ||||
| 21687435 | 201 days ago | 0 ETH | ||||
| 21686532 | 201 days ago | 0 ETH | ||||
| 21686532 | 201 days ago | 0 ETH | ||||
| 21685629 | 201 days ago | 0 ETH | ||||
| 21685629 | 201 days ago | 0 ETH | ||||
| 21684726 | 201 days ago | 0 ETH | ||||
| 21684726 | 201 days ago | 0 ETH | ||||
| 21683823 | 201 days ago | 0 ETH | ||||
| 21683823 | 201 days ago | 0 ETH | ||||
| 21682919 | 201 days ago | 0 ETH | ||||
| 21682919 | 201 days ago | 0 ETH | ||||
| 21682016 | 201 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Vault
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "../interfaces/IPriceFeed.sol";
import "./BaseVault.sol";
contract Vault is BaseVault {
IPriceFeed public priceFeed;
constructor(
address _wandProtocol,
address _settings,
address _assetToken_,
address _marginToken_,
address _assetTokenPriceFeed_
) BaseVault (
_wandProtocol,
_settings,
_assetToken_,
_marginToken_
) {
require(_assetTokenPriceFeed_ != address(0), "Zero address detected");
priceFeed = IPriceFeed(_assetTokenPriceFeed_);
}
function updatePriceFeed(address _assetTokenPriceFeed_) external nonReentrant onlyOwner {
require(_assetTokenPriceFeed_ != address(0), "Zero address detected");
priceFeed = IPriceFeed(_assetTokenPriceFeed_);
}
function _assetTokenPrice() internal view override returns (uint256, uint256) {
return (priceFeed.latestPrice(), priceFeed.decimals());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts 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.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// 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.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlast{
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256);
function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint256);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
interface IBlastPoints {
function configurePointsOperator(address operator) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMarginToken is IERC20 {
function configureBlastYieldsAndGas() external;
function mint(address to, uint256 amount) external;
function burn(address account, uint256 amount) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
interface IPriceFeed {
/**
* @notice The number of decimals in the returned price
*/
function decimals() external view returns (uint8);
/**
* @notice Returns the latest price of the asset in USD
*/
function latestPrice() external view returns (uint256);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
interface IProtocolSettings {
function treasury() external view returns (address);
function decimals() external view returns (uint256);
function isValidParam(bytes32 param, uint256 value) external view returns (bool);
function paramDefaultValue(bytes32 param) external view returns (uint256);
function vaultParamValue(address vault, bytes32 param) external view returns (uint256);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
interface IPtyPool {
function vault() external view returns (address);
function totalStakingShares() external view returns (uint256);
function totalStakingBalance() external view returns (uint256);
function addStakingYields(uint256 yieldsAmount) external;
function addMatchingYields(uint256 yieldsAmount) external;
function notifyBuyLowTriggered(uint256 assetAmountAdded) external;
function notifySellHighTriggered(uint256 assetAmountMatched, uint256 usbSharesReceived) external;
function configureBlastYieldsAndGas() external;
function configureBlastPoints() external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IUsb is IERC20 {
function decimals() external view returns (uint8);
function getBalanceByShares(uint256 sharesAmount) external view returns (uint256);
function getSharesByBalance(uint256 balance) external view returns (uint256);
function configureBlastYieldsAndGas() external;
function mint(address to, uint256 amount) external returns (uint256);
function burn(address account, uint256 amount) external returns (uint256);
function transferShares(address to, uint256 sharesAmount) external returns (uint256);
function rebase(uint256 addedSupply) external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "../libs/Constants.sol";
interface IVault {
function vaultType() external pure returns (Constants.VaultType);
function AARDecimals() external pure returns (uint256);
function usbToken() external view returns (address);
function assetToken() external view returns (address);
function assetTokenDecimals() external view returns (uint8);
function assetTokenPrice() external view returns (uint256, uint256);
function assetBalance() external view returns (uint256);
function usbTotalSupply() external view returns (uint256);
function marginToken() external view returns (address);
function vaultMode() external view returns (Constants.VaultMode);
function paramValue(bytes32 param) external view returns (uint256);
function AARBelowSafeLineTime() external view returns (uint256);
function AARBelowCircuitBreakerLineTime() external view returns (uint256);
function configureBlastYieldsAndGas() external;
function configureBlastPoints() external;
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
interface IWandProtocol {
function protocolOwner() external view returns (address);
function usbToken() external view returns (address);
function blastAddress() external view returns (address);
function blastPointsAddress() external view returns (address);
function blastPointsOperator() external view returns (address);
function isVault(address vaultAddress) external view returns (bool);
function isVaultAsset(address assetToken) external view returns (bool);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
library Constants {
/**
* @notice The address interpreted as native token of the chain.
*/
address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 public constant PROTOCOL_DECIMALS = 10;
struct Terms {
uint256 T1;
uint256 T2;
uint256 T3;
uint256 T4;
uint256 T5;
uint256 T6;
uint256 T7;
uint256 T8;
}
enum VaultType {
Volatile,
Stable
}
enum VaultMode {
Empty,
Stability,
AdjustmentBelowAARS,
AdjustmentAboveAARU
}
struct VaultState {
uint256 M_ETH;
uint256 P_ETH;
uint256 P_ETH_DECIMALS;
uint256 M_USB_ETH;
uint256 M_ETHx;
uint256 aar;
uint256 AART;
uint256 AARS;
uint256 AARU;
uint256 AARC;
uint256 AARDecimals;
uint256 RateR;
uint256 AARBelowSafeLineTime;
uint256 AARBelowCircuitBreakerLineTime;
}
struct StableVaultState {
uint256 M_USDC;
uint256 P_USDC;
uint256 P_USDC_DECIMALS;
uint256 M_USB_USDC;
uint256 M_USDCx;
uint256 aar;
// uint256 AART;
uint256 AARS;
// uint256 AARU;
// uint256 AARC;
uint256 AARDecimals;
uint256 RateR;
uint256 AARBelowSafeLineTime;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./Constants.sol";
library TokensTransfer {
using SafeERC20 for IERC20;
/// @dev Transfers a given amount of token.
function transferTokens(
address token,
address from,
address to,
uint256 amount
) internal {
if (token == Constants.NATIVE_TOKEN) {
safeTransferNativeToken(from, to, amount);
}
else {
safeTransferERC20(token, from, to, amount);
}
}
/// @dev Transfers `amount` of native token to `to`.
function safeTransferNativeToken(address from, address to, uint256 amount) internal {
require(from != to, "Same address");
require(from != address(0) && to != address(0), "Zero address");
require(from == address(this) || to == address(this), "One of the addresses must be this contract");
require(amount > 0, "Amount must be greater than 0");
if (to == address(this)) {
require(msg.value == amount, "Incorrect msg.value");
return;
}
// solhint-disable avoid-low-level-calls
// slither-disable-next-line low-level-calls
(bool success, ) = to.call{ value: amount }("");
require(success, "Native token transfer failed");
}
/// @dev Transfer `amount` of ERC20 token from `from` to `to`.
function safeTransferERC20(
address token,
address from,
address to,
uint256 amount
) internal {
require(from != to, "Same address");
require(from != address(0) && to != address(0), "Zero address");
// require(from == address(this) || to == address(this), "One of the addresses must be this contract");
require(amount > 0, "Amount must be greater than 0");
if (from == address(this)) {
IERC20(token).safeTransfer(to, amount);
}
else {
IERC20(token).safeTransferFrom(from, to, amount);
}
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
// import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./Constants.sol";
import "../interfaces/IMarginToken.sol";
import "../interfaces/IProtocolSettings.sol";
import "../interfaces/IPtyPool.sol";
import "../interfaces/IUsb.sol";
import "../interfaces/IVault.sol";
library VaultCalculator {
using SafeMath for uint256;
function vaultAssetTokenDecimals(IVault self) public view returns (uint8) {
address assetToken = self.assetToken();
if (assetToken == Constants.NATIVE_TOKEN) {
return 18;
}
return IERC20Metadata(assetToken).decimals();
}
/**
* @dev AAReth = (M_ETH * P_ETH / Musb-eth) * 100%
*/
function AAR(IVault self) public view returns (uint256) {
uint256 assetTotalAmount = self.assetBalance();
if (assetTotalAmount == 0) {
return 0;
}
if (self.usbTotalSupply() == 0) {
return type(uint256).max;
}
(uint256 assetTokenPrice, uint256 assetTokenPriceDecimals) = self.assetTokenPrice();
return assetTotalAmount.mul(assetTokenPrice).div(10 ** assetTokenPriceDecimals).mul(10 ** self.AARDecimals()).div(self.usbTotalSupply());
}
function getVaultState(IVault self) public view returns (Constants.VaultState memory) {
Constants.VaultState memory S;
S.M_ETH = self.assetBalance();
(S.P_ETH, S.P_ETH_DECIMALS) = self.assetTokenPrice();
S.M_USB_ETH = self.usbTotalSupply();
S.M_ETHx = IERC20(self.marginToken()).totalSupply();
S.aar = AAR(self);
S.AART = self.paramValue("AART");
S.AARS = self.paramValue("AARS");
S.AARU = self.paramValue("AARU");
S.AARC = self.paramValue("AARC");
S.AARDecimals = self.AARDecimals();
S.RateR = self.paramValue("RateR");
S.AARBelowSafeLineTime = self.AARBelowSafeLineTime();
S.AARBelowCircuitBreakerLineTime = self.AARBelowCircuitBreakerLineTime();
return S;
}
function calcMintPairs(IVault self, uint256 assetAmount) public view returns (Constants.VaultState memory, uint256, uint256) {
// Constants.VaultMode vaultMode = self.vaultMode();
// require(vaultMode == Constants.VaultMode.Empty || vaultMode == Constants.VaultMode.Stability, "Vault not in stability mode");
Constants.VaultState memory S = getVaultState(self);
uint256 usbOutAmount;
uint256 marginTokenOutAmount;
if (S.M_USB_ETH > 0 && S.M_ETHx > 0) {
// ΔUSB = ΔETH * M_USB_ETH / M_ETH
// ΔETHx = ΔUSB * M_ETHx / M_USB_ETH
usbOutAmount = assetAmount.mul(S.M_USB_ETH).div(S.M_ETH);
marginTokenOutAmount = usbOutAmount.mul(S.M_ETHx).div(S.M_USB_ETH);
} else {
// ΔUSB = ΔETH * P_ETH * 1 / AART
// ΔETHx = ΔETH * (1 - 1 / AART) = ΔETH * (AART - 1) / AART
Constants.Terms memory T;
T.T1 = assetAmount.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS);
usbOutAmount = T.T1.mul(10 ** S.AARDecimals).div(S.AART);
marginTokenOutAmount = assetAmount.mul(S.AART.sub(10 ** S.AARDecimals)).div(S.AART);
}
return (S, usbOutAmount, marginTokenOutAmount);
}
function calcMintUsbAboveAARU(IVault self, uint256 assetAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultMode vaultMode = self.vaultMode();
require(vaultMode == Constants.VaultMode.AdjustmentAboveAARU, "Vault not in adjustment above AARU mode");
Constants.VaultState memory S = getVaultState(self);
// ΔUSB = ΔETH * P_ETH
uint256 usbOutAmount = assetAmount.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS);
return (S, usbOutAmount);
}
function calcMintMarginTokensBelowAARS(IVault self, uint256 assetAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultMode vaultMode = self.vaultMode();
require(vaultMode == Constants.VaultMode.AdjustmentBelowAARS, "Vault not in adjustment below AARS mode");
Constants.VaultState memory S = getVaultState(self);
uint256 aar101 = (101 * (10 ** (S.AARDecimals - 2)));
uint256 marginTokenOutAmount;
if (S.aar >= aar101) { // aar >= 101%
// ΔETHx = ΔETH * P_ETH * M_ETHx / (M_ETH * P_ETH - Musb-eth)
marginTokenOutAmount = assetAmount.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS).mul(S.M_ETHx).div(
S.M_ETH.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS).sub(S.M_USB_ETH)
);
}
else { // aar < 101%
// ΔETHx = ΔETH * P_ETH * M_ETHx * 100 / Musb-eth
marginTokenOutAmount = assetAmount.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS).mul(S.M_ETHx).mul(100).div(S.M_USB_ETH);
}
return (S, marginTokenOutAmount);
}
function calcPairdMarginTokenAmount(IVault self, uint256 usbAmount) public view returns (uint256) {
Constants.VaultState memory S = getVaultState(self);
// ΔUSB = ΔETHx * Musb-eth / M_ETHx
// ΔETHx = ΔUSB * M_ETHx / Musb-eth
uint256 marginTokenOutAmount = usbAmount.mul(S.M_ETHx).div(S.M_USB_ETH);
return marginTokenOutAmount;
}
function calcPairedUsbAmount(IVault self, uint256 marginTokenAmount) public view returns (uint256) {
Constants.VaultState memory S = getVaultState(self);
// ΔUSB = ΔETHx * Musb-eth / M_ETHx
// ΔETHx = ΔUSB * M_ETHx / Musb-eth
uint256 usbOutAmount = marginTokenAmount.mul(S.M_USB_ETH).div(S.M_ETHx);
return usbOutAmount;
}
function calcPairedRedeemAssetAmount(IVault self, uint256 marginTokenAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultState memory S = getVaultState(self);
// ΔETH = ΔETHx * M_ETH / M_ETHx
uint256 assetOutAmount = marginTokenAmount.mul(S.M_ETH).div(S.M_ETHx);
return (S, assetOutAmount);
}
function calcRedeemByMarginTokenAboveAARU(IVault self, uint256 marginTokenAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultMode vaultMode = self.vaultMode();
require(vaultMode == Constants.VaultMode.AdjustmentAboveAARU, "Vault not in adjustment above AARU mode");
Constants.VaultState memory S = getVaultState(self);
// ΔETH = ΔETHx * (M_ETH * P_ETH - Musb-eth) / (M_ETHx * P_ETH)
uint256 assetOutAmount = marginTokenAmount.mul(
S.M_ETH.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS).sub(S.M_USB_ETH)
).div(S.M_ETHx.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS));
return (S, assetOutAmount);
}
function calcRedeemByUsbBelowAARS(IVault self, uint256 usbAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultMode vaultMode = self.vaultMode();
require(vaultMode == Constants.VaultMode.AdjustmentBelowAARS, "Vault not in adjustment below AARS mode");
Constants.VaultState memory S = getVaultState(self);
if (S.aar < (10 ** S.AARDecimals)) {
// ΔETH = ΔUSB * M_ETH / Musb-eth
uint256 assetOutAmount = usbAmount.mul(S.M_ETH).div(S.M_USB_ETH);
return (S, assetOutAmount);
}
else {
// ΔETH = ΔUSB / P_ETH
uint256 assetOutAmount = usbAmount.mul(10 ** S.P_ETH_DECIMALS).div(S.P_ETH);
return (S, assetOutAmount);
}
}
function calcUsbToMarginTokens(IVault self, IProtocolSettings settings, uint256 usbAmount) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultMode vaultMode = self.vaultMode();
require(vaultMode == Constants.VaultMode.AdjustmentBelowAARS, "Vault not in adjustment mode");
Constants.VaultState memory S = getVaultState(self);
require(S.aar >= S.AARC || (block.timestamp.sub(S.AARBelowCircuitBreakerLineTime) >= self.paramValue("CircuitBreakPeriod")), "Conditional Discount Purchase suspended");
uint256 aar101 = (101 * (10 ** (S.AARDecimals - 2)));
uint256 marginTokenOutAmount;
if (S.aar >= aar101) { // aar >= 101%
// ΔETHx = ΔUSB * M_ETHx * (1 + r) / (M_ETH * P_ETH - Musb-eth)
Constants.Terms memory T;
T.T1 = usbAmount.mul(S.M_ETHx).mul((10 ** settings.decimals()).add(_r(S.AARBelowSafeLineTime, S.RateR)));
marginTokenOutAmount = T.T1.div(
S.M_ETH.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS).sub(S.M_USB_ETH)
).div(10 ** settings.decimals());
}
else { // aar < 101%
// ΔETHx = ΔUSB * M_ETHx * 100 / Musb-eth
marginTokenOutAmount = usbAmount.mul(S.M_ETHx).mul(100).div(S.M_USB_ETH);
}
return (S, marginTokenOutAmount);
}
// 𝑟 = self.RateR() × 𝑡(h𝑟𝑠), since aar drop below 1.3;
// r = 0 since aar above 2;
function _r(uint256 aarBelowSafeLineTime, uint256 rateR) internal view returns (uint256) {
if (aarBelowSafeLineTime == 0) {
return 0;
}
return rateR.mul(block.timestamp.sub(aarBelowSafeLineTime)).div(1 hours);
}
function calcDeltaUsbForPtyPoolBuyLow(IVault self, IProtocolSettings settings, address usbToken, address ptyPoolBuyLow) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultState memory S = getVaultState(self);
// ΔETH = (Musb-eth * AART - M_ETH * P_ETH) / (P_ETH * (AART - 1))
// ΔUSB = (Musb-eth * AART - M_ETH * P_ETH) / (AART - 1)
uint256 deltaUsbAmount = S.M_USB_ETH.mul(S.AART).sub(
S.M_ETH.mul(S.P_ETH).mul(10 ** S.AARDecimals).div(10 ** S.P_ETH_DECIMALS)
).div(S.AART.sub(10 ** S.AARDecimals));
uint256 minUsbAmount = self.paramValue("PtyPoolMinUsbAmount");
// Convert to $USB decimals
minUsbAmount = minUsbAmount.mul(10 ** ((IUsb(usbToken).decimals() - settings.decimals())));
uint256 ptyPoolUsbBalance = IERC20(usbToken).balanceOf(ptyPoolBuyLow);
if (ptyPoolUsbBalance <= minUsbAmount) {
return (S, 0);
}
// console.log('calcDeltaUsbForPtyPoolBuyLow, minUsbAmount: %s, deltaUsbAmount: %s', minUsbAmount, deltaUsbAmount);
deltaUsbAmount = deltaUsbAmount > ptyPoolUsbBalance.sub(minUsbAmount) ? ptyPoolUsbBalance.sub(minUsbAmount) : deltaUsbAmount;
return (S, deltaUsbAmount);
}
function calcDeltaAssetForPtyPoolSellHigh(IVault self, IProtocolSettings settings, address ptyPoolSellHigh) public view returns (Constants.VaultState memory, uint256) {
Constants.VaultState memory S = getVaultState(self);
// ΔETH = (M_ETH * P_ETH - Musb-eth * AART) / (P_ETH * (AART - 1))
uint256 deltaAssetAmount = S.M_ETH.mul(S.P_ETH).mul(10 ** S.AARDecimals).sub(
S.M_USB_ETH.mul(S.AART).mul(10 ** S.P_ETH_DECIMALS)
).div(S.P_ETH.mul(S.AART.sub(10 ** S.AARDecimals)));
uint256 minAssetAmount = self.paramValue("PtyPoolMinAssetAmount");
if (self.assetTokenDecimals() > settings.decimals()) {
minAssetAmount = minAssetAmount.mul(10 ** (self.assetTokenDecimals() - settings.decimals()));
}
else {
minAssetAmount = minAssetAmount.div(10 ** (settings.decimals() - self.assetTokenDecimals()));
}
uint256 ptyPoolAssetBalance = IPtyPool(ptyPoolSellHigh).totalStakingBalance();
if (ptyPoolAssetBalance <= minAssetAmount) {
return (S, 0);
}
// console.log('calcDeltaAssetForPtyPoolSellHigh, minAssetAmount: %s, deltaAssetAmount: %s', minAssetAmount, deltaAssetAmount);
deltaAssetAmount = deltaAssetAmount > ptyPoolAssetBalance.sub(minAssetAmount) ? ptyPoolAssetBalance.sub(minAssetAmount) : deltaAssetAmount;
return (S, deltaAssetAmount);
}
function calcRedeemFees(IVault self, IProtocolSettings settings, uint256 assetAmount) public view returns (uint256, uint256, uint256, uint256) {
require(assetAmount <= self.assetBalance(), "Not enough asset balance");
uint256 totalFees = assetAmount.mul(settings.vaultParamValue(address(self), "C")).div(10 ** settings.decimals());
uint256 feesToTreasury = totalFees.mul(settings.vaultParamValue(address(self), "TreasuryFeeRate")).div(10 ** settings.decimals());
uint256 feesToPtyPoolBuyLow = totalFees.sub(feesToTreasury).mul(settings.vaultParamValue(address(self), "PtyPoolBuyLowFeeRate")).div(10 ** settings.decimals());
uint256 feesToPtyPoolSellHigh = totalFees.sub(feesToTreasury).sub(feesToPtyPoolBuyLow);
uint256 netRedeemAmount = assetAmount.sub(feesToTreasury).sub(feesToPtyPoolBuyLow).sub(feesToPtyPoolSellHigh);
return (netRedeemAmount, feesToTreasury, feesToPtyPoolBuyLow, feesToPtyPoolSellHigh);
}
function calcSettleYields(
IVault self, IProtocolSettings settings, uint256 yieldsBaseAssetAmount,
uint256 lastYieldsSettlementTime
) public view returns (uint256, uint256) {
uint256 usbOutAmount = 0;
uint256 marginTokenOutAmount = 0;
uint256 timeElapsed = block.timestamp.sub(lastYieldsSettlementTime);
uint256 Y = settings.vaultParamValue(address(self), "Y");
uint256 deltaAssetAmount = timeElapsed.mul(Y).mul(yieldsBaseAssetAmount).div(365 days).div(10 ** settings.decimals());
if (deltaAssetAmount > 0) {
Constants.VaultState memory S;
(S, usbOutAmount, marginTokenOutAmount) = calcMintPairs(self, deltaAssetAmount);
}
return (usbOutAmount, marginTokenOutAmount);
}
function paramValue(IVault self, IProtocolSettings settings, bytes32 paramName) public view returns (uint256) {
return settings.vaultParamValue(address(self), paramName);
}
function getParamAARs(IVault self, IProtocolSettings settings) public view returns (uint256, uint256, uint256, uint256) {
return (
settings.vaultParamValue(address(self), "AART"),
settings.vaultParamValue(address(self), "AARS"),
settings.vaultParamValue(address(self), "AARU"),
settings.vaultParamValue(address(self), "AARC")
);
}
function calcPtyPoolMinAssetAmount(IVault self, IProtocolSettings settings) public view returns (uint256) {
uint256 minAssetAmount = settings.vaultParamValue(address(self), "PtyPoolMinAssetAmount");
if (vaultAssetTokenDecimals(self) > settings.decimals()) {
minAssetAmount = minAssetAmount.mul(10 ** (vaultAssetTokenDecimals(self) - settings.decimals()));
}
else {
minAssetAmount = minAssetAmount.div(10 ** (settings.decimals() - vaultAssetTokenDecimals(self)));
}
return minAssetAmount;
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/utils/Context.sol";
import "../interfaces/IWandProtocol.sol";
abstract contract ProtocolOwner is Context {
IWandProtocol public immutable wandProtocol;
constructor(address _wandProtocol_) {
require(_wandProtocol_ != address(0), "Zero address detected");
wandProtocol = IWandProtocol(_wandProtocol_);
}
modifier onlyProtocol() {
require(_msgSender() == address(wandProtocol), "Ownable: caller is not the protocol");
_;
}
modifier onlyOwner() {
require(_msgSender() == IWandProtocol(wandProtocol).protocolOwner(), "Ownable: caller is not the owner");
_;
}
function owner() public view returns(address) {
return IWandProtocol(wandProtocol).protocolOwner();
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
// import "hardhat/console.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../libs/Constants.sol";
import "../libs/TokensTransfer.sol";
import "../libs/VaultCalculator.sol";
import "../interfaces/IBlast.sol";
import "../interfaces/IMarginToken.sol";
import "../interfaces/IProtocolSettings.sol";
import "../interfaces/IPtyPool.sol";
import "../interfaces/IUsb.sol";
import "../interfaces/IVault.sol";
import "../interfaces/IWandProtocol.sol";
import "../settings/ProtocolOwner.sol";
import "./TokenPot.sol";
abstract contract BaseVault is IVault, ReentrancyGuard, ProtocolOwner {
using SafeMath for uint256;
using VaultCalculator for BaseVault;
bool internal _mintPaused;
bool internal _redeemPaused;
bool internal _usbToMarginTokensPaused;
IProtocolSettings public immutable settings;
TokenPot public immutable tokenPot;
IPtyPool public ptyPoolBuyLow;
IPtyPool public ptyPoolSellHigh;
uint256 internal _accruedStakingYieldsForPtyPoolBuyLow; // $ETHx
uint256 internal _accruedMatchingYieldsForPtyPoolBuyLow; // $ETH
uint256 internal _accruedStakingYieldsForPtyPoolSellHigh; // $ETH
uint256 internal _accruedMatchingYieldsForPtyPoolSellHigh; // $ETHx
address internal immutable _assetToken;
address internal immutable _usbToken;
address internal immutable _marginToken;
uint256 internal _usbTotalShares;
Constants.VaultMode internal _vaultMode;
uint256 internal _lastYieldsSettlementTime;
uint256 internal _previousAAR;
uint256 internal _aarBelowSafeLineTime;
uint256 internal _aarBelowCircuitBreakerLineTime;
constructor(
address _wandProtocol,
address _settings,
address _assetToken_,
address _marginToken_
) ProtocolOwner(_wandProtocol) {
require(
_settings != address(0) && _assetToken_ != address(0) && _marginToken_ != address(0),
"Zero address detected"
);
require(tx.origin == wandProtocol.protocolOwner(), "Vault should only be created by protocol owner");
tokenPot = new TokenPot(_wandProtocol, _settings);
_assetToken = _assetToken_;
_marginToken = _marginToken_;
_usbToken = wandProtocol.usbToken();
settings = IProtocolSettings(_settings);
_vaultMode = Constants.VaultMode.Empty;
_mintPaused = false;
_redeemPaused = false;
_usbToMarginTokensPaused = false;
}
receive() external payable { TokensTransfer.transferTokens(_assetToken, address(this), address(tokenPot), msg.value); }
/* ================= VIEWS ================ */
function paused() external view virtual returns (bool, bool, bool) {
return (_mintPaused, _redeemPaused, _usbToMarginTokensPaused);
}
function usbToken() external view override returns (address) {
return _usbToken;
}
function vaultType() external pure override returns (Constants.VaultType) {
return Constants.VaultType.Volatile;
}
function usbTotalSupply() public view override returns (uint256) {
return IUsb(_usbToken).getBalanceByShares(_usbTotalShares);
}
function usbTotalShares() public view returns (uint256) {
return _usbTotalShares;
}
function assetBalance() external view override returns (uint256) {
return tokenPot.balance(_assetToken).sub(
_accruedMatchingYieldsForPtyPoolBuyLow
).sub(_accruedStakingYieldsForPtyPoolSellHigh);
}
function assetToken() public view override returns (address) {
return _assetToken;
}
function assetTokenDecimals() public view override returns (uint8) {
return this.vaultAssetTokenDecimals();
}
function assetTokenPrice() external view override returns (uint256, uint256) {
return _assetTokenPrice();
}
function marginToken() public view override returns (address) {
return _marginToken;
}
function paramValue(bytes32 param) public view override returns (uint256) {
return settings.vaultParamValue(address(this), param);
}
function vaultMode() external view override returns (Constants.VaultMode) {
return _vaultMode;
}
function AARDecimals() public pure returns (uint256) {
return Constants.PROTOCOL_DECIMALS;
}
function AARBelowSafeLineTime() public view returns (uint256) {
return _aarBelowSafeLineTime;
}
function AARBelowCircuitBreakerLineTime() public view returns (uint256) {
return _aarBelowCircuitBreakerLineTime;
}
/* ========== Mint FUNCTIONS ========== */
function mintPairs(uint256 assetAmount) external payable nonReentrant whenMintNotPaused noneZeroValue(assetAmount) onUserAction(true) {
(Constants.VaultState memory S, uint256 usbOutAmount, uint256 marginTokenOutAmount) = this.calcMintPairs(assetAmount);
_doMint(assetAmount, S, usbOutAmount, marginTokenOutAmount);
}
function mintUsbAboveAARU(uint256 assetAmount) external payable nonReentrant whenMintNotPaused noneZeroValue(assetAmount) onUserAction(true) {
(Constants.VaultState memory S, uint256 usbOutAmount) = this.calcMintUsbAboveAARU(assetAmount);
_doMint(assetAmount, S, usbOutAmount, 0);
}
function mintMarginTokensBelowAARS(uint256 assetAmount) external payable nonReentrant whenMintNotPaused noneZeroValue(assetAmount) onUserAction(true) {
(Constants.VaultState memory S, uint256 marginTokenOutAmount) = this.calcMintMarginTokensBelowAARS(assetAmount);
_doMint(assetAmount, S, 0, marginTokenOutAmount);
}
/* ========== Redeem FUNCTIONS ========== */
function redeemByPairsWithExpectedUsbAmount(uint256 usbAmount) external nonReentrant whenRedeemNotPaused noneZeroValue(usbAmount) onUserAction(true) {
require(usbAmount <= IUsb(_usbToken).balanceOf(_msgSender()), "Not enough USB balance");
uint256 pairdMarginTokenAmount = this.calcPairdMarginTokenAmount(usbAmount);
require(pairdMarginTokenAmount <= IMarginToken(_marginToken).balanceOf(_msgSender()), "Not enough margin token balance");
(Constants.VaultState memory S, uint256 assetOutAmount) = this.calcPairedRedeemAssetAmount(pairdMarginTokenAmount);
uint256 netRedeemAmount = _doRedeem(assetOutAmount, S, usbAmount, pairdMarginTokenAmount);
emit AssetRedeemedWithPairs(_msgSender(), usbAmount, pairdMarginTokenAmount, netRedeemAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
function redeemByPairsWithExpectedMarginTokenAmount(uint256 marginTokenAmount) external nonReentrant whenRedeemNotPaused noneZeroValue(marginTokenAmount) onUserAction(true) {
require(marginTokenAmount <= IMarginToken(_marginToken).balanceOf(_msgSender()), "Not enough margin token balance");
uint256 pairedUSBAmount = this.calcPairedUsbAmount(marginTokenAmount);
require(pairedUSBAmount <= IUsb(_usbToken).balanceOf(_msgSender()), "Not enough USB balance");
(Constants.VaultState memory S, uint256 assetOutAmount) = this.calcPairedRedeemAssetAmount(marginTokenAmount);
uint256 netRedeemAmount = _doRedeem(assetOutAmount, S, pairedUSBAmount, marginTokenAmount);
emit AssetRedeemedWithPairs(_msgSender(), pairedUSBAmount, marginTokenAmount, netRedeemAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
function redeemByMarginTokenAboveAARU(uint256 marginTokenAmount) external nonReentrant whenRedeemNotPaused noneZeroValue(marginTokenAmount) onUserAction(true) {
require(marginTokenAmount <= IMarginToken(_marginToken).balanceOf(_msgSender()), "Not enough margin token balance");
(Constants.VaultState memory S, uint256 assetOutAmount) = this.calcRedeemByMarginTokenAboveAARU(marginTokenAmount);
uint256 netRedeemAmount = _doRedeem(assetOutAmount, S, 0, marginTokenAmount);
emit AssetRedeemedWithMarginToken(_msgSender(), marginTokenAmount, netRedeemAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
function redeemByUsbBelowAARS(uint256 usbAmount) external payable nonReentrant whenRedeemNotPaused noneZeroValue(usbAmount) onUserAction(true) {
require(usbAmount <= IUsb(_usbToken).balanceOf(_msgSender()), "Not enough USB balance");
(Constants.VaultState memory S, uint256 assetOutAmount) = this.calcRedeemByUsbBelowAARS(usbAmount);
uint256 netRedeemAmount = _doRedeem(assetOutAmount, S, usbAmount, 0);
emit AssetRedeemedWithUSB(_msgSender(), usbAmount, netRedeemAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
/* ========== Other FUNCTIONS ========== */
function usbToMarginTokens(uint256 usbAmount) external nonReentrant whenUsbToMarginTokensNotPaused noneZeroValue(usbAmount) onUserAction(false) {
require(usbAmount <= IUsb(_usbToken).balanceOf(_msgSender()), "Not enough USB balance");
(Constants.VaultState memory S, uint256 marginTokenAmount) = this.calcUsbToMarginTokens(settings, usbAmount);
uint256 usbSharesAmount = IUsb(_usbToken).burn(_msgSender(), usbAmount);
_usbTotalShares = _usbTotalShares.sub(usbSharesAmount);
emit UsbBurned(_msgSender(), usbAmount, usbSharesAmount, S.P_ETH, S.P_ETH_DECIMALS);
IMarginToken(_marginToken).mint(_msgSender(), marginTokenAmount);
emit MarginTokenMinted(_msgSender(), 0, marginTokenAmount, S.P_ETH, S.P_ETH_DECIMALS);
emit UsbToMarginTokens(_msgSender(), usbAmount, marginTokenAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
/* ========== RESTRICTED FUNCTIONS ========== */
function configureBlastYieldsAndGas() external nonReentrant onlyProtocol {
address blastAddress = wandProtocol.blastAddress();
if (blastAddress != address(0)) {
IBlast blast = IBlast(wandProtocol.blastAddress());
if (_assetToken == Constants.NATIVE_TOKEN) {
blast.configureAutomaticYield();
}
blast.configureClaimableGas();
tokenPot.configureBlastYieldsAndGas();
IMarginToken(_marginToken).configureBlastYieldsAndGas();
ptyPoolBuyLow.configureBlastYieldsAndGas();
ptyPoolSellHigh.configureBlastYieldsAndGas();
}
}
function configureBlastPoints() external nonReentrant onlyProtocol {
address blastPointsAddress = wandProtocol.blastPointsAddress();
address blastPointsOperatorAddress = wandProtocol.blastPointsOperator();
if (blastPointsAddress != address(0) && blastPointsOperatorAddress != address(0)) {
tokenPot.configureBlastPoints();
ptyPoolBuyLow.configureBlastPoints();
ptyPoolSellHigh.configureBlastPoints();
}
}
function pauseMint() external nonReentrant onlyOwner {
_mintPaused = true;
emit MintPaused();
}
function unpauseMint() external nonReentrant onlyOwner {
_mintPaused = false;
emit MintUnpaused();
}
function pauseRedeem() external nonReentrant onlyOwner {
_redeemPaused = true;
emit RedeemPaused();
}
function unpauseRedeem() external nonReentrant onlyOwner {
_redeemPaused = false;
emit RedeemUnpaused();
}
function pauseUsbToMarginTokens() external nonReentrant onlyOwner {
_usbToMarginTokensPaused = true;
emit UsbToMarginTokensPaused();
}
function unpauseUsbToMarginTokens() external nonReentrant onlyOwner {
_usbToMarginTokensPaused = false;
emit UsbToMarginTokensUnpaused();
}
function setPtyPools(address _ptyPoolBuyLow, address _ptyPoolSellHigh) external nonReentrant onlyOwner {
require(_ptyPoolBuyLow != address(0) && _ptyPoolSellHigh != address(0), "Zero address detected");
// require(ptyPoolBuyLow == IPtyPool(address(0)) && ptyPoolSellHigh == IPtyPool(address(0)), "PtyPools already set");
require(IPtyPool(_ptyPoolBuyLow).vault() == address(this) && IPtyPool(_ptyPoolSellHigh).vault() == address(this), "Invalid vault");
ptyPoolBuyLow = IPtyPool(_ptyPoolBuyLow);
ptyPoolSellHigh = IPtyPool(_ptyPoolSellHigh);
}
/* ========== INTERNAL FUNCTIONS ========== */
function _doMint(uint256 assetAmount, Constants.VaultState memory S, uint256 usbOutAmount, uint256 marginTokenOutAmount) internal {
if (_assetToken == Constants.NATIVE_TOKEN) {
TokensTransfer.transferTokens(_assetToken, address(this), address(tokenPot), assetAmount);
}
else {
TokensTransfer.transferTokens(_assetToken, _msgSender(), address(tokenPot), assetAmount);
}
if (usbOutAmount > 0) {
uint256 usbSharesAmount = IUsb(_usbToken).mint(_msgSender(), usbOutAmount);
_usbTotalShares = _usbTotalShares.add(usbSharesAmount);
emit UsbMinted(_msgSender(), assetAmount, usbOutAmount, usbSharesAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
if (marginTokenOutAmount > 0) {
IMarginToken(_marginToken).mint(_msgSender(), marginTokenOutAmount);
emit MarginTokenMinted(_msgSender(), assetAmount, marginTokenOutAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
}
function _doRedeem(uint256 assetAmount, Constants.VaultState memory S, uint256 usbAmount, uint256 marginTokenAmount) internal returns (uint256) {
(uint256 netRedeemAmount, uint256 feesToTreasury, uint256 feesToPtyPoolBuyLow, uint256 feesToPtyPoolSellHigh) = this.calcRedeemFees(settings, assetAmount);
tokenPot.withdraw(_msgSender(), _assetToken, netRedeemAmount);
if (feesToTreasury > 0) {
tokenPot.withdraw(settings.treasury(), _assetToken, feesToTreasury);
}
// console.log('_doRedeem, asset: %s, feesToTreasury: %s, netRedeemAmount: %s', totalFees, feesToTreasury, netRedeemAmount);
_accruedMatchingYieldsForPtyPoolBuyLow = _accruedMatchingYieldsForPtyPoolBuyLow.add(feesToPtyPoolBuyLow);
if (_accruedMatchingYieldsForPtyPoolBuyLow > 0 && ptyPoolBuyLow.totalStakingShares() > 0) {
tokenPot.withdraw(address(ptyPoolBuyLow), _assetToken, _accruedMatchingYieldsForPtyPoolBuyLow);
ptyPoolBuyLow.addMatchingYields(_accruedMatchingYieldsForPtyPoolBuyLow);
_accruedMatchingYieldsForPtyPoolBuyLow = 0;
}
_accruedStakingYieldsForPtyPoolSellHigh = _accruedStakingYieldsForPtyPoolSellHigh.add(feesToPtyPoolSellHigh);
if (_accruedStakingYieldsForPtyPoolSellHigh > 0 && ptyPoolSellHigh.totalStakingShares() > 0) {
tokenPot.withdraw(address(ptyPoolSellHigh), _assetToken, _accruedStakingYieldsForPtyPoolSellHigh);
ptyPoolSellHigh.addStakingYields(_accruedStakingYieldsForPtyPoolSellHigh);
_accruedStakingYieldsForPtyPoolSellHigh = 0;
}
if (usbAmount > 0) {
uint256 usbBurnShares = IUsb(_usbToken).burn(_msgSender(), usbAmount);
_usbTotalShares = _usbTotalShares.sub(usbBurnShares);
emit UsbBurned(_msgSender(), usbAmount, usbBurnShares, S.P_ETH, S.P_ETH_DECIMALS);
}
if (marginTokenAmount > 0) {
IMarginToken(_marginToken).burn(_msgSender(), marginTokenAmount);
emit MarginTokenBurned(_msgSender(), marginTokenAmount, S.P_ETH, S.P_ETH_DECIMALS);
}
return netRedeemAmount;
}
function _ptyPoolMatchBelowAARS() internal {
(Constants.VaultState memory S, uint256 deltaUsbAmount) = this.calcDeltaUsbForPtyPoolBuyLow(settings, wandProtocol.usbToken(), address(ptyPoolBuyLow));
if (deltaUsbAmount == 0) {
return;
}
uint256 deltaAssetAmount = deltaUsbAmount.mul(10 ** S.P_ETH_DECIMALS).div(S.P_ETH);
tokenPot.withdraw(address(ptyPoolBuyLow), _assetToken, deltaAssetAmount);
// console.log('_ptyPoolMatchBelowAARS, deltaUsbAmount: %s, deltaAssetAmount: %s', deltaUsbAmount, deltaAssetAmount);
uint256 usbBurnShares = IUsb(_usbToken).burn(address(ptyPoolBuyLow), deltaUsbAmount);
_usbTotalShares = _usbTotalShares.sub(usbBurnShares);
emit UsbBurned(address(ptyPoolBuyLow), deltaUsbAmount, usbBurnShares, S.P_ETH, S.P_ETH_DECIMALS);
ptyPoolBuyLow.notifyBuyLowTriggered(deltaAssetAmount);
}
function _ptyPoolMatchAboveAARU() internal {
(Constants.VaultState memory S, uint256 deltaAssetAmount) = this.calcDeltaAssetForPtyPoolSellHigh(settings, address(ptyPoolSellHigh));
if (deltaAssetAmount == 0) {
return;
}
uint256 deltaUsbAmount = deltaAssetAmount.mul(S.P_ETH).div(10 ** S.P_ETH_DECIMALS);
uint256 usbSharesAmount = IUsb(_usbToken).mint(address(ptyPoolSellHigh), deltaUsbAmount);
_usbTotalShares = _usbTotalShares.add(usbSharesAmount);
emit UsbMinted(_msgSender(), deltaAssetAmount, deltaUsbAmount, usbSharesAmount, S.P_ETH, S.P_ETH_DECIMALS);
// console.log('_ptyPoolMatchAboveAARU, deltaUsbAmount: %s, deltaAssetAmount: %s', deltaUsbAmount, deltaAssetAmount);
ptyPoolSellHigh.notifySellHighTriggered(deltaAssetAmount, usbSharesAmount);
}
function _doSettleYields(uint256 yieldsBaseAssetAmount) internal {
(uint256 usbOutAmount, uint256 marginTokenOutAmount) = this.calcSettleYields(settings, yieldsBaseAssetAmount, _lastYieldsSettlementTime);
if (usbOutAmount > 0) {
IUsb(_usbToken).rebase(usbOutAmount);
}
if (marginTokenOutAmount > 0) {
uint256 toPtyPoolBuyLow = marginTokenOutAmount.mul(
settings.vaultParamValue(address(this), "PtyPoolBuyLowMarginYieldsRate")
).div(10 ** settings.decimals());
_accruedStakingYieldsForPtyPoolBuyLow = _accruedStakingYieldsForPtyPoolBuyLow.add(toPtyPoolBuyLow);
uint256 toPtyPoolSellHigh = marginTokenOutAmount.sub(toPtyPoolBuyLow);
_accruedMatchingYieldsForPtyPoolSellHigh = _accruedMatchingYieldsForPtyPoolSellHigh.add(toPtyPoolSellHigh);
}
if (_accruedStakingYieldsForPtyPoolBuyLow > 0 && ptyPoolBuyLow.totalStakingShares() > 0) {
IMarginToken(_marginToken).mint(address(this), _accruedStakingYieldsForPtyPoolBuyLow);
TokensTransfer.transferTokens(_marginToken, address(this), address(ptyPoolBuyLow), _accruedStakingYieldsForPtyPoolBuyLow);
ptyPoolBuyLow.addStakingYields(_accruedStakingYieldsForPtyPoolBuyLow);
_accruedStakingYieldsForPtyPoolBuyLow = 0;
}
if (_accruedMatchingYieldsForPtyPoolSellHigh > 0 && ptyPoolSellHigh.totalStakingShares() > 0) {
IMarginToken(_marginToken).mint(address(this), _accruedMatchingYieldsForPtyPoolSellHigh);
TokensTransfer.transferTokens(_marginToken, address(this), address(ptyPoolSellHigh), _accruedMatchingYieldsForPtyPoolSellHigh);
ptyPoolSellHigh.addMatchingYields(_accruedMatchingYieldsForPtyPoolSellHigh);
_accruedMatchingYieldsForPtyPoolSellHigh = 0;
}
if (usbOutAmount > 0 || marginTokenOutAmount > 0) {
emit YieldsSettlement(usbOutAmount, marginTokenOutAmount);
}
}
function _assetTokenPrice() internal view virtual returns (uint256, uint256);
/* ============== MODIFIERS =============== */
modifier whenMintNotPaused() {
require(!_mintPaused, "Mint paused");
_;
}
modifier whenRedeemNotPaused() {
require(!_redeemPaused, "Redeem paused");
_;
}
modifier whenUsbToMarginTokensNotPaused() {
require(!_usbToMarginTokensPaused, "USB to Margin Tokens paused");
_;
}
modifier noneZeroValue(uint256 value) {
require(value > 0, "Value must be greater than 0");
_;
}
modifier noneZeroAddress(address addr) {
require(addr != address(0), "Zero address detected");
_;
}
function _updateStateOnUserAction(uint256 previousAAR, uint256 afterAAR) internal {
(uint256 AART, uint256 AARS, uint256 AARU, uint256 AARC) = this.getParamAARs(settings);
if (afterAAR > AARU) {
_vaultMode = Constants.VaultMode.AdjustmentAboveAARU;
_aarBelowSafeLineTime = 0;
}
else if (afterAAR < AARS) {
_vaultMode = Constants.VaultMode.AdjustmentBelowAARS;
if (previousAAR >= AARS) {
_aarBelowSafeLineTime = block.timestamp;
}
}
else if ((previousAAR < AART && afterAAR >= AART) || (previousAAR > AART && afterAAR <= AART)) {
// else if ((previousAAR < AARS && afterAAR >= AART) || (previousAAR > AARU && afterAAR <= AART)) {
// bool lastIsAdjustment = _vaultMode != Constants.VaultMode.Stability;
if (_vaultMode != Constants.VaultMode.Stability) {
_vaultMode = Constants.VaultMode.Stability;
_aarBelowSafeLineTime = 0;
}
}
if (previousAAR >= AARC && afterAAR < AARC) {
_aarBelowCircuitBreakerLineTime = block.timestamp;
}
else if (previousAAR < AARC && afterAAR >= AARC) {
_aarBelowCircuitBreakerLineTime = 0;
}
}
modifier onUserAction(bool settleYields) {
if (_vaultMode == Constants.VaultMode.Empty) {
_vaultMode = Constants.VaultMode.Stability;
}
uint256 yieldsBaseAssetAmount = tokenPot.balance(_assetToken);
_;
if (settleYields) {
if (_lastYieldsSettlementTime != 0) {
_doSettleYields(yieldsBaseAssetAmount);
}
_lastYieldsSettlementTime = block.timestamp;
}
uint256 afterAAR = this.AAR();
_updateStateOnUserAction(_previousAAR, afterAAR);
if (afterAAR < paramValue("AARS")) {
require(ptyPoolBuyLow != IPtyPool(address(0)), "PtyPoolBuyLow not set");
uint256 minUsbAmount = paramValue("PtyPoolMinUsbAmount").mul(10 ** ((IUsb(_usbToken).decimals() - settings.decimals())));
if (ptyPoolBuyLow.totalStakingBalance() > minUsbAmount) {
_ptyPoolMatchBelowAARS();
_updateStateOnUserAction(afterAAR, this.AAR());
}
}
else if (afterAAR > paramValue("AARU")) {
require(ptyPoolSellHigh != IPtyPool(address(0)), "PtyPoolSellHigh not set");
uint256 minAssetAmount = this.calcPtyPoolMinAssetAmount(settings);
if (ptyPoolSellHigh.totalStakingBalance() > minAssetAmount) {
_ptyPoolMatchAboveAARU();
_updateStateOnUserAction(afterAAR, this.AAR());
}
}
_previousAAR = this.AAR();
address blastAddress = wandProtocol.blastAddress();
if (blastAddress != address(0)) {
IBlast blast = IBlast(blastAddress);
(uint256 etherSeconds, uint256 etherBalance, ,) = blast.readGasParams(address(this));
if (etherSeconds > 0 && etherBalance > 0) {
blast.claimAllGas(address(this), settings.treasury());
}
}
}
/* =============== EVENTS ============= */
event MintPaused();
event MintUnpaused();
event RedeemPaused();
event RedeemUnpaused();
event UsbToMarginTokensPaused();
event UsbToMarginTokensUnpaused();
event UsbMinted(address indexed user, uint256 assetTokenAmount, uint256 usbTokenAmount, uint256 usbSharesAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event MarginTokenMinted(address indexed user, uint256 assetTokenAmount, uint256 marginTokenAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event UsbBurned(address indexed user, uint256 usbTokenAmount, uint256 usbSharesAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event MarginTokenBurned(address indexed user, uint256 marginTokenAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event AssetRedeemedWithPairs(address indexed user, uint256 usbAmount, uint256 marginTokenAmount, uint256 assetAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event AssetRedeemedWithUSB(address indexed user, uint256 usbAmount, uint256 assetAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event AssetRedeemedWithMarginToken(address indexed user, uint256 marginTokenAmount, uint256 assetAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event UsbToMarginTokens(address indexed user, uint256 usbAmount, uint256 marginTokenAmount, uint256 assetTokenPrice, uint256 assetTokenPriceDecimals);
event YieldsSettlement(uint256 usbYieldsAmount, uint256 marginTokenYieldsAmount);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "../libs/Constants.sol";
import "../libs/TokensTransfer.sol";
import "../settings/ProtocolOwner.sol";
import "../interfaces/IBlast.sol";
import "../interfaces/IBlastPoints.sol";
import "../interfaces/IProtocolSettings.sol";
import "../interfaces/IWandProtocol.sol";
contract TokenPot is Context, ReentrancyGuard {
// IBlastPoints public immutable blastPoints;
IProtocolSettings public immutable settings;
address public immutable owner;
IWandProtocol public immutable wandProtocol;
constructor(address _wandProtocol, address _settings) {
require(_wandProtocol != address(0) && _settings != address(0), "Zero address detected");
owner = msg.sender;
settings = IProtocolSettings(_settings);
wandProtocol = IWandProtocol(_wandProtocol);
}
receive() external payable {}
function balance(address token) public view returns (uint256) {
if (token == Constants.NATIVE_TOKEN) {
return address(this).balance;
}
else {
return IERC20(token).balanceOf(address(this));
}
}
function configureBlastYieldsAndGas() external nonReentrant onlyOwner {
address blastAddress = wandProtocol.blastAddress();
if (blastAddress != address(0)) {
IBlast blast = IBlast(wandProtocol.blastAddress());
blast.configureAutomaticYield();
blast.configureClaimableGas();
}
}
function configureBlastPoints() external nonReentrant onlyOwner {
address blastPointsAddress = wandProtocol.blastPointsAddress();
address blastPointsOperatorAddress = wandProtocol.blastPointsOperator();
if (blastPointsAddress != address(0) && blastPointsOperatorAddress != address(0)) {
IBlastPoints blastPoints = IBlastPoints(blastPointsAddress);
blastPoints.configurePointsOperator(blastPointsOperatorAddress);
}
}
// Only owner could withdraw from this contract
function withdraw(address recipient, address token, uint256 amount) external nonReentrant onlyOwner {
require(recipient != address(0) && token != address(0), "Zero address detected");
require(amount > 0 && amount <= balance(token), "Invalid amount");
TokensTransfer.transferTokens(token, address(this), recipient, amount);
emit Withdrawn(_msgSender(), recipient, token, amount);
address blastAddress = wandProtocol.blastAddress();
if (blastAddress != address(0)) {
IBlast blast = IBlast(blastAddress);
(uint256 etherSeconds, uint256 etherBalance, ,) = blast.readGasParams(address(this));
if (etherSeconds > 0 && etherBalance > 0) {
blast.claimAllGas(address(this), settings.treasury());
}
}
}
modifier onlyOwner() {
require(_msgSender() == owner, "TokenPot: caller is not the owner");
_;
}
/* =============== EVENTS ============= */
event Withdrawn(address indexed withdrawer, address indexed recipient, address indexed token, uint256 amount);
}{
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 100,
"details": {
"yulDetails": {
"optimizerSteps": "u"
}
}
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {
"contracts/libs/VaultCalculator.sol": {
"VaultCalculator": "0xb5ecfd108619fb8e7c65658b9419f81ea62e4952"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_wandProtocol","type":"address"},{"internalType":"address","name":"_settings","type":"address"},{"internalType":"address","name":"_assetToken_","type":"address"},{"internalType":"address","name":"_marginToken_","type":"address"},{"internalType":"address","name":"_assetTokenPriceFeed_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"AssetRedeemedWithMarginToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"usbAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"AssetRedeemedWithPairs","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"usbAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"AssetRedeemedWithUSB","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"marginTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"MarginTokenBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"MarginTokenMinted","type":"event"},{"anonymous":false,"inputs":[],"name":"MintPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"MintUnpaused","type":"event"},{"anonymous":false,"inputs":[],"name":"RedeemPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"RedeemUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"usbTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usbSharesAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"UsbBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usbTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usbSharesAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"UsbMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"usbAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetTokenPriceDecimals","type":"uint256"}],"name":"UsbToMarginTokens","type":"event"},{"anonymous":false,"inputs":[],"name":"UsbToMarginTokensPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"UsbToMarginTokensUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"usbYieldsAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"marginTokenYieldsAmount","type":"uint256"}],"name":"YieldsSettlement","type":"event"},{"inputs":[],"name":"AARBelowCircuitBreakerLineTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AARBelowSafeLineTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AARDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"assetBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetTokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"configureBlastPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"configureBlastYieldsAndGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marginToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"mintMarginTokensBelowAARS","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"mintPairs","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"mintUsbAboveAARU","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"param","type":"bytes32"}],"name":"paramValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseUsbToMarginTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"contract IPriceFeed","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ptyPoolBuyLow","outputs":[{"internalType":"contract IPtyPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ptyPoolSellHigh","outputs":[{"internalType":"contract IPtyPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"marginTokenAmount","type":"uint256"}],"name":"redeemByMarginTokenAboveAARU","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"marginTokenAmount","type":"uint256"}],"name":"redeemByPairsWithExpectedMarginTokenAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usbAmount","type":"uint256"}],"name":"redeemByPairsWithExpectedUsbAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usbAmount","type":"uint256"}],"name":"redeemByUsbBelowAARS","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_ptyPoolBuyLow","type":"address"},{"internalType":"address","name":"_ptyPoolSellHigh","type":"address"}],"name":"setPtyPools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settings","outputs":[{"internalType":"contract IProtocolSettings","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenPot","outputs":[{"internalType":"contract TokenPot","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpauseMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpauseUsbToMarginTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_assetTokenPriceFeed_","type":"address"}],"name":"updatePriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usbAmount","type":"uint256"}],"name":"usbToMarginTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usbToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usbTotalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usbTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultMode","outputs":[{"internalType":"enum Constants.VaultMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultType","outputs":[{"internalType":"enum Constants.VaultType","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"wandProtocol","outputs":[{"internalType":"contract IWandProtocol","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
610140604052346200021f57620000236200001962000302565b93929092620003f5565b604051615f606200086a82396080518181816104d501528181610a2101528181611c1b0152818161398a015281816139bc01528181613d7401528181613f2c015281816142df015281816150330152615dc3015260a05181818161087b0152818161163e01528181611b2401528181611d0e01528181611fa30152818161345e015281816136a6015281816148a401528181614fee01528181615357015281816155d70152615c03015260c05181818161098901528181610ad70152818161149b0152818161198c015281816124870152818161261b015281816127c201528181612bbc01528181612e0a0152818161307a015281816132e101528181613ae901528181613e23015281816145d9015281816148fc0152615117015260e05181818161035801528181610aaa015281816114ca01528181613a630152818161457c0152818161492a015261514f015261010051818181610484015281816113e801528181611abe0152818161290b01528181612d23015281816130f9015281816133f70152818161360d0152818161470901528181614b37015281816151a40152818161541f0152615b2101526101205181818161061e015281816129f701528181612c3b01528181612eb6015281816137b601528181613b4f0152818161463501528181614a4b015281816156f101526158950152615f6090f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200025c57604052565b62000224565b90620002796200027160405190565b92836200023a565b565b6001600160a01b031690565b90565b6001600160a01b038116036200021f57565b9050519062000279826200028a565b919060a0838203126200021f57620002c481846200029c565b92620002d482602083016200029c565b9262000287620002e884604085016200029c565b93620002f881606086016200029c565b936080016200029c565b620003256200805c80380380620003198162000262565b928339810190620002ab565b9091929394565b6200027b62000287620002879290565b62000287906200032c565b156200034f57565b60405162461bcd60e51b815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606490fd5b62000287906200027b906001600160a01b031682565b620002879062000394565b6200028790620003aa565b906001600160a01b03905b9181191691161790565b90620003e962000287620003f192620003b5565b8254620003c0565b9055565b926200027994926200040c926200043895620005ab565b62000432620004206200027b60006200033c565b6001600160a01b038316141562000347565b620003b5565b600d620003d5565b906020828203126200021f5762000287916200029c565b6040513d6000823e3d90fd5b156200046b57565b60405162461bcd60e51b815260206004820152602e60248201527f5661756c742073686f756c64206f6e6c7920626520637265617465642062792060448201526d383937ba37b1b7b61037bbb732b960911b6064820152608490fd5b6001600160a01b0391821681529116602082015260400190565b9060ff90620003cb565b634e487b7160e01b600052602160045260246000fd5b600411156200050c57565b620004eb565b90620002798262000501565b620002879062000512565b906200053d62000287620003f1926200051e565b8254620004e1565b906200053d62000287620003f192151590565b9061ff009060081b620003cb565b906200057962000287620003f192151590565b825462000558565b9062ff00009060101b620003cb565b90620005a362000287620003f192151590565b825462000581565b91929092620005ba83620007f2565b600092620005f8620005cc856200033c565b6001600160a01b0381166001600160a01b03881614159081620007d3575b81620007b5575b5062000347565b6200062f32602062000616620004326080516001600160a01b031690565b63c1d6ba69906200062660405190565b94859260e01b90565b825260049082905afa80156200078c57620006636200067091620006779460009162000792575b506001600160a01b031690565b916001600160a01b031690565b1462000463565b604051906118928201906001600160401b038211838310176200025c5786620006ab918493611892620067ca8639620004c7565b039084f080156200078c5760c05260e05261012052620006f66020620006dd620004326080516001600160a01b031690565b632e20712190620006ed60405190565b93849260e01b90565b825260049082905afa9283156200078c576200027993620007259260009162000757575b5061010052620003b5565b60a0526200073581600862000529565b6200074281600162000545565b6200074f81600162000566565b600162000590565b6200077d915060203d811162000784575b6200077481836200023a565b81019062000440565b386200071a565b503d62000768565b62000457565b620007ae915060203d811162000784576200077481836200023a565b3862000656565b6001600160a01b031690506001600160a01b038516141538620005f1565b90506001600160a01b0381166001600160a01b038516141590620005ea565b62000801906200040c62000806565b608052565b6200027962000853565b6200028762000287620002879290565b62000287600162000810565b9060001990620003cb565b906200084b62000287620003f19262000810565b82546200082c565b620002796200086162000820565b60006200083756fe60806040526004361015610023575b361561001957600080fd5b610021610aa5565b005b60003560e01c8062b190d9146102a257806302b0dbd71461029d5780631083f761146102985780631a8bd2da146102935780631f6ac4a31461028e578063271d1df4146102895780632e2071211461028457806332ec84d21461027f5780633fef6dc11461027a5780634ac032be146102755780634e29a3331461027057806350eb741c1461026b57806351dddf4f146102665780635c975abb146102615780635cd480b41461025c5780636685ed87146102575780636a8f6ebb14610252578063741bef1a1461024d5780638d93fb21146102485780638da5cb5b146102435780639136bd471461023e5780639283556f1461023957806395877f78146102345780639e3141d31461022f578063af3345d11461022a578063b25f2f8514610225578063b85fc76614610220578063bd4f7c571461021b578063c66f245514610216578063cd85cdb514610211578063d189b8a11461020c578063d5ba680914610207578063dbbfedf214610202578063ddef1953146101fd578063e06174e4146101f8578063e0851a88146101f3578063e13a4fe9146101ee578063ea00162c146101e9578063eaee8425146101e45763f7a17d930361000e57610974565b610959565b610941565b610913565b6108d5565b610866565b61084e565b610833565b61080f565b6107f6565b6107bb565b6107a0565b61078d565b610772565b61075f565b610747565b61072f565b610717565b6106d2565b6106ba565b61069f565b610684565b610669565b610642565b610609565b6105f1565b6105c7565b610594565b610581565b610569565b61054a565b6104c0565b6104a8565b61046f565b61045c565b61040b565b610384565b610343565b6102f0565b6102bd565b60009103126102b257565b600080fd5b9052565b565b346102b2576102cd3660046102a7565b6102ec6102d86115ae565b6040519182918260ff909116815260200190565b0390f35b346102b2576103003660046102a7565b6102ec61030b6116b5565b6040519182918290815260200190565b6001600160a01b031690565b90565b6102b79061031b565b6020810192916102bb919061032a565b346102b2576103533660046102a7565b6102ec7f00000000000000000000000000000000000000000000000000000000000000005b60405191829182610333565b346102b2576103943660046102a7565b61039c61407c565b604051005b610327916008021c6001600160a01b031690565b9061032791546103a1565b610327600360016103b5565b6103279061031b906001600160a01b031682565b610327906103cc565b610327906103e0565b6102b7906103e9565b6020810192916102bb91906103f2565b346102b25761041b3660046102a7565b6102ec6104266103c0565b604051918291826103fb565b805b036102b257565b905035906102bb82610432565b906020828203126102b2576103279161043b565b61039c61046a366004610448565b613228565b346102b25761047f3660046102a7565b6102ec7f0000000000000000000000000000000000000000000000000000000000000000610378565b346102b2576104b83660046102a7565b61039c614120565b346102b2576104d03660046102a7565b6102ec7f0000000000000000000000000000000000000000000000000000000000000000610426565b634e487b7160e01b600052602160045260246000fd5b6002111561051957565b6104f9565b906102bb8261050f565b6103279061051e565b6102b790610528565b6020810192916102bb9190610531565b346102b25761055a3660046102a7565b604051806102ec60008261053a565b346102b2576105793660046102a7565b61039c613d50565b61039c61058f366004610448565b612371565b346102b2576105a43660046102a7565b61039c6142bd565b90151581529015156020820152901515604082015260600190565b346102b2576105d73660046102a7565b6102ec6105e2611384565b604051919391938493846105ac565b346102b25761039c610604366004610448565b613909565b346102b2576106193660046102a7565b6102ec7f0000000000000000000000000000000000000000000000000000000000000000610378565b346102b2576106523660046102a7565b6102ec61030b6116ad565b6103276000600d6103b5565b346102b2576106793660046102a7565b6102ec61042661065d565b346102b2576106943660046102a7565b6102ec61030b6116bf565b346102b2576106af3660046102a7565b6102ec610378610a17565b346102b25761039c6106cd366004610448565b613014565b346102b2576106e23660046102a7565b6102ec61030b611487565b6104348161031b565b905035906102bb826106ed565b906020828203126102b257610327916106f6565b346102b25761039c61072a366004610703565b615e40565b346102b25761039c610742366004610448565b612da4565b346102b2576107573660046102a7565b61039c61419c565b61039c61076d366004610448565b6125b5565b346102b2576107823660046102a7565b6102ec61030b6113db565b61039c61079b366004610448565b612716565b346102b2576107b03660046102a7565b6102ec61030b611491565b346102b2576107cb3660046102a7565b61039c614000565b91906040838203126102b257610327906107ed81856106f6565b936020016106f6565b346102b25761039c6108093660046107d3565b9061456d565b346102b25761039c610822366004610448565b612b56565b610327600060026103b5565b346102b2576108433660046102a7565b6102ec610426610827565b346102b25761085e3660046102a7565b61039c613eb8565b346102b2576108763660046102a7565b6102ec7f0000000000000000000000000000000000000000000000000000000000000000610426565b6004111561051957565b906102bb8261089f565b610327906108a9565b6102b7906108b3565b6020810192916102bb91906108bc565b346102b2576108e53660046102a7565b6102ec6108f0611699565b604051918291826108c5565b9081526040810192916102bb9160200152565b0152565b346102b2576109233660046102a7565b61092b61162b565b906102ec61093860405190565b928392836108fc565b346102b2576109513660046102a7565b61039c614241565b346102b2576102ec61030b61096f366004610448565b611637565b346102b2576109843660046102a7565b6102ec7f0000000000000000000000000000000000000000000000000000000000000000610426565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff8211176109e557604052565b6109ad565b905051906102bb826106ed565b906020828203126102b257610327916109ea565b6040513d6000823e3d90fd5b610a5d6020610a457f00000000000000000000000000000000000000000000000000000000000000006103e9565b63c1d6ba6990610a5460405190565b93849260e01b90565b825260049082905afa908115610aa057600091610a78575090565b610327915060203d8111610a99575b610a9181836109c3565b8101906109f7565b503d610a87565b610a0b565b6102bb7f0000000000000000000000000000000000000000000000000000000000000000610ad2306103e9565b610afb7f00000000000000000000000000000000000000000000000000000000000000006103e9565b9034925b929190610b2473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b61031b565b610b2d8561031b565b03610b3c576102bb9350610d86565b6102bb93610e9d565b0190565b15610b5057565b60405162461bcd60e51b815260206004820152600c60248201526b53616d65206164647265737360a01b6044820152606490fd5b0390fd5b61031b6103276103279290565b61032790610b88565b15610ba557565b60405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b15610be057565b60405162461bcd60e51b815260206004820152602a60248201527f4f6e65206f662074686520616464726573736573206d757374206265207468696044820152691cc818dbdb9d1c9858dd60b21b6064820152608490fd5b6103276103276103279290565b15610c4c57565b60405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b15610c9857565b60405162461bcd60e51b8152602060048201526013602482015272496e636f7272656374206d73672e76616c756560681b6044820152606490fd5b906102bb610ce060405190565b92836109c3565b67ffffffffffffffff81116109e557602090601f01601f19160190565b90610d16610d1183610ce7565b610cd3565b918252565b3d15610d3557610d2a3d610d04565b903d6000602084013e565b606090565b15610d4157565b60405162461bcd60e51b815260206004820152601c60248201527f4e617469766520746f6b656e207472616e73666572206661696c6564000000006044820152606490fd5b90610da3610d938261031b565b610d9c8461031b565b1415610b49565b610e17600092610dd6610db585610b95565b610dbe8161031b565b610dc78461031b565b14159081610e82575b50610b9e565b610ddf306103e9565b90610df2610dec8361031b565b9161031b565b148015610e64575b610e0390610bd9565b610b1f610e0f85610c38565b865b11610c45565b610e208261031b565b14610e495781906102bb93610e3460405190565b90818003925af1610e43610d1b565b50610d3a565b50506102bb90610e5e610e5a349290565b9190565b14610c91565b50610e03610e718261031b565b610e7a8561031b565b149050610dfa565b610e8c915061031b565b610e958561031b565b141538610dd0565b929190610eb5610eac8361031b565b610d9c8361031b565b610ef4610eee6000610ee9610ec982610b95565b610ed28161031b565b610edb8761031b565b14159081610f315750610b9e565b610c38565b84610e11565b610f00610b1f306103e9565b610f098261031b565b03610f205750610f1b6102bb936103e9565b610f85565b610f2c6102bb946103e9565b610ff7565b610f3b915061031b565b610e958761031b565b610f5d610f576103279263ffffffff1690565b60e01b90565b6001600160e01b03191690565b9160206102bb92949361090f6040820196600083019061032a565b610fc8600492610fb96102bb95610f9f63a9059cbb610f44565b92610fa960405190565b9687946020860190815201610f6a565b602082018103825203836109c3565b6110f0565b60409061090f6102bb9496959396610fed6060840198600085019061032a565b602083019061032a565b90610fc890610fb96102bb956004956110136323b872dd610f44565b9361101d60405190565b9788956020870190815201610fcd565b6110376020610d04565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602082015290565b61032761102d565b801515610434565b905051906102bb82611068565b906020828203126102b25761032791611070565b1561109857565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6102bb9161110061110f926103e9565b90611109611060565b9161114d565b805161111e610e5a6000610c38565b1490811561112d575b50611091565b6111479150602061113c825190565b81830101910161107d565b38611127565b610327929161115c6000610c38565b916111bd565b1561116957565b60405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608490fd5b906000610327949381926111cf606090565b506111e66111dc306103e9565b8390311015611162565b60208101905191855af16111f8610d1b565b9161124a565b1561120557565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b9192901561127c57508151611262610e5a6000610c38565b1461126b575090565b61127761032791611282565b6111fe565b826112fc565b3b611290610e5a6000610c38565b1190565b60005b8381106112a75750506000910152565b8181015183820152602001611297565b6112d86112e1602093610b45936112cc815190565b80835293849260200190565b95869101611294565b601f01601f191690565b6020808252610327929101906112b7565b90611305825190565b611312610e5a6000610c38565b11156113215750805190602001fd5b610b849061132e60405190565b62461bcd60e51b8152918291600483016112eb565b610327905b60ff1690565b6103279054611343565b6103279060081c611348565b6103279054611358565b6103279060101c611348565b610327905461136e565b61138e600161134e565b6113986001611364565b916113a3600161137a565b91929190565b6103279081565b61032790546113a9565b905051906102bb82610432565b906020828203126102b257610327916113ba565b611449602061141161140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b6103e9565b63db977f959061143b61142460076113b0565b9261142e60405190565b9586948593849360e01b90565b835260048301526024820190565b03915afa908115610aa05760009161145f575090565b610327915060203d8111611480575b61147881836109c3565b8101906113c7565b503d61146e565b61032760076113b0565b6114fe60206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b63e3d670d7906114f37f00000000000000000000000000000000000000000000000000000000000000009261142e60405190565b835260048301610333565b03915afa908115610aa0576103279161152a91600091611534575b5061152460046113b0565b9061157a565b61152460056113b0565b61154c915060203d81116114805761147881836109c3565b38611519565b634e487b7160e01b600052601160045260246000fd5b9190820391821161157557565b611552565b6103279190611568565b60ff8116610434565b905051906102bb82611584565b906020828203126102b2576103279161158d565b6115ed60206115bc306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e49526115e263f7dcd19361142e60405190565b8352600483016103fb565b03915af4908115610aa057600091611603575090565b610327915060203d8111611624575b61161c81836109c3565b81019061159a565b503d611612565b611633615e49565b9091565b60206116627f00000000000000000000000000000000000000000000000000000000000000006103e9565b635bec50be9061168e611674306103e9565b9261144961168160405190565b9687958694859460e01b90565b845260048401610f6a565b610327600861134e565b610327600a610c38565b6103276116a3565b610327600b6113b0565b610327600c6113b0565b6116da906116d56123d0565b61171c565b6102bb612402565b156116e957565b60405162461bcd60e51b815260206004820152600b60248201526a135a5b9d081c185d5cd95960aa1b6044820152606490fd5b6102bb90611739611734611730600161134e565b1590565b6116e2565b61178a565b1561174557565b60405162461bcd60e51b815260206004820152601c60248201527f56616c7565206d7573742062652067726561746572207468616e2030000000006044820152606490fd5b6102bb906117a261179b6000610c38565b821161173e565b61195a565b9060ff905b9181191691161790565b906117c66103276117cd926108b3565b82546117a7565b9055565b90600019906117ac565b906117eb6103276117cd92610c38565b82546117d1565b6103279061031b565b61032790546117f2565b1561180c57565b60405162461bcd60e51b8152602060048201526017602482015276141d1e541bdbdb14d95b1b121a59da081b9bdd081cd95d604a1b6044820152606490fd5b9160206102bb929493611866604082019660008301906103f2565b01906103f2565b6103279060181c61031b565b610327905461186d565b1561188a57565b60405162461bcd60e51b8152602060048201526015602482015274141d1e541bdbdb109d5e531bddc81b9bdd081cd95d605a1b6044820152606490fd5b6103276103276103279260ff1690565b604d811161157557600a0a90565b600211156102b257565b905051906102bb826118e5565b6080818303126102b25761191082826113ba565b9261032761192184602085016113ba565b9361192f81604086016113ba565b936060016118ef565b9160206102bb9294936119536040820196600083019061032a565b019061032a565b6001611966600861134e565b9160009261197c611976856108a9565b916108a9565b14612152575b6119b060206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa057839160009361212e575b506119cf906122cb565b6120f1575b5030906119e0826103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e495290630b7c480590611a0660405190565b90611a118360e01b90565b825260208280611a2488600483016103fb565b0381875af4918215610aa0576000926120d1575b50611a4c82611a47600a6113b0565b615bd5565b611a5f610327634141525360e01b611637565b821015611f4557611a96611a7282611879565b611a8f611a89611a8461140c8c610b95565b6117f2565b916117f2565b1415611883565b611ab572141d1e541bdbdb135a5b955cd8905b5bdd5b9d606a1b611637565b90611ae261140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b9163313ce5676020611af360405190565b8095611aff8460e01b90565b825260049082905afa908115610aa057611b5594600092611f23575b50602090611b487f00000000000000000000000000000000000000000000000000000000000000006103e9565b6040515b96879260e01b90565b825260049082905afa938415610aa057611b9f602093611b99611b94611bbd98611ba59661140c96600092611f00575b50611b8f906118c7565b611568565b6118d7565b90612420565b93611879565b63e766c83590611bb460405190565b94859260e01b90565b825260049082905afa918215610aa057600092611ed8575b50905b11611e5b575b50916020916115e2611bf3945b60405161142e565b03915af48015610aa057611c1191600091611e3d575b50600a6117db565b611c4e6020611c3f7f00000000000000000000000000000000000000000000000000000000000000006103e9565b6349d3d5e190610a5460405190565b825260049082905afa908115610aa057600091611e1f575b50611c73610b1f84610b95565b611c7c8261031b565b03611c87575b505050565b61140c611c93916103e9565b90611ca263dde798a4916103e9565b90611cb6611caf60405190565b9160e01b90565b815260808180611cc98560048301610333565b0381865afa8015610aa0576000918291611dec575b50611ceb610e5a86610c38565b119081611dd7575b50611cfd57505050565b611d419163954fa5ee936020611d327f00000000000000000000000000000000000000000000000000000000000000006103e9565b6361d027b390611b4c60405190565b825260049082905afa938415610aa057600094611db1575b50611d7b9060209495611d86611d6e60405190565b9788968795869460e01b90565b845260048401611938565b03925af18015610aa057611d975750565b611dae9060203d81116114805761147881836109c3565b50565b6020945090611dcf611d7b92863d8111610a9957610a9181836109c3565b945090611d59565b9050611de5610e5a85610c38565b1138611cf3565b9050611e0f915060803d8111611e18575b611e0781836109c3565b8101906118fc565b50919091611cde565b503d611dfd565b611e37915060203d8111610a9957610a9181836109c3565b38611c66565b611e55915060203d81116114805761147881836109c3565b38611c09565b929091611e66614fe3565b60405193611e748460e01b90565b855260208580611e8786600483016103fb565b0381855af4938415610aa057611eaf6020956115e293611bf398600092611eb9575b50615bd5565b9294505091611bde565b611ed1919250883d81116114805761147881836109c3565b9038611ea9565b611bd8919250611ef8610e5a9160203d81116114805761147881836109c3565b929150611bd5565b611b8f919250611f1c908a3d81116114805761147881836109c3565b9190611b85565b6020919250611f3e90823d81116116245761161c81836109c3565b9190611b1b565b50611f59610327634141525560e01b611637565b8111611f71575b50916020916115e2611bf394611beb565b611f97611f7e60026117fb565b611f90611a89611a8461140c8b610b95565b1415611805565b635915a1746020611fda7f000000000000000000000000000000000000000000000000000000000000000092611fe6611fcf60405190565b948593849360e01b90565b8352896004840161184b565b0381875af48015610aa05761200d916000916120b3575b506020611ba561140c60026117fb565b825260049082905afa918215610aa05760009261208b575b50905b1115611f605792909161203961534c565b604051936120478460e01b90565b85526020858061205a86600483016103fb565b0381855af4938415610aa0576120816020956115e293611bf398600092611eb95750615bd5565b9294505091611f60565b6120289192506120ab610e5a9160203d81116114805761147881836109c3565b929150612025565b6120cb915060203d81116114805761147881836109c3565b38611ffd565b6120ea91925060203d81116114805761147881836109c3565b9038611a38565b6120fb60096113b0565b612107610e5a85610c38565b0361211f575b506121194260096117db565b386119d4565b612128906155a8565b3861210d565b6119cf91935061214b9060203d81116114805761147881836109c3565b92906119c5565b61215d8260086117b6565b611982565b9190916101c0818403126102b25761227761217e6101c0610cd3565b93600061218b82856113ba565b90860152602061219d828286016113ba565b9086015260406121af828286016113ba565b9086015260606121c1828286016113ba565b9086015260806121d3828286016113ba565b9086015260a06121e5828286016113ba565b9086015260c06121f7828286016113ba565b9086015260e0612209828286016113ba565b9086015261010061221c828286016113ba565b9086015261012061222f828286016113ba565b90860152610140612242828286016113ba565b90860152610160612255828286016113ba565b90860152610180612268828286016113ba565b908601526101a08093016113ba565b90830152565b9091610200828403126102b2576103276122978484612162565b936122a6816101c086016113ba565b936101e0016113ba565b9160206102bb92949361090f604082019660008301906103f2565b806102006122d8306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e631ff858b661231961230160405190565b9788958694859460e01b90565b8452600484016122b0565b03915af48015610aa0576102bb92600092839283929061233a575b50614577565b9150925061236091506102003d811161236a575b61235881836109c3565b81019061227d565b9238929192612334565b503d61234e565b6102bb906116c9565b6103276002610c38565b1561238b57565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6102bb6123dd60006113b0565b6123f16123e861237a565b91821415612384565b60006117db565b6103276001610c38565b6102bb6123f16123f8565b8181029291811591840414171561157557565b610327919061240d565b6116da906124366123d0565b6102bb9061244a611734611730600161134e565b6102bb9061245b61179b6000610c38565b6001612467600861134e565b91600092612477611976856108a9565b146124ee575b6124ab60206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa05783916000936124ca575b506119cf90612523565b6119cf9193506124e79060203d81116114805761147881836109c3565b92906124c0565b6124f98260086117b6565b61247d565b91906101e0838203126102b257610327906125198185612162565b936101c0016113ba565b806101e0612530306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e6394eb4aca61255961230160405190565b03915af4918215610aa0576102bb926000918291612583575b5061257d6000610c38565b92614577565b90506125a791506101e03d81116125ae575b61259f81836109c3565b8101906124fe565b9038612572565b503d612595565b6102bb9061242a565b6116da906125ca6123d0565b6102bb906125de611734611730600161134e565b6102bb906125ef61179b6000610c38565b60016125fb600861134e565b9160009261260b611976856108a9565b14612682575b61263f60206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa057839160009361265e575b506119cf90612692565b6119cf91935061267b9060203d81116114805761147881836109c3565b9290612654565b61268d8260086117b6565b612611565b806101e061269f306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e6344ff2f636126c861168160405190565b03915af4918215610aa0576102bb9260009283916126f2575b506126ec6000610c38565b91614577565b905061270e9192506101e03d81116125ae5761259f81836109c3565b9190386126e1565b6102bb906125be565b6116da9061272b6123d0565b61276c565b1561273757565b60405162461bcd60e51b815260206004820152600d60248201526c14995919595b481c185d5cd959609a1b6044820152606490fd5b6102bb906127856127806117306001611364565b612730565b6102bb9061279661179b6000610c38565b60016127a2600861134e565b916000926127b2611976856108a9565b14612829575b6127e660206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa0578391600093612805575b506119cf90612903565b6119cf9193506128229060203d81116114805761147881836109c3565b92906127fb565b6128348260086117b6565b6127b8565b1561284057565b60405162461bcd60e51b81526020600482015260166024820152754e6f7420656e6f756768205553422062616c616e636560501b6044820152606490fd5b1561288557565b60405162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f756768206d617267696e20746f6b656e2062616c616e6365006044820152606490fd5b909594926102bb946128fc61090f926128f56080966128ee60a088019c6000890152565b6020870152565b6040850152565b6060830152565b61292f61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b6370a08231913391602061294260405190565b809261294e8760e01b90565b8252818061295f8860048301610333565b03915afa908115610aa0576129869161297d9160009161145f575090565b825b1115612839565b61298f306103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e495291634b10cd51946129bf6129b860405190565b9660e01b90565b8652602086806129d38686600484016122b0565b0381875af4958615610aa057600096612b2e575b50906020612a2392612a1b61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b604051611bb4565b82528180612a348a60048301610333565b03915afa938415610aa057612a5f612a5688966101e09560009161145f575090565b865b111561287e565b61230e63df4ef462612a80612a7360405190565b998a958694859460e01b90565b03915af4938415610aa057600080919095612b00575b50612aa6838387612afb94614872565b94612abd6040612ab7602084015190565b92015190565b90612ae87f5975ae134530356ba04a9728ddefa4c6676e1433c72bf75970c7775d4771a762966103e9565b96612af260405190565b958695866128ca565b0390a2565b829550612afb915083612b24612aa6926101e03d81116125ae5761259f81836109c3565b9350965050612a96565b612a2392919650612b4d602091823d81116114805761147881836109c3565b969192506129e7565b6102bb9061271f565b6116da90612b6b6123d0565b6102bb90612b7f6127806117306001611364565b6102bb90612b9061179b6000610c38565b6001612b9c600861134e565b91600092612bac611976856108a9565b14612c23575b612be060206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa0578391600093612bff575b506119cf90612c33565b6119cf919350612c1c9060203d81116114805761147881836109c3565b9290612bf5565b612c2e8260086117b6565b612bb2565b612c5f61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b6370a0823133916020612c7160405190565b8092612c7d8560e01b90565b82528180612c8e8860048301610333565b03915afa908115610aa057612cb291612cac9160009161145f575090565b84612a58565b612cbb306103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e49529163532d6bcc90612ceb612ce460405190565b9260e01b90565b825260208280612cff8985600484016122b0565b0381875af4918215610aa057600092612d80575b506020612d479293612a1b61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b82528180612d588a60048301610333565b03915afa938415610aa057612a5f612d7a88966101e09560009161145f575090565b8561297f565b612d479250612d9d602091823d81116114805761147881836109c3565b9250612d13565b6102bb90612b5f565b6116da90612db96123d0565b6102bb90612dcd6127806117306001611364565b6102bb90612dde61179b6000610c38565b6001612dea600861134e565b91600092612dfa611976856108a9565b14612e71575b612e2e60206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa0578391600093612e4d575b506119cf90612eae565b6119cf919350612e6a9060203d81116114805761147881836109c3565b9290612e43565b612e7c8260086117b6565b612e00565b61090f6102bb94612ea7606094989795612ea0608086019a6000870152565b6020850152565b6040830152565b612eda61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b612ef060206370a08231335b93610a5460405190565b82528180612f018760048301610333565b03915afa908115610aa057612f2591612f1f9160009161145f575090565b83612a58565b816101e0612f32306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e631823dec0612f68612f5b60405190565b9889958694859460e01b90565b03915af4928315610aa057600080919094612fec575b5081612f959185612f8f6000610c38565b91614872565b90612afb612faf6040612fa9602088015190565b96015190565b612fd97ff364e0a28f9a8aafaf506d9afb875c3c563242a31e7aa6a29049be7d514822b5956103e9565b95612fe360405190565b94859485612e81565b829450612f95915061300c906101e03d81116125ae5761259f81836109c3565b915093612f7e565b6102bb90612dad565b6116da906130296123d0565b6102bb9061303d6127806117306001611364565b6102bb9061304e61179b6000610c38565b600161305a600861134e565b9160009261306a611976856108a9565b146130e1575b61309e60206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa05783916000936130bd575b506119cf906130f1565b6119cf9193506130da9060203d81116114805761147881836109c3565b92906130b3565b6130ec8260086117b6565b613070565b61311d61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b61312d60206370a0823133612ee6565b8252818061313e8760048301610333565b03915afa908115610aa0576131629161315c9160009161145f575090565b8361297f565b816101e061316f306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e63b5321dd6613198612f5b60405190565b03915af4928315610aa057600080919094613203575b506131c59082856131bf6000610c38565b92614872565b90612afb6131d96040612fa9602088015190565b612fd97f63c111c8e2f0628c2100af0de149ab39c61f77b487b7ce9b884badc8ad55ad68956103e9565b6131c5945061322191506101e03d81116125ae5761259f81836109c3565b90936131ae565b6102bb9061301d565b6116da9061323d6123d0565b61328e565b1561324957565b60405162461bcd60e51b815260206004820152601b60248201527f55534220746f204d617267696e20546f6b656e732070617573656400000000006044820152606490fd5b6102bb906132a76132a2611730600161137a565b613242565b6102bb906132b861179b6000610c38565b6000906132c5600861134e565b6132d1611976846108a9565b1461359f575b61330560206114bf7f00000000000000000000000000000000000000000000000000000000000000006103e9565b03915afa918215610aa057839160009361357b575b5061332490613605565b61353e575b5030613334816103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e4952630b7c480561335760405190565b6133618260e01b90565b81526020818061337487600483016103fb565b0381865af4908115610aa057600091613520575b5061339781611a47600a6113b0565b6133aa610327634141525360e01b611637565b81101561350d576133d06133be6001611879565b611a8f611a89611a8461140c8b610b95565b6133ef72141d1e541bdbdb135a5b955cd8905b5bdd5b9d606a1b611637565b61341b61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b9063313ce56790602061342d60405190565b80946134398560e01b90565b825260049082905afa918215610aa05761348f936000936134eb575b506020906134827f00000000000000000000000000000000000000000000000000000000000000006103e9565b6040515b95869260e01b90565b825260049082905afa918215610aa057611b946134bf93611b9992611bbd966000926134ce5750611b8f906118c7565b6020611ba561140c6001611879565b611b8f919250611f1c9060203d81116114805761147881836109c3565b602091935061350690823d81116116245761161c81836109c3565b9290613455565b611f59610327634141525560e01b611637565b613538915060203d81116114805761147881836109c3565b38613388565b61354860096113b0565b613554610e5a84610c38565b0361356c575b506135664260096117db565b38613329565b613575906155a8565b3861355a565b6133249193506135989060203d81116114805761147881836109c3565b929061331a565b6135ab600160086117b6565b6132d7565b60409061090f6102bb94969593966135d0606084019860008501906103f2565b60208301906103f2565b6102b790610c38565b61090f6102bb94612ea7606094989795612ea0608086019a60008701906135da565b61363161140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b906370a08231903391613646611caf60405190565b8152602081806136598660048301610333565b0381875afa908115610aa0576136789161297d9160009161145f575090565b613681306103e9565b906101e073b5ecfd108619fb8e7c65658b9419f81ea62e495292633671ef3e936136e07f0000000000000000000000000000000000000000000000000000000000000000956136eb866136d360405190565b9889968795869560e01b90565b8552600485016135b0565b03915af48015610aa0576137189460009384926138e2575b50604051956020918791632770a7eb60e21b90565b82528160008161372c888b60048401610f6a565b03925af1938415610aa0576137ab956000956138c2575b5061376161375a8661375560076113b0565b61157a565b60076117db565b60208201916040613770845190565b91019561377b875190565b91600080516020615f0b83398151915291613795856103e9565b998a946137a160405190565b9384938a85612e81565b0390a26137da61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b906340c10f1990823b156102b257859261168e600080946137fd611d6e60405190565b03925af18015610aa057612afb926138719261386c9261389c575b5087600087613825845190565b916138656138318c5190565b7fe79d2400774c9ceba50645590d91414af42f277c27641bd9cba2f5b92db83ad59461385c60405190565b948594856135e3565b0390a25190565b945190565b7f52d7aa340d530e823911f14778f0f82b34460971ef6af5c237d103ebeae637bc94612fe360405190565b6138b59060005b6138ad81836109c3565b8101906102a7565b38613818565b503d6138a3565b6138db91955060203d81116114805761147881836109c3565b9338613743565b602094506139009192506101e03d81116125ae5761259f81836109c3565b93919091613703565b6102bb90613231565b61391a6123d0565b6116da61397a565b1561392957565b60405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652070726f746f60448201526218dbdb60ea1b6064820152608490fd5b6139b4335b6139ae610dec610b1f7f00000000000000000000000000000000000000000000000000000000000000006103e9565b14613922565b6102bb6139e07f00000000000000000000000000000000000000000000000000000000000000006103e9565b6349d3d5e16139ee60405190565b916139f98260e01b90565b8352602083600481845afa928315610aa057600093613d30575b50600092613a26610dec610b1f86610b95565b03613a3057505050565b613a4091602091610a5460405190565b825260049082905afa8015610aa057613a6191600091613d12575b506103e9565b7f0000000000000000000000000000000000000000000000000000000000000000613aa2610dec73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b14613cad575b613ab1906103e9565b634e606c4790803b156102b257613acd918391610a5460405190565b8252600490829084905af18015610aa057613c91575b50613b0d7f00000000000000000000000000000000000000000000000000000000000000006103e9565b634e29a33390803b156102b25782613b2460405190565b8092613b308560e01b90565b8252600490829084905af18015610aa057613c75575b50613b7361140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b803b156102b25782613b8460405190565b8092613b908560e01b90565b8252600490829084905af18015610aa057613c59575b50613bb461140c6001611879565b803b156102b25782613bc560405190565b8092613bd18560e01b90565b8252600490829084905af18015610aa057613c3d575b50613bf561140c60026117fb565b803b156102b257613c0b918391610a5460405190565b8252818381600481015b03925af18015610aa057613c27575050565b816102bb92903d106138bb576138ad81836109c3565b613c5390833d85116138bb576138ad81836109c3565b38613be7565b613c6f90833d85116138bb576138ad81836109c3565b38613ba6565b613c8b90833d85116138bb576138ad81836109c3565b38613b46565b613ca790823d84116138bb576138ad81836109c3565b38613ae3565b613cb6816103e9565b90637114177a91803b156102b257613cd3928491611bb460405190565b8252600490829084905af1918215610aa057613ab192613cf6575b509050613aa8565b613d0c90843d86116138bb576138ad81836109c3565b38613cee565b613d2a915060203d8111610a9957610a9181836109c3565b38613a5b565b613d4991935060203d8111610a9957610a9181836109c3565b9138613a13565b6102bb613912565b613d606123d0565b6116da613d6c3361397f565b6102bb613d987f00000000000000000000000000000000000000000000000000000000000000006103e9565b63095f363c90613daa612ce460405190565b8252602082600481845afa908115610aa057613dda92600092613e96575b506040516020916340ae3e1491611bb4565b825260049082905afa918215610aa057600092613e76575b50600091613dff83610b95565b91613e0c610dec8461031b565b14159182613e5e575b5050613e1e5750565b613e477f00000000000000000000000000000000000000000000000000000000000000006103e9565b63ddef195390803b156102b25782613b8460405190565b613e6d919250610dec9061031b565b14153880613e15565b613e8f91925060203d8111610a9957610a9181836109c3565b9038613df2565b6020919250613eb190823d8111610a9957610a9181836109c3565b9190613dc8565b6102bb613d58565b613ec86123d0565b6116da613f20565b15613ed757565b60405162461bcd60e51b815280610b84600482016020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b613f5f335b6020613f507f00000000000000000000000000000000000000000000000000000000000000006103e9565b63c1d6ba6990611bb460405190565b825260049082905afa8015610aa057610dec613f8791613f8d94600091613f95575b5061031b565b14613ed0565b6102bb613fc3565b613fad915060203d8111610a9957610a9181836109c3565b38613f81565b906117c66103276117cd92151590565b613fce600180613fb3565b7fd7d248ba47bac931be252275aff92303dd610ca36c92c05dbac783fde1662a0e613ff860405190565b80805b0390a1565b6102bb613ec0565b6140106123d0565b6116da61401c33613f25565b825260049082905afa8015610aa057610dec613f879161404394600091613f95575061031b565b6102bb61405260006001613fb3565b7fd76d4045ba8d223490b9c6a5657cfdaa2316ac28a5a65274870bfe66a33ea0c4613ff860405190565b6102bb614008565b61408c6123d0565b6116da61409833613f25565b825260049082905afa8015610aa057610dec613f87916140bf94600091613f95575061031b565b6102bb6140eb565b9061ff009060081b6117ac565b906140e46103276117cd92151590565b82546140c7565b6140f66001806140d4565b7f60b78ed2d882d2d2387ad2b7119495f7c99dd9a9c191d3d02c35982a0750bcc6613ff860405190565b6102bb614084565b6141306123d0565b6116da61413c33613f25565b825260049082905afa8015610aa057610dec613f879161416394600091613f95575061031b565b6102bb614172600060016140d4565b7f687bf6e69dbabcc95e11041b4816a83f36dcf6ef647f6acf63e7469d28f5ea73613ff860405190565b6102bb614128565b6141ac6123d0565b6116da6141b833613f25565b825260049082905afa8015610aa057610dec613f87916141df94600091613f95575061031b565b6102bb61420c565b9062ff00009060101b6117ac565b906142056103276117cd92151590565b82546141e7565b6142176001806141f5565b7fff1961bacbc4ad36bbb3affa41b9ca1167f9f3e8b2fa05b3a3d87546424c72f8613ff860405190565b6102bb6141a4565b6142516123d0565b6116da61425d33613f25565b825260049082905afa8015610aa057610dec613f879161428494600091613f95575061031b565b6102bb614293600060016141f5565b7fe2a0c3d430f5c761f9440a5c7c1a9c27524338eb75537ec0ffa23744248e89de613ff860405190565b6102bb614249565b906116da916142d26123d0565b9033916143036020610a457f00000000000000000000000000000000000000000000000000000000000000006103e9565b825260049082905afa938415610aa057613f87610dec6102bb9661432e94600091613f95575061031b565b614405565b1561433a57565b60405162461bcd60e51b815260206004820152601560248201527416995c9bc81859191c995cdcc819195d1958dd1959605a1b6044820152606490fd5b1561437e57565b60405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081d985d5b1d609a1b6044820152606490fd5b906301000000600160b81b039060181b6117ac565b906143d86103276117cd926103e9565b82546143b3565b906001600160a01b03906117ac565b906143fe6103276117cd926103e9565b82546143df565b6144379061140c6144166000610b95565b61441f8161031b565b6144288461031b565b14159081614552575b50614333565b614440816103e9565b63fbfa77cf90602061445160405190565b809261445d8560e01b90565b825260049082905afa908115610aa057600091614534575b5061447f306103e9565b9061448c610dec8361031b565b1491826144b8575b50509161140c6144b1926144aa6102bb95614377565b60016143c8565b60026143ee565b849250602090611b4861140c6144cd976103e9565b825260049082905afa928315610aa0576144aa6144b19461140c936102bb9760009261450c575b50610dec6145019161031b565b149395505092614494565b61450191925061452c610dec9160203d8111610a9957610a9181836109c3565b9291506144f4565b61454c915060203d8111610a9957610a9181836109c3565b38614475565b61455c915061031b565b6145658561031b565b141538614431565b906102bb916142c5565b9092907f0000000000000000000000000000000000000000000000000000000000000000816145b973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b6145c28361031b565b036147f357614603916145d4306103e9565b6145fd7f00000000000000000000000000000000000000000000000000000000000000006103e9565b91610aff565b60009261460f84610c38565b8111614701575b5061462083610c38565b821161462d575b50505050565b61465961140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b926340c10f193394803b156102b257614677918391610a5460405190565b825281838161468a8a8c60048401610f6a565b03925af18015610aa0576146e4575b50506146d86146ae6040612fa9602088015190565b612fd97fe79d2400774c9ceba50645590d91414af42f277c27641bd9cba2f5b92db83ad5956103e9565b0390a238808080614627565b816146fa92903d106138bb576138ad81836109c3565b3880614699565b61472d61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b61473d60206340c10f1933612ee6565b8252818981614750898960048401610f6a565b03925af1908115610aa0576000916147d5575b5061477a61375a8261477560076113b0565b61480f565b6020870151926147cc61478e60408a015190565b6147b87f63c3f185975ecdfdf59dfa778ff2ddbfe5a3f930ccc104a7b4f6d9f882fde93c956103e9565b956147c260405190565b94859489866128ca565b0390a238614616565b6147ed915060203d81116114805761147881836109c3565b38614763565b6147fd91336145d4565b614603565b9190820180921161157557565b6103279190614802565b6080818303126102b25761482d82826113ba565b9261032761483e84602085016113ba565b9361484c81604086016113ba565b936060016113ba565b9081526060810193926102bb92909160409161090f906020830152565b9192916148dc91906080614885306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e49526136e063d4ff72d87f00000000000000000000000000000000000000000000000000000000000000009788966148cf60405190565b998a968795869560e01b90565b03915af4948515610aa05760008080809196909298614f73575b506149207f00000000000000000000000000000000000000000000000000000000000000006103e9565b63d9caed129133977f000000000000000000000000000000000000000000000000000000000000000094833b156102b2578b6000878c61497c61496260405190565b94859384936149718d60e01b90565b855260048501610fcd565b038183895af18015610aa057614f5d575b5060009761499a89610c38565b8311614ea7575b506149bc91506149b59061477560046113b0565b60046117db565b6149c660046113b0565b6149d2610e5a88610c38565b1180614e4b575b614d53575b6149ef6149f69161477560056113b0565b60056117db565b614a0060056113b0565b614a0c610e5a87610c38565b1180614ce8575b614bf9575b505050614a2482610c38565b8111614b29575b50614a3581610c38565b8411614a43575b5050505090565b614a6f61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b639dc29fac90803b156102b257614a8b918391610a5460405190565b8252818381614a9e8b8b60048401610f6a565b03925af18015610aa057614b0c575b5050614abf6040612ab7602084015190565b92614b00614aed7f3b931001c0728420650d0922e385dcd2dbcf634aee98dc541642fe27358da458946103e9565b94614af760405190565b93849384614855565b0390a238808080614a3c565b81614b2292903d106138bb576138ad81836109c3565b3880614aad565b614b6a906020614b5b61140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b639dc29fac90611bb460405190565b8252818681614b7d878c60048401610f6a565b03925af1918215610aa057600092614bd9575b50614ba261375a8361375560076113b0565b602084015191614bb3604086015190565b91614bd0600080516020615f0b83398151915293612fd9896103e9565b0390a238614a2b565b614bf291925060203d81116114805761147881836109c3565b9038614b90565b614c0661140c60026117fb565b90614c1160056113b0565b92813b156102b2578661497191614c398296614c2c60405190565b9889978896879560e01b90565b03925af18015610aa057614ccc575b50614c5661140c60026117fb565b631b2a1914614c6560056113b0565b823b156102b257614c8c9261143b868094614c7f60405190565b9687958694859360e01b90565b03925af18015610aa057614cb0575b50614ca86149ef83610c38565b388080614a18565b614cc690833d85116138bb576138ad81836109c3565b38614c9b565b614ce290833d85116138bb576138ad81836109c3565b38614c48565b50614d0a6020614cfb61140c60026117fb565b6370c6a17e90610a5460405190565b825260049082905afa908115610aa057600091614d35575b50614d2f610e5a87610c38565b11614a13565b614d4d915060203d81116114805761147881836109c3565b38614d22565b614d6061140c6001611879565b614d6a60046113b0565b90833b156102b257858891614d90614d8160405190565b94859384936149718b60e01b90565b038183875af18015610aa057614e2f575b50614daf61140c6001611879565b906339db85c5614dbf60046113b0565b833b156102b257614de69361143b8a8094614dd960405190565b9788958694859360e01b90565b03925af1908115610aa0576149f6926149ef92614e13575b50614e0b6149b589610c38565b9150506149de565b614e2990893d8b116138bb576138ad81836109c3565b38614dfe565b614e4590873d89116138bb576138ad81836109c3565b38614da1565b50614e5e6020614cfb61140c6001611879565b825260049082905afa908115610aa057600091614e89575b50614e83610e5a88610c38565b116149d9565b614ea1915060203d81116114805761147881836109c3565b38614e76565b6020614eb5614ec4926103e9565b6361d027b390610a5460405190565b825260049082905afa908115610aa057600091614f3f575b50843b156102b257868991614f02614ef360405190565b95869384936149718c60e01b90565b038183885af1908115610aa0576149bc926149b592614f23575b50906149a1565b614f39908a3d8c116138bb576138ad81836109c3565b38614f1c565b614f57915060203d8111610a9957610a9181836109c3565b38614edc565b614f6d9060006138ad81836109c3565b3861498d565b9295505050614f9a91955060803d8111614fa6575b614f9281836109c3565b810190614819565b389793979592956148f6565b503d614f88565b6119536102bb94614fd9606094989795614fcf608086019a60008701906103f2565b60208501906103f2565b604083019061032a565b614fec306103e9565b7f0000000000000000000000000000000000000000000000000000000000000000906150669073b5ecfd108619fb8e7c65658b9419f81ea62e495263fae31b3060206150577f00000000000000000000000000000000000000000000000000000000000000006103e9565b632e20712190611b4c60405190565b825260049082905afa908115610aa0576150b96150ae926101e0966000916152df575b5061509761140c6001611879565b906150a160405190565b9889978896879660e01b90565b865260048601614fad565b03915af4908115610aa0576000809190926152be575b506000916150dc83610c38565b8214611c8257604081019061511160206151006150fa611b94865190565b86612420565b92019161510b835190565b90615322565b9261513b7f00000000000000000000000000000000000000000000000000000000000000006103e9565b63d9caed1261514d61140c6001611879565b7f000000000000000000000000000000000000000000000000000000000000000092803b156102b2576149718980946151898b614c2c60405190565b03925af18015610aa0576152a2575b508060206151c861140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b639dc29fac9061168e896151df61140c6001611879565b936151f96151ec60405190565b9889968795869460e01b90565b03925af1918215610aa057600092615282575b5061521e61375a8361375560076113b0565b61525161523961523461523461140c6001611879565b955190565b612fd9600080516020615f0b833981519152956103e9565b0390a261526161140c6001611879565b906392a1594290823b156102b257613c159261143b858094614c7f60405190565b61529b91925060203d81116114805761147881836109c3565b903861520c565b6152b890863d88116138bb576138ad81836109c3565b38615198565b90506152d991506101e03d81116125ae5761259f81836109c3565b386150cf565b6152f7915060203d8111610a9957610a9181836109c3565b38615089565b634e487b7160e01b600052601260045260246000fd5b811561531d570490565b6152fd565b6103279190615313565b6040906119536102bb94969593966135d0606084019860008501906103f2565b615355306103e9565b7f0000000000000000000000000000000000000000000000000000000000000000906101e09073b5ecfd108619fb8e7c65658b9419f81ea62e49526153b8632582105d6153c36153a861140c60026117fb565b6040519788968795869560e01b90565b85526004850161532c565b03915af48015610aa0576000918291615503575b506000916153e483610c38565b8114611c8257602082019161541360406154056153ff865190565b85612420565b92019161510b611b94845190565b9283602061544361140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b6340c10f199061168e8961545a61140c60026117fb565b9361547461546760405190565b9b8c968795869460e01b90565b03925af1948515610aa0576000956154e3575b50849061549b61375a8361477560076113b0565b6154a861478e6152343381565b0390a26154b861140c60026117fb565b90634445f73091803b156102b2576154d8858094613c15611d6e60405190565b8452600484016108fc565b6154fc91955060203d81116114805761147881836109c3565b9338615487565b905061551e91506101e03d81116125ae5761259f81836109c3565b90386153d7565b91906040838203126102b2576103279061553f81856113ba565b936020016113ba565b61090f6102bb94612ea7606094989795614fcf608086019a60008701906103f2565b6040810192916102bb9160209161558290829061032a565b017f507479506f6f6c4275794c6f774d617267696e5969656c6473526174650000009052565b615625903060406155b8826103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261561a636937938b7f000000000000000000000000000000000000000000000000000000000000000097889761560360096113b0565b9061560d60405190565b998a978896879660e01b90565b865260048601615548565b03915af4928315610aa057600080939094615ba0575b50600061564781610c38565b85119283615b19575b61565982610c38565b85119283615a13575b5061566d60036113b0565b615679610e5a84610c38565b11806159b7575b615893575b61568f60066113b0565b61569b610e5a84610c38565b1180615837575b6156ef575b505081156156e7575b506156b9575050565b7f55de42fd7838b64e6e196dc82f1aa2e87ad5c13ea8fc85ab51095bad26b754ab91613ffb61093860405190565b9050386156b0565b7f000000000000000000000000000000000000000000000000000000000000000061571c61140c826103e9565b9161572b6340c10f19916103e9565b9061573660066113b0565b843b156102b2576157699461575d87809461575060405190565b9889958694859360e01b90565b83528860048401610f6a565b03925af1928315610aa05761579c9361581b575b5061578b61140c60026117fb565b9061579660066113b0565b92610aff565b6157a961140c60026117fb565b906339db85c56157b960066113b0565b833b156102b2576157d39361143b848094614dd960405190565b03925af1908115610aa0576157f8926157f1926157ff575b50610c38565b60066117db565b38806156a7565b61581590823d84116138bb576138ad81836109c3565b386157eb565b61583190853d87116138bb576138ad81836109c3565b3861577d565b5061584a6020614cfb61140c60026117fb565b825260049082905afa908115610aa057600091615875575b5061586f610e5a84610c38565b116156a2565b61588d915060203d81116114805761147881836109c3565b38615862565b7f00000000000000000000000000000000000000000000000000000000000000006158c061140c826103e9565b906340c10f196158cf846103e9565b906158da60036113b0565b843b156102b2576158f49461575d88809461575060405190565b03925af1928315610aa0576159219361599b575b5061591661140c6001611879565b9061579660036113b0565b61592e61140c6001611879565b631b2a191461593d60036113b0565b823b156102b2576159579261143b868094614c7f60405190565b03925af18015610aa05761597f575b5061597a61597383610c38565b60036117db565b615685565b61599590833d85116138bb576138ad81836109c3565b38615966565b6159b190863d88116138bb576138ad81836109c3565b38615908565b506159ca6020614cfb61140c6001611879565b825260049082905afa908115610aa0576000916159f5575b506159ef610e5a84610c38565b11615680565b615a0d915060203d81116114805761147881836109c3565b386159e2565b615a1c906103e9565b635bec50be906020615a48615a30856103e9565b93615a53615a3d60405190565b958693849360e01b90565b83526004830161556a565b0381845afa8015610aa057615a77602091615a8794600091615afc575b5089612420565b9163313ce56790611bb460405190565b825260049082905afa918215610aa057615ab76157f19261510b615ad895615ace94600091615ade575b506118d7565b615ac86159738261477560036113b0565b8861157a565b61477560066113b0565b38615662565b615af6915060203d81116114805761147881836109c3565b38615ab1565b615b139150833d81116114805761147881836109c3565b38615a70565b615b4561140c7f00000000000000000000000000000000000000000000000000000000000000006103e9565b63bc4f2d6d90803b156102b257615b61918491610a5460405190565b8252600482018a9052602490829084905af18015610aa057615b84575b50615650565b615b9a90833d85116138bb576138ad81836109c3565b38615b7e565b909350615bc591925060403d8111615bce575b615bbd81836109c3565b810190615525565b9190923861563b565b503d615bb3565b90615bdf306103e9565b91608073b5ecfd108619fb8e7c65658b9419f81ea62e49529363b18da4fd94615c2f7f000000000000000000000000000000000000000000000000000000000000000096615c3a612f5b60405190565b84526004840161184b565b03915af48015610aa057600093849182918291615d85575b505b841115615cd3575050615c69600360086117b6565b615c7d615c766000610c38565b600b6117db565b8281101580615cca575b15615c9a575050506102bb42600c6117db565b82119182615cbf575b5050615cab57565b6102bb615cb86000610c38565b600c6117db565b915010153880615ca3565b50828210615c87565b80841015615d0257615cec9150610327600260086117b6565b8110615c7d57615cfd42600b6117db565b615c7d565b508082109081615d7a575b8115615d5d575b5015615c7d57615d24600861134e565b600190615d33611976836108a9565b03615d3f575b50615c7d565b615d4a9060086117b6565b615d57615c766000610c38565b38615d39565b808311915081615d6f575b5038615d14565b905082111538615d68565b808410159150615d0d565b915050615c549450615da5915060803d8111614fa657614f9281836109c3565b95615c52565b6116da90615db76123d0565b3390615de76020610a457f00000000000000000000000000000000000000000000000000000000000000006103e9565b825260049082905afa928315610aa057613f87610dec6102bb95615e1294600091613f95575061031b565b615e396102bb9161140c615e29610b1f6000610b95565b615e328361031b565b1415614333565b600d6143ee565b6102bb90615dab565b615e6b906020615e5c61140c600d6117fb565b63a3e6ba9490611bb460405190565b825260049082905afa8015610aa057615ea592600091615eec575b506020615e9661140c600d6117fb565b63313ce5679061348660405190565b825260049082905afa928315610aa057600093615ec8575b5061032790926118c7565b610327919350615ee59060203d81116116245761161c81836109c3565b9290615ebd565b615f04915060203d81116114805761147881836109c3565b38615e8656fe8331e6d9453e2cdb4da24bdc7337453d7324ddf71d1cb7949834baea5de4ba43a2646970667358221220af4f5be994e67a93537866ca0975c5ec1087f2d9e07fa67979a0670801ad170f64736f6c6343000812003360e0604052346200006f576200001f6200001862000123565b90620001de565b6040516115eb620002a782396080518181816102530152610bba015260a051818181610188015261047a015260c051818181610109015281816104ee0152818161079d0152610ad301526115eb90f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b03821117620000ac57604052565b62000074565b90620000c9620000c160405190565b92836200008a565b565b6001600160a01b031690565b90565b6001600160a01b038116036200006f57565b90505190620000c982620000da565b91906040838203126200006f57620000d790620001198185620000ec565b93602001620000ec565b6200014662001892803803806200013a81620000b2565b928339810190620000fb565b9091565b620000cb620000d7620000d79290565b620000d7906200014a565b156200016d57565b60405162461bcd60e51b815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606490fd5b620000d790620000cb906001600160a01b031682565b620000d790620001b2565b620000d790620001c8565b620002306200023992620001f162000290565b620002266200020160006200015a565b6001600160a01b0381166001600160a01b038616141590816200023e575b5062000165565b3360a052620001d3565b608052620001d3565b60c052565b6001600160a01b031690506001600160a01b0383161415386200021f565b620000d7620000d7620000d79290565b620000d760016200025c565b90620000d7620000d76200028c926200025c565b9055565b620000c96200029e6200026c565b60006200027856fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80633fef6dc11461008b5780634e29a333146100865780638da5cb5b14610081578063d9caed121461007c578063ddef195314610077578063e06174e4146100725763e3d670d70361000e5761028b565b61023e565b610226565b61020d565b61016f565b610139565b6100f4565b600091031261009b57565b600080fd5b6100b4906100b7906001600160a01b031682565b90565b6001600160a01b031690565b6100b4906100a0565b6100b4906100c3565b6100de906100cc565b9052565b6020810192916100f291906100d5565b565b3461009b57610104366004610090565b6101357f00000000000000000000000000000000000000000000000000000000000000005b604051918291826100e2565b0390f35b3461009b57610149366004610090565b61015161069f565b604051005b6100de906100b7565b6020810192916100f29190610156565b3461009b5761017f366004610090565b604051806101357f00000000000000000000000000000000000000000000000000000000000000008261015f565b6101b6816100b7565b0361009b57565b905035906100f2826101ad565b806101b6565b905035906100f2826101ca565b909160608284031261009b576100b46101f684846101bd565b9361020481602086016101bd565b936040016101d0565b3461009b576101516102203660046101dd565b91610d31565b3461009b57610236366004610090565b6101516108ed565b3461009b5761024e366004610090565b6101357f0000000000000000000000000000000000000000000000000000000000000000610129565b9060208282031261009b576100b4916101bd565b3461009b576101356102a66102a1366004610277565b610321565b6040515b9182918290815260200190565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff8211176102ef57604052565b6102b7565b905051906100f2826101ca565b9060208282031261009b576100b4916102f4565b6040513d6000823e3d90fd5b61034373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6100b7565b6100b7565b61034c826100b7565b0361035f575061035b306100cc565b3190565b60206103756103706103a9936100cc565b6100cc565b6370a082319061039e610387306100cc565b9261039160405190565b9586948593849360e01b90565b83526004830161015f565b03915afa9081156103e7576000916103bf575090565b6100b4915060203d81116103e0575b6103d881836102cd565b810190610301565b503d6103ce565b610315565b6103f461073a565b6103fc61046d565b6100f2610776565b0190565b60208082526021908201527f546f6b656e506f743a2063616c6c6572206973206e6f7420746865206f776e656040820152603960f91b606082015260800190565b1561045057565b60405162461bcd60e51b81528061046960048201610408565b0390fd5b6104aa335b6104a461049e7f00000000000000000000000000000000000000000000000000000000000000006100b7565b916100b7565b14610449565b6100f26104e9565b905051906100f2826101ad565b9060208282031261009b576100b4916104b2565b6100b76100b46100b49290565b6100b4906104d3565b6105127f00000000000000000000000000000000000000000000000000000000000000006100cc565b6349d3d5e161052060405190565b9161052b8260e01b90565b8352602083600481845afa9283156103e75760009361067f575b5060009261055861049e61033e866104e0565b0361056257505050565b61057b9160209161057260405190565b93849260e01b90565b825260049082905afa9081156103e7576105a19161037091600091610651575b506100cc565b637114177a813b1561009b576105c06105b960405190565b9160e01b90565b8152828160048183865af180156103e757610635575b50634e606c4790803b1561009b576105f391839161057260405190565b8252818381600481015b03925af180156103e75761060f575050565b816100f292903d1061062e575b61062681836102cd565b810190610090565b503d61061c565b61064b90833d851161062e5761062681836102cd565b386105d6565b610672915060203d8111610678575b61066a81836102cd565b8101906104bf565b3861059b565b503d610660565b61069891935060203d81116106785761066a81836102cd565b9138610545565b6100f26103ec565b6100b49081565b6100b490546106a7565b6100b46100b46100b49290565b6100b460026106b8565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b1561070d57565b60405162461bcd60e51b815280610469600482016106cf565b906100b46100b4610736926106b8565b9055565b6100f261074760006106ae565b6107656107526106c5565b91829061075e565b9190565b1415610706565b6000610726565b6100b460016106b8565b6100f261076561076c565b61078961073a565b6103fc61079533610472565b6100f26107c17f00000000000000000000000000000000000000000000000000000000000000006100cc565b63095f363c906107da6107d360405190565b9260e01b90565b8252602082600481845afa9182156103e7576000926108c7575b50602061080a916340ae3e149061057260405190565b825260049082905afa9081156103e7576000916108a9575b5060009161082f836104e0565b610838816100b7565b610841836100b7565b1415908161088e575b5061085457505050565b610370610860916100cc565b906336b91f2b90823b1561009b576105fd9261039e85809461088160405190565b9687958694859360e01b90565b61089891506100b7565b6108a1836100b7565b14153861084a565b6108c1915060203d81116106785761066a81836102cd565b38610822565b61080a9192506108e5602091823d81116106785761066a81836102cd565b9291506107f4565b6100f2610781565b906103fc929161090361073a565b6100f292919061091233610472565b610a23565b60208082526015908201527416995c9bc81859191c995cdcc819195d1958dd1959605a1b604082015260600190565b1561094d57565b60405162461bcd60e51b81528061046960048201610917565b6020808252600e908201526d125b9d985b1a5908185b5bdd5b9d60921b604082015260600190565b1561099557565b60405162461bcd60e51b81528061046960048201610966565b6002111561009b57565b905051906100f2826109ae565b60808183031261009b576109d982826102f4565b926100b46109ea84602085016102f4565b936109f881604086016102f4565b936060016109b8565b9160206100f2929493610a1c60408201966000830190610156565b0190610156565b90610b0f90600093610a34856104e0565b91610a3e836100b7565b610a47866100b7565b141580610d12575b610a5890610946565b610a61866106b8565b821180610cf8575b610a729061098e565b610a7b306100cc565b94610a8883828885610d3c565b7fa4195c37c2947bbe89165f03e320b6903116f0b10d8cfdb522330f7ce6f9fa24610ac9610abf610ab980336100cc565b946100cc565b946102aa60405190565b0390a46020610af77f00000000000000000000000000000000000000000000000000000000000000006100cc565b6349d3d5e190610b0660405190565b94859260e01b90565b825260049082905afa9182156103e757600092610cd4575b50610b31906100b7565b610b3a826100b7565b03610b4457505050565b610370610b50916100cc565b9063dde798a4610b626105b960405190565b815260808180610b75856004830161015f565b0381865afa80156103e7576000918291610ca1575b50610b9761075a866106b8565b119081610c8c575b50610ba957505050565b610bf69163954fa5ee936020610bde7f00000000000000000000000000000000000000000000000000000000000000006100cc565b6361d027b390610bed60405190565b96879260e01b90565b825260049082905afa9384156103e757600094610c66575b50610c309060209495610c3b610c2360405190565b9788968795869460e01b90565b845260048401610a01565b03925af180156103e757610c4c5750565b610c639060203d81116103e0576103d881836102cd565b50565b6020945090610c84610c3092863d81116106785761066a81836102cd565b945090610c0e565b9050610c9a61075a856106b8565b1138610b9f565b9050610cc4915060803d8111610ccd575b610cbc81836102cd565b8101906109c5565b50919091610b8a565b503d610cb2565b610b31919250610cf19060203d81116106785761066a81836102cd565b9190610b27565b50610a72610d086100b483610321565b8311159050610a69565b50610a58610d1f846100b7565b610d28836100b7565b14159050610a4f565b906100f292916108f5565b929190610d5c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6100b7565b610d65856100b7565b03610d74576100f29350610fd5565b6100f2936110ea565b6020808252600c908201526b53616d65206164647265737360a01b604082015260600190565b15610daa57565b60405162461bcd60e51b81528061046960048201610d7d565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b15610df057565b60405162461bcd60e51b81528061046960048201610dc3565b6020808252602a908201527f4f6e65206f662074686520616464726573736573206d757374206265207468696040820152691cc818dbdb9d1c9858dd60b21b606082015260800190565b15610e5a57565b60405162461bcd60e51b81528061046960048201610e09565b6020808252601d908201527f416d6f756e74206d7573742062652067726561746572207468616e2030000000604082015260600190565b15610eb157565b60405162461bcd60e51b81528061046960048201610e73565b602080825260139082015272496e636f7272656374206d73672e76616c756560681b604082015260600190565b15610efe57565b60405162461bcd60e51b81528061046960048201610eca565b906100f2610f2460405190565b92836102cd565b67ffffffffffffffff81116102ef57602090601f01601f19160190565b90610f5a610f5583610f2b565b610f17565b918252565b3d15610f7957610f6e3d610f48565b903d6000602084013e565b606090565b6020808252601c908201527f4e617469766520746f6b656e207472616e73666572206661696c656400000000604082015260600190565b15610fbc57565b60405162461bcd60e51b81528061046960048201610f7e565b90610ff2610fe2826100b7565b610feb846100b7565b1415610da3565b611060600092611025611004856104e0565b61100d816100b7565b611016846100b7565b141590816110cf575b50610de9565b61102e306100cc565b9061103b61049e836100b7565b1480156110b1575b61104c90610e53565b61033e611058856106b8565b865b11610eaa565b611069826100b7565b1461109a5781906100f29361107d60405190565b9081611088816100b4565b03925af1611094610f5f565b50610fb5565b50506100f2906110ab61075a349290565b14610ef7565b5061104c6110be826100b7565b6110c7856100b7565b149050611043565b6110d991506100b7565b6110e2856100b7565b14153861101f565b9291906111026110f9836100b7565b610feb836100b7565b61114161113b6000611136611116826104e0565b61111f816100b7565b611128876100b7565b1415908161117e5750610de9565b6106b8565b8461105a565b61114d61033e306100cc565b611156826100b7565b0361116d57506111686100f2936100cc565b6111d6565b6111796100f2946100cc565b611248565b61118891506100b7565b6110e2876100b7565b6111aa6111a46100b49263ffffffff1690565b60e01b90565b6001600160e01b03191690565b9160206100f29294936111d260408201966000830190610156565b0152565b61121960049261120a6100f2956111f063a9059cbb611191565b926111fa60405190565b96879460208601908152016111b7565b602082018103825203836102cd565b61134c565b6040906111d26100f2949695939661123e60608401986000850190610156565b6020830190610156565b906112199061120a6100f2956004956112646323b872dd611191565b9361126e60405190565b978895602087019081520161121e565b6112886020610f48565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602082015290565b6100b461127e565b8015156101b6565b905051906100f2826112b9565b9060208282031261009b576100b4916112c1565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b1561133357565b60405162461bcd60e51b815280610469600482016112e2565b6100f29161135c61136b926100cc565b906113656112b1565b916113a9565b805161137a61075a60006106b8565b14908115611389575b5061132c565b6113a391506020611398825190565b8183010191016112ce565b38611383565b6100b492916113b860006106b8565b91611424565b60208082526026908201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6040820152651c8818d85b1b60d21b606082015260800190565b1561140b57565b60405162461bcd60e51b815280610469600482016113be565b9060006100b494938192611436606090565b5061144d611443306100cc565b8390311015611404565b60208101905191855af161145f610f5f565b916114bc565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b156114a357565b60405162461bcd60e51b81528061046960048201611465565b919290156114ee575081516114d461075a60006106b8565b146114dd575090565b6114e96100b4916114f4565b61149c565b8261156e565b3b61150261075a60006106b8565b1190565b60005b8381106115195750506000910152565b8181015183820152602001611509565b61154a6115536020936104049361153e815190565b80835293849260200190565b95869101611506565b601f01601f191690565b60208082526100b492910190611529565b90611577825190565b61158461075a60006106b8565b11156115935750805190602001fd5b610469906115a060405190565b62461bcd60e51b81529182916004830161155d56fea26469706673582212202925253f117c3d8d0257b40d4cc4d58d48baf9702c60a507bc390cd44ddf19d264736f6c6343000812003300000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d000000000000000000000000b0cc02228cbbacad1b8350dd24bd335ed6ba54bf
Deployed Bytecode
0x60806040526004361015610023575b361561001957600080fd5b610021610aa5565b005b60003560e01c8062b190d9146102a257806302b0dbd71461029d5780631083f761146102985780631a8bd2da146102935780631f6ac4a31461028e578063271d1df4146102895780632e2071211461028457806332ec84d21461027f5780633fef6dc11461027a5780634ac032be146102755780634e29a3331461027057806350eb741c1461026b57806351dddf4f146102665780635c975abb146102615780635cd480b41461025c5780636685ed87146102575780636a8f6ebb14610252578063741bef1a1461024d5780638d93fb21146102485780638da5cb5b146102435780639136bd471461023e5780639283556f1461023957806395877f78146102345780639e3141d31461022f578063af3345d11461022a578063b25f2f8514610225578063b85fc76614610220578063bd4f7c571461021b578063c66f245514610216578063cd85cdb514610211578063d189b8a11461020c578063d5ba680914610207578063dbbfedf214610202578063ddef1953146101fd578063e06174e4146101f8578063e0851a88146101f3578063e13a4fe9146101ee578063ea00162c146101e9578063eaee8425146101e45763f7a17d930361000e57610974565b610959565b610941565b610913565b6108d5565b610866565b61084e565b610833565b61080f565b6107f6565b6107bb565b6107a0565b61078d565b610772565b61075f565b610747565b61072f565b610717565b6106d2565b6106ba565b61069f565b610684565b610669565b610642565b610609565b6105f1565b6105c7565b610594565b610581565b610569565b61054a565b6104c0565b6104a8565b61046f565b61045c565b61040b565b610384565b610343565b6102f0565b6102bd565b60009103126102b257565b600080fd5b9052565b565b346102b2576102cd3660046102a7565b6102ec6102d86115ae565b6040519182918260ff909116815260200190565b0390f35b346102b2576103003660046102a7565b6102ec61030b6116b5565b6040519182918290815260200190565b6001600160a01b031690565b90565b6102b79061031b565b6020810192916102bb919061032a565b346102b2576103533660046102a7565b6102ec7f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee5b60405191829182610333565b346102b2576103943660046102a7565b61039c61407c565b604051005b610327916008021c6001600160a01b031690565b9061032791546103a1565b610327600360016103b5565b6103279061031b906001600160a01b031682565b610327906103cc565b610327906103e0565b6102b7906103e9565b6020810192916102bb91906103f2565b346102b25761041b3660046102a7565b6102ec6104266103c0565b604051918291826103fb565b805b036102b257565b905035906102bb82610432565b906020828203126102b2576103279161043b565b61039c61046a366004610448565b613228565b346102b25761047f3660046102a7565b6102ec7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb77610378565b346102b2576104b83660046102a7565b61039c614120565b346102b2576104d03660046102a7565b6102ec7f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b610426565b634e487b7160e01b600052602160045260246000fd5b6002111561051957565b6104f9565b906102bb8261050f565b6103279061051e565b6102b790610528565b6020810192916102bb9190610531565b346102b25761055a3660046102a7565b604051806102ec60008261053a565b346102b2576105793660046102a7565b61039c613d50565b61039c61058f366004610448565b612371565b346102b2576105a43660046102a7565b61039c6142bd565b90151581529015156020820152901515604082015260600190565b346102b2576105d73660046102a7565b6102ec6105e2611384565b604051919391938493846105ac565b346102b25761039c610604366004610448565b613909565b346102b2576106193660046102a7565b6102ec7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d610378565b346102b2576106523660046102a7565b6102ec61030b6116ad565b6103276000600d6103b5565b346102b2576106793660046102a7565b6102ec61042661065d565b346102b2576106943660046102a7565b6102ec61030b6116bf565b346102b2576106af3660046102a7565b6102ec610378610a17565b346102b25761039c6106cd366004610448565b613014565b346102b2576106e23660046102a7565b6102ec61030b611487565b6104348161031b565b905035906102bb826106ed565b906020828203126102b257610327916106f6565b346102b25761039c61072a366004610703565b615e40565b346102b25761039c610742366004610448565b612da4565b346102b2576107573660046102a7565b61039c61419c565b61039c61076d366004610448565b6125b5565b346102b2576107823660046102a7565b6102ec61030b6113db565b61039c61079b366004610448565b612716565b346102b2576107b03660046102a7565b6102ec61030b611491565b346102b2576107cb3660046102a7565b61039c614000565b91906040838203126102b257610327906107ed81856106f6565b936020016106f6565b346102b25761039c6108093660046107d3565b9061456d565b346102b25761039c610822366004610448565b612b56565b610327600060026103b5565b346102b2576108433660046102a7565b6102ec610426610827565b346102b25761085e3660046102a7565b61039c613eb8565b346102b2576108763660046102a7565b6102ec7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933610426565b6004111561051957565b906102bb8261089f565b610327906108a9565b6102b7906108b3565b6020810192916102bb91906108bc565b346102b2576108e53660046102a7565b6102ec6108f0611699565b604051918291826108c5565b9081526040810192916102bb9160200152565b0152565b346102b2576109233660046102a7565b61092b61162b565b906102ec61093860405190565b928392836108fc565b346102b2576109513660046102a7565b61039c614241565b346102b2576102ec61030b61096f366004610448565b611637565b346102b2576109843660046102a7565b6102ec7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc1390610426565b634e487b7160e01b600052604160045260246000fd5b90601f01601f1916810190811067ffffffffffffffff8211176109e557604052565b6109ad565b905051906102bb826106ed565b906020828203126102b257610327916109ea565b6040513d6000823e3d90fd5b610a5d6020610a457f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b63c1d6ba6990610a5460405190565b93849260e01b90565b825260049082905afa908115610aa057600091610a78575090565b610327915060203d8111610a99575b610a9181836109c3565b8101906109f7565b503d610a87565b610a0b565b6102bb7f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee610ad2306103e9565b610afb7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b9034925b929190610b2473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b61031b565b610b2d8561031b565b03610b3c576102bb9350610d86565b6102bb93610e9d565b0190565b15610b5057565b60405162461bcd60e51b815260206004820152600c60248201526b53616d65206164647265737360a01b6044820152606490fd5b0390fd5b61031b6103276103279290565b61032790610b88565b15610ba557565b60405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606490fd5b15610be057565b60405162461bcd60e51b815260206004820152602a60248201527f4f6e65206f662074686520616464726573736573206d757374206265207468696044820152691cc818dbdb9d1c9858dd60b21b6064820152608490fd5b6103276103276103279290565b15610c4c57565b60405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b15610c9857565b60405162461bcd60e51b8152602060048201526013602482015272496e636f7272656374206d73672e76616c756560681b6044820152606490fd5b906102bb610ce060405190565b92836109c3565b67ffffffffffffffff81116109e557602090601f01601f19160190565b90610d16610d1183610ce7565b610cd3565b918252565b3d15610d3557610d2a3d610d04565b903d6000602084013e565b606090565b15610d4157565b60405162461bcd60e51b815260206004820152601c60248201527f4e617469766520746f6b656e207472616e73666572206661696c6564000000006044820152606490fd5b90610da3610d938261031b565b610d9c8461031b565b1415610b49565b610e17600092610dd6610db585610b95565b610dbe8161031b565b610dc78461031b565b14159081610e82575b50610b9e565b610ddf306103e9565b90610df2610dec8361031b565b9161031b565b148015610e64575b610e0390610bd9565b610b1f610e0f85610c38565b865b11610c45565b610e208261031b565b14610e495781906102bb93610e3460405190565b90818003925af1610e43610d1b565b50610d3a565b50506102bb90610e5e610e5a349290565b9190565b14610c91565b50610e03610e718261031b565b610e7a8561031b565b149050610dfa565b610e8c915061031b565b610e958561031b565b141538610dd0565b929190610eb5610eac8361031b565b610d9c8361031b565b610ef4610eee6000610ee9610ec982610b95565b610ed28161031b565b610edb8761031b565b14159081610f315750610b9e565b610c38565b84610e11565b610f00610b1f306103e9565b610f098261031b565b03610f205750610f1b6102bb936103e9565b610f85565b610f2c6102bb946103e9565b610ff7565b610f3b915061031b565b610e958761031b565b610f5d610f576103279263ffffffff1690565b60e01b90565b6001600160e01b03191690565b9160206102bb92949361090f6040820196600083019061032a565b610fc8600492610fb96102bb95610f9f63a9059cbb610f44565b92610fa960405190565b9687946020860190815201610f6a565b602082018103825203836109c3565b6110f0565b60409061090f6102bb9496959396610fed6060840198600085019061032a565b602083019061032a565b90610fc890610fb96102bb956004956110136323b872dd610f44565b9361101d60405190565b9788956020870190815201610fcd565b6110376020610d04565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602082015290565b61032761102d565b801515610434565b905051906102bb82611068565b906020828203126102b25761032791611070565b1561109857565b60405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b6102bb9161110061110f926103e9565b90611109611060565b9161114d565b805161111e610e5a6000610c38565b1490811561112d575b50611091565b6111479150602061113c825190565b81830101910161107d565b38611127565b610327929161115c6000610c38565b916111bd565b1561116957565b60405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608490fd5b906000610327949381926111cf606090565b506111e66111dc306103e9565b8390311015611162565b60208101905191855af16111f8610d1b565b9161124a565b1561120557565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b9192901561127c57508151611262610e5a6000610c38565b1461126b575090565b61127761032791611282565b6111fe565b826112fc565b3b611290610e5a6000610c38565b1190565b60005b8381106112a75750506000910152565b8181015183820152602001611297565b6112d86112e1602093610b45936112cc815190565b80835293849260200190565b95869101611294565b601f01601f191690565b6020808252610327929101906112b7565b90611305825190565b611312610e5a6000610c38565b11156113215750805190602001fd5b610b849061132e60405190565b62461bcd60e51b8152918291600483016112eb565b610327905b60ff1690565b6103279054611343565b6103279060081c611348565b6103279054611358565b6103279060101c611348565b610327905461136e565b61138e600161134e565b6113986001611364565b916113a3600161137a565b91929190565b6103279081565b61032790546113a9565b905051906102bb82610432565b906020828203126102b257610327916113ba565b611449602061141161140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b6103e9565b63db977f959061143b61142460076113b0565b9261142e60405190565b9586948593849360e01b90565b835260048301526024820190565b03915afa908115610aa05760009161145f575090565b610327915060203d8111611480575b61147881836109c3565b8101906113c7565b503d61146e565b61032760076113b0565b6114fe60206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b63e3d670d7906114f37f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9261142e60405190565b835260048301610333565b03915afa908115610aa0576103279161152a91600091611534575b5061152460046113b0565b9061157a565b61152460056113b0565b61154c915060203d81116114805761147881836109c3565b38611519565b634e487b7160e01b600052601160045260246000fd5b9190820391821161157557565b611552565b6103279190611568565b60ff8116610434565b905051906102bb82611584565b906020828203126102b2576103279161158d565b6115ed60206115bc306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e49526115e263f7dcd19361142e60405190565b8352600483016103fb565b03915af4908115610aa057600091611603575090565b610327915060203d8111611624575b61161c81836109c3565b81019061159a565b503d611612565b611633615e49565b9091565b60206116627f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f879336103e9565b635bec50be9061168e611674306103e9565b9261144961168160405190565b9687958694859460e01b90565b845260048401610f6a565b610327600861134e565b610327600a610c38565b6103276116a3565b610327600b6113b0565b610327600c6113b0565b6116da906116d56123d0565b61171c565b6102bb612402565b156116e957565b60405162461bcd60e51b815260206004820152600b60248201526a135a5b9d081c185d5cd95960aa1b6044820152606490fd5b6102bb90611739611734611730600161134e565b1590565b6116e2565b61178a565b1561174557565b60405162461bcd60e51b815260206004820152601c60248201527f56616c7565206d7573742062652067726561746572207468616e2030000000006044820152606490fd5b6102bb906117a261179b6000610c38565b821161173e565b61195a565b9060ff905b9181191691161790565b906117c66103276117cd926108b3565b82546117a7565b9055565b90600019906117ac565b906117eb6103276117cd92610c38565b82546117d1565b6103279061031b565b61032790546117f2565b1561180c57565b60405162461bcd60e51b8152602060048201526017602482015276141d1e541bdbdb14d95b1b121a59da081b9bdd081cd95d604a1b6044820152606490fd5b9160206102bb929493611866604082019660008301906103f2565b01906103f2565b6103279060181c61031b565b610327905461186d565b1561188a57565b60405162461bcd60e51b8152602060048201526015602482015274141d1e541bdbdb109d5e531bddc81b9bdd081cd95d605a1b6044820152606490fd5b6103276103276103279260ff1690565b604d811161157557600a0a90565b600211156102b257565b905051906102bb826118e5565b6080818303126102b25761191082826113ba565b9261032761192184602085016113ba565b9361192f81604086016113ba565b936060016118ef565b9160206102bb9294936119536040820196600083019061032a565b019061032a565b6001611966600861134e565b9160009261197c611976856108a9565b916108a9565b14612152575b6119b060206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa057839160009361212e575b506119cf906122cb565b6120f1575b5030906119e0826103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e495290630b7c480590611a0660405190565b90611a118360e01b90565b825260208280611a2488600483016103fb565b0381875af4918215610aa0576000926120d1575b50611a4c82611a47600a6113b0565b615bd5565b611a5f610327634141525360e01b611637565b821015611f4557611a96611a7282611879565b611a8f611a89611a8461140c8c610b95565b6117f2565b916117f2565b1415611883565b611ab572141d1e541bdbdb135a5b955cd8905b5bdd5b9d606a1b611637565b90611ae261140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b9163313ce5676020611af360405190565b8095611aff8460e01b90565b825260049082905afa908115610aa057611b5594600092611f23575b50602090611b487f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f879336103e9565b6040515b96879260e01b90565b825260049082905afa938415610aa057611b9f602093611b99611b94611bbd98611ba59661140c96600092611f00575b50611b8f906118c7565b611568565b6118d7565b90612420565b93611879565b63e766c83590611bb460405190565b94859260e01b90565b825260049082905afa918215610aa057600092611ed8575b50905b11611e5b575b50916020916115e2611bf3945b60405161142e565b03915af48015610aa057611c1191600091611e3d575b50600a6117db565b611c4e6020611c3f7f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b6349d3d5e190610a5460405190565b825260049082905afa908115610aa057600091611e1f575b50611c73610b1f84610b95565b611c7c8261031b565b03611c87575b505050565b61140c611c93916103e9565b90611ca263dde798a4916103e9565b90611cb6611caf60405190565b9160e01b90565b815260808180611cc98560048301610333565b0381865afa8015610aa0576000918291611dec575b50611ceb610e5a86610c38565b119081611dd7575b50611cfd57505050565b611d419163954fa5ee936020611d327f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f879336103e9565b6361d027b390611b4c60405190565b825260049082905afa938415610aa057600094611db1575b50611d7b9060209495611d86611d6e60405190565b9788968795869460e01b90565b845260048401611938565b03925af18015610aa057611d975750565b611dae9060203d81116114805761147881836109c3565b50565b6020945090611dcf611d7b92863d8111610a9957610a9181836109c3565b945090611d59565b9050611de5610e5a85610c38565b1138611cf3565b9050611e0f915060803d8111611e18575b611e0781836109c3565b8101906118fc565b50919091611cde565b503d611dfd565b611e37915060203d8111610a9957610a9181836109c3565b38611c66565b611e55915060203d81116114805761147881836109c3565b38611c09565b929091611e66614fe3565b60405193611e748460e01b90565b855260208580611e8786600483016103fb565b0381855af4938415610aa057611eaf6020956115e293611bf398600092611eb9575b50615bd5565b9294505091611bde565b611ed1919250883d81116114805761147881836109c3565b9038611ea9565b611bd8919250611ef8610e5a9160203d81116114805761147881836109c3565b929150611bd5565b611b8f919250611f1c908a3d81116114805761147881836109c3565b9190611b85565b6020919250611f3e90823d81116116245761161c81836109c3565b9190611b1b565b50611f59610327634141525560e01b611637565b8111611f71575b50916020916115e2611bf394611beb565b611f97611f7e60026117fb565b611f90611a89611a8461140c8b610b95565b1415611805565b635915a1746020611fda7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f8793392611fe6611fcf60405190565b948593849360e01b90565b8352896004840161184b565b0381875af48015610aa05761200d916000916120b3575b506020611ba561140c60026117fb565b825260049082905afa918215610aa05760009261208b575b50905b1115611f605792909161203961534c565b604051936120478460e01b90565b85526020858061205a86600483016103fb565b0381855af4938415610aa0576120816020956115e293611bf398600092611eb95750615bd5565b9294505091611f60565b6120289192506120ab610e5a9160203d81116114805761147881836109c3565b929150612025565b6120cb915060203d81116114805761147881836109c3565b38611ffd565b6120ea91925060203d81116114805761147881836109c3565b9038611a38565b6120fb60096113b0565b612107610e5a85610c38565b0361211f575b506121194260096117db565b386119d4565b612128906155a8565b3861210d565b6119cf91935061214b9060203d81116114805761147881836109c3565b92906119c5565b61215d8260086117b6565b611982565b9190916101c0818403126102b25761227761217e6101c0610cd3565b93600061218b82856113ba565b90860152602061219d828286016113ba565b9086015260406121af828286016113ba565b9086015260606121c1828286016113ba565b9086015260806121d3828286016113ba565b9086015260a06121e5828286016113ba565b9086015260c06121f7828286016113ba565b9086015260e0612209828286016113ba565b9086015261010061221c828286016113ba565b9086015261012061222f828286016113ba565b90860152610140612242828286016113ba565b90860152610160612255828286016113ba565b90860152610180612268828286016113ba565b908601526101a08093016113ba565b90830152565b9091610200828403126102b2576103276122978484612162565b936122a6816101c086016113ba565b936101e0016113ba565b9160206102bb92949361090f604082019660008301906103f2565b806102006122d8306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e631ff858b661231961230160405190565b9788958694859460e01b90565b8452600484016122b0565b03915af48015610aa0576102bb92600092839283929061233a575b50614577565b9150925061236091506102003d811161236a575b61235881836109c3565b81019061227d565b9238929192612334565b503d61234e565b6102bb906116c9565b6103276002610c38565b1561238b57565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6102bb6123dd60006113b0565b6123f16123e861237a565b91821415612384565b60006117db565b6103276001610c38565b6102bb6123f16123f8565b8181029291811591840414171561157557565b610327919061240d565b6116da906124366123d0565b6102bb9061244a611734611730600161134e565b6102bb9061245b61179b6000610c38565b6001612467600861134e565b91600092612477611976856108a9565b146124ee575b6124ab60206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa05783916000936124ca575b506119cf90612523565b6119cf9193506124e79060203d81116114805761147881836109c3565b92906124c0565b6124f98260086117b6565b61247d565b91906101e0838203126102b257610327906125198185612162565b936101c0016113ba565b806101e0612530306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e6394eb4aca61255961230160405190565b03915af4918215610aa0576102bb926000918291612583575b5061257d6000610c38565b92614577565b90506125a791506101e03d81116125ae575b61259f81836109c3565b8101906124fe565b9038612572565b503d612595565b6102bb9061242a565b6116da906125ca6123d0565b6102bb906125de611734611730600161134e565b6102bb906125ef61179b6000610c38565b60016125fb600861134e565b9160009261260b611976856108a9565b14612682575b61263f60206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa057839160009361265e575b506119cf90612692565b6119cf91935061267b9060203d81116114805761147881836109c3565b9290612654565b61268d8260086117b6565b612611565b806101e061269f306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e6344ff2f636126c861168160405190565b03915af4918215610aa0576102bb9260009283916126f2575b506126ec6000610c38565b91614577565b905061270e9192506101e03d81116125ae5761259f81836109c3565b9190386126e1565b6102bb906125be565b6116da9061272b6123d0565b61276c565b1561273757565b60405162461bcd60e51b815260206004820152600d60248201526c14995919595b481c185d5cd959609a1b6044820152606490fd5b6102bb906127856127806117306001611364565b612730565b6102bb9061279661179b6000610c38565b60016127a2600861134e565b916000926127b2611976856108a9565b14612829575b6127e660206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa0578391600093612805575b506119cf90612903565b6119cf9193506128229060203d81116114805761147881836109c3565b92906127fb565b6128348260086117b6565b6127b8565b1561284057565b60405162461bcd60e51b81526020600482015260166024820152754e6f7420656e6f756768205553422062616c616e636560501b6044820152606490fd5b1561288557565b60405162461bcd60e51b815260206004820152601f60248201527f4e6f7420656e6f756768206d617267696e20746f6b656e2062616c616e6365006044820152606490fd5b909594926102bb946128fc61090f926128f56080966128ee60a088019c6000890152565b6020870152565b6040850152565b6060830152565b61292f61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b6370a08231913391602061294260405190565b809261294e8760e01b90565b8252818061295f8860048301610333565b03915afa908115610aa0576129869161297d9160009161145f575090565b825b1115612839565b61298f306103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e495291634b10cd51946129bf6129b860405190565b9660e01b90565b8652602086806129d38686600484016122b0565b0381875af4958615610aa057600096612b2e575b50906020612a2392612a1b61140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b604051611bb4565b82528180612a348a60048301610333565b03915afa938415610aa057612a5f612a5688966101e09560009161145f575090565b865b111561287e565b61230e63df4ef462612a80612a7360405190565b998a958694859460e01b90565b03915af4938415610aa057600080919095612b00575b50612aa6838387612afb94614872565b94612abd6040612ab7602084015190565b92015190565b90612ae87f5975ae134530356ba04a9728ddefa4c6676e1433c72bf75970c7775d4771a762966103e9565b96612af260405190565b958695866128ca565b0390a2565b829550612afb915083612b24612aa6926101e03d81116125ae5761259f81836109c3565b9350965050612a96565b612a2392919650612b4d602091823d81116114805761147881836109c3565b969192506129e7565b6102bb9061271f565b6116da90612b6b6123d0565b6102bb90612b7f6127806117306001611364565b6102bb90612b9061179b6000610c38565b6001612b9c600861134e565b91600092612bac611976856108a9565b14612c23575b612be060206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa0578391600093612bff575b506119cf90612c33565b6119cf919350612c1c9060203d81116114805761147881836109c3565b9290612bf5565b612c2e8260086117b6565b612bb2565b612c5f61140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b6370a0823133916020612c7160405190565b8092612c7d8560e01b90565b82528180612c8e8860048301610333565b03915afa908115610aa057612cb291612cac9160009161145f575090565b84612a58565b612cbb306103e9565b9073b5ecfd108619fb8e7c65658b9419f81ea62e49529163532d6bcc90612ceb612ce460405190565b9260e01b90565b825260208280612cff8985600484016122b0565b0381875af4918215610aa057600092612d80575b506020612d479293612a1b61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b82528180612d588a60048301610333565b03915afa938415610aa057612a5f612d7a88966101e09560009161145f575090565b8561297f565b612d479250612d9d602091823d81116114805761147881836109c3565b9250612d13565b6102bb90612b5f565b6116da90612db96123d0565b6102bb90612dcd6127806117306001611364565b6102bb90612dde61179b6000610c38565b6001612dea600861134e565b91600092612dfa611976856108a9565b14612e71575b612e2e60206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa0578391600093612e4d575b506119cf90612eae565b6119cf919350612e6a9060203d81116114805761147881836109c3565b9290612e43565b612e7c8260086117b6565b612e00565b61090f6102bb94612ea7606094989795612ea0608086019a6000870152565b6020850152565b6040830152565b612eda61140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b612ef060206370a08231335b93610a5460405190565b82528180612f018760048301610333565b03915afa908115610aa057612f2591612f1f9160009161145f575090565b83612a58565b816101e0612f32306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e631823dec0612f68612f5b60405190565b9889958694859460e01b90565b03915af4928315610aa057600080919094612fec575b5081612f959185612f8f6000610c38565b91614872565b90612afb612faf6040612fa9602088015190565b96015190565b612fd97ff364e0a28f9a8aafaf506d9afb875c3c563242a31e7aa6a29049be7d514822b5956103e9565b95612fe360405190565b94859485612e81565b829450612f95915061300c906101e03d81116125ae5761259f81836109c3565b915093612f7e565b6102bb90612dad565b6116da906130296123d0565b6102bb9061303d6127806117306001611364565b6102bb9061304e61179b6000610c38565b600161305a600861134e565b9160009261306a611976856108a9565b146130e1575b61309e60206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa05783916000936130bd575b506119cf906130f1565b6119cf9193506130da9060203d81116114805761147881836109c3565b92906130b3565b6130ec8260086117b6565b613070565b61311d61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b61312d60206370a0823133612ee6565b8252818061313e8760048301610333565b03915afa908115610aa0576131629161315c9160009161145f575090565b8361297f565b816101e061316f306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261230e63b5321dd6613198612f5b60405190565b03915af4928315610aa057600080919094613203575b506131c59082856131bf6000610c38565b92614872565b90612afb6131d96040612fa9602088015190565b612fd97f63c111c8e2f0628c2100af0de149ab39c61f77b487b7ce9b884badc8ad55ad68956103e9565b6131c5945061322191506101e03d81116125ae5761259f81836109c3565b90936131ae565b6102bb9061301d565b6116da9061323d6123d0565b61328e565b1561324957565b60405162461bcd60e51b815260206004820152601b60248201527f55534220746f204d617267696e20546f6b656e732070617573656400000000006044820152606490fd5b6102bb906132a76132a2611730600161137a565b613242565b6102bb906132b861179b6000610c38565b6000906132c5600861134e565b6132d1611976846108a9565b1461359f575b61330560206114bf7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b03915afa918215610aa057839160009361357b575b5061332490613605565b61353e575b5030613334816103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e4952630b7c480561335760405190565b6133618260e01b90565b81526020818061337487600483016103fb565b0381865af4908115610aa057600091613520575b5061339781611a47600a6113b0565b6133aa610327634141525360e01b611637565b81101561350d576133d06133be6001611879565b611a8f611a89611a8461140c8b610b95565b6133ef72141d1e541bdbdb135a5b955cd8905b5bdd5b9d606a1b611637565b61341b61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b9063313ce56790602061342d60405190565b80946134398560e01b90565b825260049082905afa918215610aa05761348f936000936134eb575b506020906134827f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f879336103e9565b6040515b95869260e01b90565b825260049082905afa918215610aa057611b946134bf93611b9992611bbd966000926134ce5750611b8f906118c7565b6020611ba561140c6001611879565b611b8f919250611f1c9060203d81116114805761147881836109c3565b602091935061350690823d81116116245761161c81836109c3565b9290613455565b611f59610327634141525560e01b611637565b613538915060203d81116114805761147881836109c3565b38613388565b61354860096113b0565b613554610e5a84610c38565b0361356c575b506135664260096117db565b38613329565b613575906155a8565b3861355a565b6133249193506135989060203d81116114805761147881836109c3565b929061331a565b6135ab600160086117b6565b6132d7565b60409061090f6102bb94969593966135d0606084019860008501906103f2565b60208301906103f2565b6102b790610c38565b61090f6102bb94612ea7606094989795612ea0608086019a60008701906135da565b61363161140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b906370a08231903391613646611caf60405190565b8152602081806136598660048301610333565b0381875afa908115610aa0576136789161297d9160009161145f575090565b613681306103e9565b906101e073b5ecfd108619fb8e7c65658b9419f81ea62e495292633671ef3e936136e07f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933956136eb866136d360405190565b9889968795869560e01b90565b8552600485016135b0565b03915af48015610aa0576137189460009384926138e2575b50604051956020918791632770a7eb60e21b90565b82528160008161372c888b60048401610f6a565b03925af1938415610aa0576137ab956000956138c2575b5061376161375a8661375560076113b0565b61157a565b60076117db565b60208201916040613770845190565b91019561377b875190565b91600080516020615f0b83398151915291613795856103e9565b998a946137a160405190565b9384938a85612e81565b0390a26137da61140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b906340c10f1990823b156102b257859261168e600080946137fd611d6e60405190565b03925af18015610aa057612afb926138719261386c9261389c575b5087600087613825845190565b916138656138318c5190565b7fe79d2400774c9ceba50645590d91414af42f277c27641bd9cba2f5b92db83ad59461385c60405190565b948594856135e3565b0390a25190565b945190565b7f52d7aa340d530e823911f14778f0f82b34460971ef6af5c237d103ebeae637bc94612fe360405190565b6138b59060005b6138ad81836109c3565b8101906102a7565b38613818565b503d6138a3565b6138db91955060203d81116114805761147881836109c3565b9338613743565b602094506139009192506101e03d81116125ae5761259f81836109c3565b93919091613703565b6102bb90613231565b61391a6123d0565b6116da61397a565b1561392957565b60405162461bcd60e51b815260206004820152602360248201527f4f776e61626c653a2063616c6c6572206973206e6f74207468652070726f746f60448201526218dbdb60ea1b6064820152608490fd5b6139b4335b6139ae610dec610b1f7f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b14613922565b6102bb6139e07f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b6349d3d5e16139ee60405190565b916139f98260e01b90565b8352602083600481845afa928315610aa057600093613d30575b50600092613a26610dec610b1f86610b95565b03613a3057505050565b613a4091602091610a5460405190565b825260049082905afa8015610aa057613a6191600091613d12575b506103e9565b7f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee613aa2610dec73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b14613cad575b613ab1906103e9565b634e606c4790803b156102b257613acd918391610a5460405190565b8252600490829084905af18015610aa057613c91575b50613b0d7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b634e29a33390803b156102b25782613b2460405190565b8092613b308560e01b90565b8252600490829084905af18015610aa057613c75575b50613b7361140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b803b156102b25782613b8460405190565b8092613b908560e01b90565b8252600490829084905af18015610aa057613c59575b50613bb461140c6001611879565b803b156102b25782613bc560405190565b8092613bd18560e01b90565b8252600490829084905af18015610aa057613c3d575b50613bf561140c60026117fb565b803b156102b257613c0b918391610a5460405190565b8252818381600481015b03925af18015610aa057613c27575050565b816102bb92903d106138bb576138ad81836109c3565b613c5390833d85116138bb576138ad81836109c3565b38613be7565b613c6f90833d85116138bb576138ad81836109c3565b38613ba6565b613c8b90833d85116138bb576138ad81836109c3565b38613b46565b613ca790823d84116138bb576138ad81836109c3565b38613ae3565b613cb6816103e9565b90637114177a91803b156102b257613cd3928491611bb460405190565b8252600490829084905af1918215610aa057613ab192613cf6575b509050613aa8565b613d0c90843d86116138bb576138ad81836109c3565b38613cee565b613d2a915060203d8111610a9957610a9181836109c3565b38613a5b565b613d4991935060203d8111610a9957610a9181836109c3565b9138613a13565b6102bb613912565b613d606123d0565b6116da613d6c3361397f565b6102bb613d987f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b63095f363c90613daa612ce460405190565b8252602082600481845afa908115610aa057613dda92600092613e96575b506040516020916340ae3e1491611bb4565b825260049082905afa918215610aa057600092613e76575b50600091613dff83610b95565b91613e0c610dec8461031b565b14159182613e5e575b5050613e1e5750565b613e477f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b63ddef195390803b156102b25782613b8460405190565b613e6d919250610dec9061031b565b14153880613e15565b613e8f91925060203d8111610a9957610a9181836109c3565b9038613df2565b6020919250613eb190823d8111610a9957610a9181836109c3565b9190613dc8565b6102bb613d58565b613ec86123d0565b6116da613f20565b15613ed757565b60405162461bcd60e51b815280610b84600482016020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b613f5f335b6020613f507f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b63c1d6ba6990611bb460405190565b825260049082905afa8015610aa057610dec613f8791613f8d94600091613f95575b5061031b565b14613ed0565b6102bb613fc3565b613fad915060203d8111610a9957610a9181836109c3565b38613f81565b906117c66103276117cd92151590565b613fce600180613fb3565b7fd7d248ba47bac931be252275aff92303dd610ca36c92c05dbac783fde1662a0e613ff860405190565b80805b0390a1565b6102bb613ec0565b6140106123d0565b6116da61401c33613f25565b825260049082905afa8015610aa057610dec613f879161404394600091613f95575061031b565b6102bb61405260006001613fb3565b7fd76d4045ba8d223490b9c6a5657cfdaa2316ac28a5a65274870bfe66a33ea0c4613ff860405190565b6102bb614008565b61408c6123d0565b6116da61409833613f25565b825260049082905afa8015610aa057610dec613f87916140bf94600091613f95575061031b565b6102bb6140eb565b9061ff009060081b6117ac565b906140e46103276117cd92151590565b82546140c7565b6140f66001806140d4565b7f60b78ed2d882d2d2387ad2b7119495f7c99dd9a9c191d3d02c35982a0750bcc6613ff860405190565b6102bb614084565b6141306123d0565b6116da61413c33613f25565b825260049082905afa8015610aa057610dec613f879161416394600091613f95575061031b565b6102bb614172600060016140d4565b7f687bf6e69dbabcc95e11041b4816a83f36dcf6ef647f6acf63e7469d28f5ea73613ff860405190565b6102bb614128565b6141ac6123d0565b6116da6141b833613f25565b825260049082905afa8015610aa057610dec613f87916141df94600091613f95575061031b565b6102bb61420c565b9062ff00009060101b6117ac565b906142056103276117cd92151590565b82546141e7565b6142176001806141f5565b7fff1961bacbc4ad36bbb3affa41b9ca1167f9f3e8b2fa05b3a3d87546424c72f8613ff860405190565b6102bb6141a4565b6142516123d0565b6116da61425d33613f25565b825260049082905afa8015610aa057610dec613f879161428494600091613f95575061031b565b6102bb614293600060016141f5565b7fe2a0c3d430f5c761f9440a5c7c1a9c27524338eb75537ec0ffa23744248e89de613ff860405190565b6102bb614249565b906116da916142d26123d0565b9033916143036020610a457f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b825260049082905afa938415610aa057613f87610dec6102bb9661432e94600091613f95575061031b565b614405565b1561433a57565b60405162461bcd60e51b815260206004820152601560248201527416995c9bc81859191c995cdcc819195d1958dd1959605a1b6044820152606490fd5b1561437e57565b60405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a59081d985d5b1d609a1b6044820152606490fd5b906301000000600160b81b039060181b6117ac565b906143d86103276117cd926103e9565b82546143b3565b906001600160a01b03906117ac565b906143fe6103276117cd926103e9565b82546143df565b6144379061140c6144166000610b95565b61441f8161031b565b6144288461031b565b14159081614552575b50614333565b614440816103e9565b63fbfa77cf90602061445160405190565b809261445d8560e01b90565b825260049082905afa908115610aa057600091614534575b5061447f306103e9565b9061448c610dec8361031b565b1491826144b8575b50509161140c6144b1926144aa6102bb95614377565b60016143c8565b60026143ee565b849250602090611b4861140c6144cd976103e9565b825260049082905afa928315610aa0576144aa6144b19461140c936102bb9760009261450c575b50610dec6145019161031b565b149395505092614494565b61450191925061452c610dec9160203d8111610a9957610a9181836109c3565b9291506144f4565b61454c915060203d8111610a9957610a9181836109c3565b38614475565b61455c915061031b565b6145658561031b565b141538614431565b906102bb916142c5565b9092907f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee816145b973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61031b565b6145c28361031b565b036147f357614603916145d4306103e9565b6145fd7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b91610aff565b60009261460f84610c38565b8111614701575b5061462083610c38565b821161462d575b50505050565b61465961140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b926340c10f193394803b156102b257614677918391610a5460405190565b825281838161468a8a8c60048401610f6a565b03925af18015610aa0576146e4575b50506146d86146ae6040612fa9602088015190565b612fd97fe79d2400774c9ceba50645590d91414af42f277c27641bd9cba2f5b92db83ad5956103e9565b0390a238808080614627565b816146fa92903d106138bb576138ad81836109c3565b3880614699565b61472d61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b61473d60206340c10f1933612ee6565b8252818981614750898960048401610f6a565b03925af1908115610aa0576000916147d5575b5061477a61375a8261477560076113b0565b61480f565b6020870151926147cc61478e60408a015190565b6147b87f63c3f185975ecdfdf59dfa778ff2ddbfe5a3f930ccc104a7b4f6d9f882fde93c956103e9565b956147c260405190565b94859489866128ca565b0390a238614616565b6147ed915060203d81116114805761147881836109c3565b38614763565b6147fd91336145d4565b614603565b9190820180921161157557565b6103279190614802565b6080818303126102b25761482d82826113ba565b9261032761483e84602085016113ba565b9361484c81604086016113ba565b936060016113ba565b9081526060810193926102bb92909160409161090f906020830152565b9192916148dc91906080614885306103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e49526136e063d4ff72d87f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f879339788966148cf60405190565b998a968795869560e01b90565b03915af4948515610aa05760008080809196909298614f73575b506149207f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b63d9caed129133977f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee94833b156102b2578b6000878c61497c61496260405190565b94859384936149718d60e01b90565b855260048501610fcd565b038183895af18015610aa057614f5d575b5060009761499a89610c38565b8311614ea7575b506149bc91506149b59061477560046113b0565b60046117db565b6149c660046113b0565b6149d2610e5a88610c38565b1180614e4b575b614d53575b6149ef6149f69161477560056113b0565b60056117db565b614a0060056113b0565b614a0c610e5a87610c38565b1180614ce8575b614bf9575b505050614a2482610c38565b8111614b29575b50614a3581610c38565b8411614a43575b5050505090565b614a6f61140c7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6103e9565b639dc29fac90803b156102b257614a8b918391610a5460405190565b8252818381614a9e8b8b60048401610f6a565b03925af18015610aa057614b0c575b5050614abf6040612ab7602084015190565b92614b00614aed7f3b931001c0728420650d0922e385dcd2dbcf634aee98dc541642fe27358da458946103e9565b94614af760405190565b93849384614855565b0390a238808080614a3c565b81614b2292903d106138bb576138ad81836109c3565b3880614aad565b614b6a906020614b5b61140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b639dc29fac90611bb460405190565b8252818681614b7d878c60048401610f6a565b03925af1918215610aa057600092614bd9575b50614ba261375a8361375560076113b0565b602084015191614bb3604086015190565b91614bd0600080516020615f0b83398151915293612fd9896103e9565b0390a238614a2b565b614bf291925060203d81116114805761147881836109c3565b9038614b90565b614c0661140c60026117fb565b90614c1160056113b0565b92813b156102b2578661497191614c398296614c2c60405190565b9889978896879560e01b90565b03925af18015610aa057614ccc575b50614c5661140c60026117fb565b631b2a1914614c6560056113b0565b823b156102b257614c8c9261143b868094614c7f60405190565b9687958694859360e01b90565b03925af18015610aa057614cb0575b50614ca86149ef83610c38565b388080614a18565b614cc690833d85116138bb576138ad81836109c3565b38614c9b565b614ce290833d85116138bb576138ad81836109c3565b38614c48565b50614d0a6020614cfb61140c60026117fb565b6370c6a17e90610a5460405190565b825260049082905afa908115610aa057600091614d35575b50614d2f610e5a87610c38565b11614a13565b614d4d915060203d81116114805761147881836109c3565b38614d22565b614d6061140c6001611879565b614d6a60046113b0565b90833b156102b257858891614d90614d8160405190565b94859384936149718b60e01b90565b038183875af18015610aa057614e2f575b50614daf61140c6001611879565b906339db85c5614dbf60046113b0565b833b156102b257614de69361143b8a8094614dd960405190565b9788958694859360e01b90565b03925af1908115610aa0576149f6926149ef92614e13575b50614e0b6149b589610c38565b9150506149de565b614e2990893d8b116138bb576138ad81836109c3565b38614dfe565b614e4590873d89116138bb576138ad81836109c3565b38614da1565b50614e5e6020614cfb61140c6001611879565b825260049082905afa908115610aa057600091614e89575b50614e83610e5a88610c38565b116149d9565b614ea1915060203d81116114805761147881836109c3565b38614e76565b6020614eb5614ec4926103e9565b6361d027b390610a5460405190565b825260049082905afa908115610aa057600091614f3f575b50843b156102b257868991614f02614ef360405190565b95869384936149718c60e01b90565b038183885af1908115610aa0576149bc926149b592614f23575b50906149a1565b614f39908a3d8c116138bb576138ad81836109c3565b38614f1c565b614f57915060203d8111610a9957610a9181836109c3565b38614edc565b614f6d9060006138ad81836109c3565b3861498d565b9295505050614f9a91955060803d8111614fa6575b614f9281836109c3565b810190614819565b389793979592956148f6565b503d614f88565b6119536102bb94614fd9606094989795614fcf608086019a60008701906103f2565b60208501906103f2565b604083019061032a565b614fec306103e9565b7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933906150669073b5ecfd108619fb8e7c65658b9419f81ea62e495263fae31b3060206150577f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b632e20712190611b4c60405190565b825260049082905afa908115610aa0576150b96150ae926101e0966000916152df575b5061509761140c6001611879565b906150a160405190565b9889978896879660e01b90565b865260048601614fad565b03915af4908115610aa0576000809190926152be575b506000916150dc83610c38565b8214611c8257604081019061511160206151006150fa611b94865190565b86612420565b92019161510b835190565b90615322565b9261513b7f000000000000000000000000dc3985196d263e5259ab946a4b52cedcbadc13906103e9565b63d9caed1261514d61140c6001611879565b7f000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92803b156102b2576149718980946151898b614c2c60405190565b03925af18015610aa0576152a2575b508060206151c861140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b639dc29fac9061168e896151df61140c6001611879565b936151f96151ec60405190565b9889968795869460e01b90565b03925af1918215610aa057600092615282575b5061521e61375a8361375560076113b0565b61525161523961523461523461140c6001611879565b955190565b612fd9600080516020615f0b833981519152956103e9565b0390a261526161140c6001611879565b906392a1594290823b156102b257613c159261143b858094614c7f60405190565b61529b91925060203d81116114805761147881836109c3565b903861520c565b6152b890863d88116138bb576138ad81836109c3565b38615198565b90506152d991506101e03d81116125ae5761259f81836109c3565b386150cf565b6152f7915060203d8111610a9957610a9181836109c3565b38615089565b634e487b7160e01b600052601260045260246000fd5b811561531d570490565b6152fd565b6103279190615313565b6040906119536102bb94969593966135d0606084019860008501906103f2565b615355306103e9565b7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933906101e09073b5ecfd108619fb8e7c65658b9419f81ea62e49526153b8632582105d6153c36153a861140c60026117fb565b6040519788968795869560e01b90565b85526004850161532c565b03915af48015610aa0576000918291615503575b506000916153e483610c38565b8114611c8257602082019161541360406154056153ff865190565b85612420565b92019161510b611b94845190565b9283602061544361140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b6340c10f199061168e8961545a61140c60026117fb565b9361547461546760405190565b9b8c968795869460e01b90565b03925af1948515610aa0576000956154e3575b50849061549b61375a8361477560076113b0565b6154a861478e6152343381565b0390a26154b861140c60026117fb565b90634445f73091803b156102b2576154d8858094613c15611d6e60405190565b8452600484016108fc565b6154fc91955060203d81116114805761147881836109c3565b9338615487565b905061551e91506101e03d81116125ae5761259f81836109c3565b90386153d7565b91906040838203126102b2576103279061553f81856113ba565b936020016113ba565b61090f6102bb94612ea7606094989795614fcf608086019a60008701906103f2565b6040810192916102bb9160209161558290829061032a565b017f507479506f6f6c4275794c6f774d617267696e5969656c6473526174650000009052565b615625903060406155b8826103e9565b73b5ecfd108619fb8e7c65658b9419f81ea62e495261561a636937938b7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f8793397889761560360096113b0565b9061560d60405190565b998a978896879660e01b90565b865260048601615548565b03915af4928315610aa057600080939094615ba0575b50600061564781610c38565b85119283615b19575b61565982610c38565b85119283615a13575b5061566d60036113b0565b615679610e5a84610c38565b11806159b7575b615893575b61568f60066113b0565b61569b610e5a84610c38565b1180615837575b6156ef575b505081156156e7575b506156b9575050565b7f55de42fd7838b64e6e196dc82f1aa2e87ad5c13ea8fc85ab51095bad26b754ab91613ffb61093860405190565b9050386156b0565b7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d61571c61140c826103e9565b9161572b6340c10f19916103e9565b9061573660066113b0565b843b156102b2576157699461575d87809461575060405190565b9889958694859360e01b90565b83528860048401610f6a565b03925af1928315610aa05761579c9361581b575b5061578b61140c60026117fb565b9061579660066113b0565b92610aff565b6157a961140c60026117fb565b906339db85c56157b960066113b0565b833b156102b2576157d39361143b848094614dd960405190565b03925af1908115610aa0576157f8926157f1926157ff575b50610c38565b60066117db565b38806156a7565b61581590823d84116138bb576138ad81836109c3565b386157eb565b61583190853d87116138bb576138ad81836109c3565b3861577d565b5061584a6020614cfb61140c60026117fb565b825260049082905afa908115610aa057600091615875575b5061586f610e5a84610c38565b116156a2565b61588d915060203d81116114805761147881836109c3565b38615862565b7f0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d6158c061140c826103e9565b906340c10f196158cf846103e9565b906158da60036113b0565b843b156102b2576158f49461575d88809461575060405190565b03925af1928315610aa0576159219361599b575b5061591661140c6001611879565b9061579660036113b0565b61592e61140c6001611879565b631b2a191461593d60036113b0565b823b156102b2576159579261143b868094614c7f60405190565b03925af18015610aa05761597f575b5061597a61597383610c38565b60036117db565b615685565b61599590833d85116138bb576138ad81836109c3565b38615966565b6159b190863d88116138bb576138ad81836109c3565b38615908565b506159ca6020614cfb61140c6001611879565b825260049082905afa908115610aa0576000916159f5575b506159ef610e5a84610c38565b11615680565b615a0d915060203d81116114805761147881836109c3565b386159e2565b615a1c906103e9565b635bec50be906020615a48615a30856103e9565b93615a53615a3d60405190565b958693849360e01b90565b83526004830161556a565b0381845afa8015610aa057615a77602091615a8794600091615afc575b5089612420565b9163313ce56790611bb460405190565b825260049082905afa918215610aa057615ab76157f19261510b615ad895615ace94600091615ade575b506118d7565b615ac86159738261477560036113b0565b8861157a565b61477560066113b0565b38615662565b615af6915060203d81116114805761147881836109c3565b38615ab1565b615b139150833d81116114805761147881836109c3565b38615a70565b615b4561140c7f000000000000000000000000d86b2b6f1169e4304be700d6522c3ff79ff8fb776103e9565b63bc4f2d6d90803b156102b257615b61918491610a5460405190565b8252600482018a9052602490829084905af18015610aa057615b84575b50615650565b615b9a90833d85116138bb576138ad81836109c3565b38615b7e565b909350615bc591925060403d8111615bce575b615bbd81836109c3565b810190615525565b9190923861563b565b503d615bb3565b90615bdf306103e9565b91608073b5ecfd108619fb8e7c65658b9419f81ea62e49529363b18da4fd94615c2f7f0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f8793396615c3a612f5b60405190565b84526004840161184b565b03915af48015610aa057600093849182918291615d85575b505b841115615cd3575050615c69600360086117b6565b615c7d615c766000610c38565b600b6117db565b8281101580615cca575b15615c9a575050506102bb42600c6117db565b82119182615cbf575b5050615cab57565b6102bb615cb86000610c38565b600c6117db565b915010153880615ca3565b50828210615c87565b80841015615d0257615cec9150610327600260086117b6565b8110615c7d57615cfd42600b6117db565b615c7d565b508082109081615d7a575b8115615d5d575b5015615c7d57615d24600861134e565b600190615d33611976836108a9565b03615d3f575b50615c7d565b615d4a9060086117b6565b615d57615c766000610c38565b38615d39565b808311915081615d6f575b5038615d14565b905082111538615d68565b808410159150615d0d565b915050615c549450615da5915060803d8111614fa657614f9281836109c3565b95615c52565b6116da90615db76123d0565b3390615de76020610a457f00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b6103e9565b825260049082905afa928315610aa057613f87610dec6102bb95615e1294600091613f95575061031b565b615e396102bb9161140c615e29610b1f6000610b95565b615e328361031b565b1415614333565b600d6143ee565b6102bb90615dab565b615e6b906020615e5c61140c600d6117fb565b63a3e6ba9490611bb460405190565b825260049082905afa8015610aa057615ea592600091615eec575b506020615e9661140c600d6117fb565b63313ce5679061348660405190565b825260049082905afa928315610aa057600093615ec8575b5061032790926118c7565b610327919350615ee59060203d81116116245761161c81836109c3565b9290615ebd565b615f04915060203d81116114805761147881836109c3565b38615e8656fe8331e6d9453e2cdb4da24bdc7337453d7324ddf71d1cb7949834baea5de4ba43a2646970667358221220af4f5be994e67a93537866ca0975c5ec1087f2d9e07fa67979a0670801ad170f64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d000000000000000000000000b0cc02228cbbacad1b8350dd24bd335ed6ba54bf
-----Decoded View---------------
Arg [0] : _wandProtocol (address): 0x31e9026bf3A20FA3250a94caD5E6BFbE203B001B
Arg [1] : _settings (address): 0x7449dc43a03e70050c4AcD3F8A6acab9A7F87933
Arg [2] : _assetToken_ (address): 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
Arg [3] : _marginToken_ (address): 0x5A7651Dd5C9d72fc4FDD4f9706193F33DFb4122d
Arg [4] : _assetTokenPriceFeed_ (address): 0xb0cC02228CbbacaD1b8350dD24bD335eD6ba54bf
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000031e9026bf3a20fa3250a94cad5e6bfbe203b001b
Arg [1] : 0000000000000000000000007449dc43a03e70050c4acd3f8a6acab9a7f87933
Arg [2] : 000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
Arg [3] : 0000000000000000000000005a7651dd5c9d72fc4fdd4f9706193f33dfb4122d
Arg [4] : 000000000000000000000000b0cc02228cbbacad1b8350dd24bd335ed6ba54bf
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.