Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Manager
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
No with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {Access} from "../administrator/Access.sol";
import {Common} from "../libs/Common.sol";
import {Constants} from "../libs/Constants.sol";
import {Codec, OrderPayload} from "../libs/Codec.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {IMinter} from "./interface/IMinter.sol";
import {IRole} from "../administrator/interface/IRole.sol";
event Deposit(address indexed caller, address indexed asset, uint256 amount, address indexed receiver, uint256 yAmount);
interface ISToken {
function withdrawRequest(address asset, uint256 sAmount, address receiver, address owner) external;
}
contract Manager is Access {
address public sToken;
address public yToken;
address public treasury;
bool public isVault;
mapping(address => bool) public assets;
mapping(bytes32 => bool) public usedProofs;
uint256[26] __gap;
using SafeERC20 for IERC20;
function init(address _administrator) public initializer {
__Access_init(_administrator);
}
function setTokens(
address _sToken,
address _yToken,
bool _isVault
) public onlyAdmin {
require(
Common.isContract(_sToken) && Common.isContract(_yToken),
"!token"
);
sToken = _sToken;
yToken = _yToken;
isVault = _isVault;
if (_isVault) {
IERC20(_sToken).forceApprove(_yToken, type(uint256).max);
}
}
function setAsset(address asset, bool status) public onlyAdmin {
require(Common.isContract(asset), "!asset");
assets[asset] = status;
}
function setTreasury(address _treasury) public onlyAdmin {
require(_treasury != address(0), "!treasury");
treasury = _treasury;
}
function _transferFee(
uint256 amount,
uint256 fee,
address owner
) internal returns (uint256) {
if (fee == 0) {
return amount;
}
uint256 feeAmount = (amount * fee)/ Constants.HUNDRED_PERCENT;
if (owner == address(this)) {
IERC20(yToken).safeTransfer(treasury, feeAmount);
} else {
IERC20(yToken).safeTransferFrom(owner, treasury, feeAmount);
}
return amount - feeAmount;
}
function _validate (bytes calldata _data, bytes memory _sign) internal {
address signer = ECDSA.recover(
keccak256(
abi.encodePacked(Constants.ETH_SIGNED_MESSAGE_PREFIX, keccak256(_data))
),
_sign
);
if (!IRole(administrator).hasRole(Constants.SIGNER_ROLE, signer)) {
revert Common.SignatureVerificationFailed();
}
usedProofs[keccak256(_data)] = true;
}
function deposit(bytes calldata _data, bytes memory _sign) external notPaused nonReentrant {
_validate(_data, _sign);
OrderPayload memory payload = Codec.decodeOrderPayload(_data);
require(assets[payload.token] && Common.isContract(sToken) , "!token");
require(payload.trxnType == Constants.DEPOSIT || payload.trxnType == Constants.DEPOSIT_L2, "!trxnType");
IERC20(payload.token).safeTransferFrom(msg.sender, sToken, payload.amount);
uint256 shares;
if (isVault) {
IMinter(sToken).mint(address(this), payload.sAmount);
shares = IERC4626(yToken).deposit(payload.sAmount, address(this)); // transfer shares to this address
} else {
shares = (payload.sAmount * Constants.PINT) / payload.sharePrice;
IMinter(yToken).mint(address(this), shares);
emit Deposit(msg.sender, payload.token, payload.amount, payload.receiver, shares);
}
uint256 balance = _transferFee(shares, payload.fee, address(this));
IERC20(yToken).safeTransfer(payload.receiver, balance);
}
function withdraw(bytes calldata _data, bytes memory _sign) external notPaused nonReentrant {
_validate(_data, _sign);
OrderPayload memory payload = Codec.decodeOrderPayload(_data);
require(assets[payload.token] && Common.isContract(sToken) , "!token");
require(payload.trxnType == Constants.WITHDRAW || payload.trxnType == Constants.WITHDRAW_L2, "!trxnType");
uint256 amount = _transferFee(payload.amount, payload.fee, msg.sender);
uint256 sAmount;
if (isVault) {
sAmount = IERC4626(yToken).redeem(amount, address(this), msg.sender); //sUSD is part of this address
} else {
sAmount = (amount * payload.sharePrice) / Constants.PINT;
IMinter(yToken).burn(msg.sender, amount);
IMinter(sToken).mint(address(this), sAmount);
}
ISToken(sToken).withdrawRequest(payload.token, sAmount, payload.receiver, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ReentrancyGuardUpgradeable is Initializable {
// 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;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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 {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// 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) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {Common} from "../libs/Common.sol";
import {Constants} from "../libs/Constants.sol";
import {IBlackList} from "./interface/IBlackList.sol";
import {IPausable} from "./interface/IPausable.sol";
import {IRole} from "./interface/IRole.sol";
// To define all the access modifiers
abstract contract Access is ReentrancyGuardUpgradeable {
address public administrator;
function __Access_init(address _administrator) internal onlyInitializing {
__ReentrancyGuard_init();
require(_administrator != address(0), "!administrator");
administrator = _administrator;
}
modifier onlyAdmin() {
require(
IRole(administrator).hasRole(Constants.ADMIN_ROLE, msg.sender),
"!admin"
);
_;
}
modifier onlyCollateralManager() {
require(
IRole(administrator).hasRole(
Constants.COLLATERAL_MANAGER_ROLE,
msg.sender
),
"!cmgr"
);
_;
}
modifier onlyBridge() {
require(
IRole(administrator).hasRole(Constants.BRIDGE_ROLE, msg.sender),
"!bridge"
);
_;
}
modifier onlyManager() {
require(
IRole(administrator).hasRole(Constants.MANAGER_ROLE, msg.sender),
"!manager"
);
_;
}
modifier onlyMinterAndRedeemer() {
require(IRole(administrator).hasRole(Constants.MINTER_AND_REDEEMER_ROLE, msg.sender),
"!minter"
);
_;
}
modifier onlyRewarder() {
require(
IRole(administrator).hasRole(Constants.REWARDER_ROLE, msg.sender),
"!rewarder"
);
_;
}
modifier notPaused() {
require(!IPausable(administrator).isPaused(address(this)), "paused");
_;
}
modifier notBlacklisted(address user) {
require(!IBlackList(administrator).isBlackListed(user), "blacklisted");
_;
}
function setAdministrator(address _administrator) external onlyAdmin {
require(Common.isContract(_administrator), "!contract");
administrator = _administrator;
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IBlackList {
//functions
function blackListUsers(address[] calldata _users) external;
function removeBlackListUsers(address[] calldata _clearedUsers) external;
function isBlackListed(address _user) external view returns (bool);
//events
event BlackListed(address indexed _sender, address indexed _user);
event BlackListCleared(address indexed _sender, address indexed _user);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IPausable {
function pause() external;
function unpause() external;
function pauseSC(address _sc) external;
function unpauseSC(address _sc) external;
function isPaused(address _sc) external view returns (bool);
//events
event Paused(address indexed _sender);
event Unpaused(address indexed _sender);
event Paused(address indexed _sender, address indexed _sc);
event Unpaused(address indexed _sender, address indexed _sc);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IRole {
//functions
function grantRoles(bytes32 _role, address[] calldata _accounts) external;
function revokeRoles(bytes32 _role, address[] calldata _accounts) external;
function hasRole(bytes32 _role, address _account) external view returns (bool);
function hasRoles(bytes32[] calldata _role, address[] calldata _accounts) external view returns (bool[] memory);
//events
event RoleGranted(bytes32 indexed _role, address indexed _sender, address indexed _account);
event RoleRevoked(bytes32 indexed _role, address indexed _sender, address indexed _account);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IMinter {
//functions
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
//events
event Mint(address indexed _minter, address indexed _to, uint256 _amount);
event Burn(address indexed _minter, address indexed _from, uint256 _amount);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
import {Common} from "./Common.sol";
import {Constants} from "./Constants.sol";
struct RewardPayload {
address receiver;
uint256 amount;
uint256 epoch;
uint256 rewardType;
}
struct BridgeSendPayload {
uint32 dstId;
address to;
address token;
uint256 amount;
bytes32 trxnType;
}
struct OrderPayload {
address token;
address receiver; // who is gonna get yUSD
uint256 amount; // for deposit it is asset / shares order withdraw
uint256 sharePrice; // share price for yUSD only used in L2 chains
uint256 sAmount; // price for converting token to sUSD value
uint256 fee; // % represented in 1/Constants.HUNDERED_PERCENT
uint256 deadline;
bytes32 trxnType;
}
error WrongDataLength();
error WrongAddressEncoding();
error WrongData();
library Codec {
uint256 internal constant DATA_LENGTH = 32 * 5;
uint256 internal constant ORDER_DATA_LENGTH = 32 * 8;
function decodeReward(
bytes calldata _data
) internal view returns (RewardPayload memory) {
if (_data.length != DATA_LENGTH) {
revert WrongDataLength();
}
(
address receiver,
uint256 amount,
uint256 epoch,
uint256 rewardType,
bytes32 trxnType
) = abi.decode(_data, (address, uint256, uint256, uint256, bytes32));
if (trxnType != Constants.REWARD_HASH) {
revert WrongData();
}
if (receiver == address(0) || !Common.isContract(receiver)) {
revert WrongAddressEncoding();
}
if (amount == 0 || epoch < 1 || rewardType >= 2) {
revert WrongData();
}
return RewardPayload(receiver, amount, epoch, rewardType);
}
function decodeBridgeSendPayload(
bytes calldata _data
) internal view returns (BridgeSendPayload memory) {
if (_data.length != DATA_LENGTH) {
revert WrongDataLength();
}
(
uint32 dstId,
address to,
address token,
uint256 amount,
bytes32 trxnType
) = abi.decode(_data, (uint32, address, address, uint256, bytes32));
if (trxnType != Constants.BRIDGE_SEND_HASH) {
revert WrongData();
}
if (dstId == 0 ) {
revert WrongData();
}
if (to == address(0)) {
revert WrongAddressEncoding();
}
if (token == address(0) || !Common.isContract(token)) {
revert WrongAddressEncoding();
}
if (amount == 0) {
revert WrongData();
}
return BridgeSendPayload(dstId, to, token, amount, trxnType);
}
function _validate(bytes32 trxn, address receiver, uint256 amount, uint256 sharePrice, uint256 sAmount, uint256 deadline) internal view {
if (receiver == address(0) || amount == 0 || deadline == 0) {
revert WrongData();
}
if (trxn == Constants.DEPOSIT) {
if (sAmount == 0) revert WrongData();
}
if (trxn == Constants.DEPOSIT_L2 ) {
if (sAmount == 0 || sharePrice == 0) revert WrongData();
}
if (trxn == Constants.WITHDRAW_L2 ) {
if (sharePrice == 0) revert WrongData();
}
require(block.timestamp < deadline, "!deadline");
}
function decodeOrderPayload(bytes calldata _data) internal view returns (OrderPayload memory) {
if (_data.length != ORDER_DATA_LENGTH) {
revert WrongDataLength();
}
(
address token,
address receiver,
uint256 amount,
uint256 sharePrice,
uint256 sAmount,
uint256 fee,
uint256 deadline,
bytes32 trxnType
) = abi.decode(_data, (address, address, uint256, uint256, uint256, uint256, uint256, bytes32));
_validate(trxnType, receiver, amount, sharePrice, sAmount, deadline);
if (token == address(0) || !Common.isContract(token)) {
revert WrongAddressEncoding();
}
return OrderPayload(token, receiver, amount, sharePrice, sAmount, fee, deadline, trxnType);
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
library Common {
error SignatureVerificationFailed();
error BadSignature();
function isContract(address _addr) internal view returns (bool) {
return _addr != address(0) && _addr.code.length != 0 ;
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
library Constants {
// admin role
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");
// role for minting and redeeming tokens
bytes32 public constant MINTER_AND_REDEEMER_ROLE = keccak256("MINTER_AND_REDEEMER");
// role for collateral manager who can transfer collateral
bytes32 public constant COLLATERAL_MANAGER_ROLE = keccak256("COLLATERAL_MANAGER");
// role for rewarder who can transfer reward
bytes32 public constant REWARDER_ROLE = keccak256("REWARDER");
// role for managing blacklist addresses
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER");
// role for signing transactions
bytes32 public constant SIGNER_ROLE = keccak256("SIGNER");
// role assigned to bridges
bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE");
uint256 constant PINT = 1e18;
uint256 constant HUNDRED_PERCENT = 100e18;
// Period for vesting strategy rewards
uint256 constant VESTING_PERIOD = 8 hours;
// max cooling period
uint256 constant MAX_COOLDOWN_PERIOD = 7 days;
// min cooling period
uint256 constant MIN_COOLDOWN_PERIOD = 1 days;
// ETH Sign Constant
bytes constant ETH_SIGNED_MESSAGE_PREFIX = "\x19Ethereum Signed Message:\n32";
// Transaction types
bytes32 public constant REWARD_HASH = keccak256("REWARD");
// Bridge transaction types
bytes32 public constant BRIDGE_SEND_HASH = keccak256("BRIDGE_SEND");
// RFQ transaction
bytes32 public constant DEPOSIT = keccak256("DEPOSIT");
bytes32 public constant WITHDRAW = keccak256("WITHDRAW");
bytes32 public constant DEPOSIT_L2 = keccak256("DEPOSIT_L2");
bytes32 public constant WITHDRAW_L2 = keccak256("WITHDRAW_L2");
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SignatureVerificationFailed","type":"error"},{"inputs":[],"name":"WrongAddressEncoding","type":"error"},{"inputs":[],"name":"WrongData","type":"error"},{"inputs":[],"name":"WrongDataLength","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"yAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"administrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_sign","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_administrator","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isVault","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_administrator","type":"address"}],"name":"setAdministrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sToken","type":"address"},{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"bool","name":"_isVault","type":"bool"}],"name":"setTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"usedProofs","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_sign","type":"bytes"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b506137a5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639ebdf12c1161008c578063e81cc3cc11610066578063e81cc3cc14610221578063f0f442601461023f578063f11b81881461025b578063f53d0a8e1461028b576100ea565b80639ebdf12c146101b7578063c30a0f25146101d5578063df8089ef14610205576100ea565b806350fbe2d9116100c857806350fbe2d91461014557806361d027b314610161578063859a4f071461017f57806389fc437c1461019b576100ea565b8063164af1df146100ef57806319ab453c1461010b57806349bfcca114610127575b600080fd5b61010960048036038101906101049190612a34565b6102a9565b005b61012560048036038101906101209190612b0e565b61085e565b005b61012f6109ed565b60405161013c9190612b4a565b60405180910390f35b61015f600480360381019061015a9190612a34565b610a13565b005b610169610f2b565b6040516101769190612b4a565b60405180910390f35b61019960048036038101906101949190612b9d565b610f51565b005b6101b560048036038101906101b09190612bf0565b611198565b005b6101bf611336565b6040516101cc9190612b4a565b60405180910390f35b6101ef60048036038101906101ea9190612c66565b61135c565b6040516101fc9190612ca2565b60405180910390f35b61021f600480360381019061021a9190612b0e565b61137c565b005b610229611502565b6040516102369190612ca2565b60405180910390f35b61025960048036038101906102549190612b0e565b611515565b005b61027560048036038101906102709190612b0e565b6116c3565b6040516102829190612ca2565b60405180910390f35b6102936116e3565b6040516102a09190612b4a565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635b14f183306040518263ffffffff1660e01b81526004016103029190612b4a565b602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103439190612cd2565b15610383576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037a90612d5c565b60405180910390fd5b61038b611707565b61039683838361175e565b60006103a2848461191b565b905060046000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680156104285750610427600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611a88565b5b610467576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161045e90612dc8565b60405180910390fd5b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8218160e0015114806104bc57507f175edc95deb431c7abe19847bac40d41948fd28714d8af8c93fed89eaae248c88160e00151145b6104fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f290612e34565b60405180910390fd5b61055233600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168360400151846000015173ffffffffffffffffffffffffffffffffffffffff16611ae5909392919063ffffffff16565b6000600360149054906101000a900460ff16156106a757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f193084608001516040518363ffffffff1660e01b81526004016105ca929190612e6d565b600060405180830381600087803b1580156105e457600080fd5b505af11580156105f8573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e553f658360800151306040518363ffffffff1660e01b815260040161065d929190612e96565b6020604051808303816000875af115801561067c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a09190612eeb565b90506107ea565b8160600151670de0b6b3a764000083608001516106c49190612f47565b6106ce9190612fb8565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930836040518363ffffffff1660e01b815260040161072d929190612e6d565b600060405180830381600087803b15801561074757600080fd5b505af115801561075b573d6000803e3d6000fd5b50505050816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167faaefaf378e10f40556b2167ea878af7e62d89229b0bce3924630aabf1ee611ff8560400151856040516107e1929190612fe9565b60405180910390a45b60006107fb828460a0015130611b67565b905061084e836020015182600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ccc9092919063ffffffff16565b505050610859611d4b565b505050565b6000610868611d64565b905060008160000160089054906101000a900460ff1615905060008260000160009054906101000a900467ffffffffffffffff1690506000808267ffffffffffffffff161480156108b65750825b9050600060018367ffffffffffffffff161480156108eb575060003073ffffffffffffffffffffffffffffffffffffffff163b145b9050811580156108f9575080155b15610930576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018560000160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083156109805760018560000160086101000a81548160ff0219169083151502179055505b61098986611d8c565b83156109e55760008560000160086101000a81548160ff0219169083151502179055507fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260016040516109dc919061306b565b60405180910390a15b505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635b14f183306040518263ffffffff1660e01b8152600401610a6c9190612b4a565b602060405180830381865afa158015610a89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aad9190612cd2565b15610aed576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ae490612d5c565b60405180910390fd5b610af5611707565b610b0083838361175e565b6000610b0c848461191b565b905060046000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff168015610b925750610b91600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611a88565b5b610bd1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc890612dc8565b60405180910390fd5b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828698160e001511480610c2657507fec28eada7e4093a2d13c92d33b727848291ee15a6bbbffdd27f55acfa28f8aaa8160e00151145b610c65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5c90612e34565b60405180910390fd5b6000610c7a82604001518360a0015133611b67565b90506000600360149054906101000a900460ff1615610d3c57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ba0876528330336040518463ffffffff1660e01b8152600401610cf293929190613086565b6020604051808303816000875af1158015610d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d359190612eeb565b9050610e80565b670de0b6b3a7640000836060015183610d559190612f47565b610d5f9190612fb8565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33846040518363ffffffff1660e01b8152600401610dbe929190612e6d565b600060405180830381600087803b158015610dd857600080fd5b505af1158015610dec573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930836040518363ffffffff1660e01b8152600401610e4d929190612e6d565b600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b505050505b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663029d375c8460000151838660200151306040518563ffffffff1660e01b8152600401610ee994939291906130bd565b600060405180830381600087803b158015610f0357600080fd5b505af1158015610f17573d6000803e3d6000fd5b50505050505050610f26611d4b565b505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401610fcc929190613111565b602060405180830381865afa158015610fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100d9190612cd2565b61104c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104390613186565b60405180910390fd5b61105583611a88565b8015611066575061106582611a88565b5b6110a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161109c90612dc8565b60405180910390fd5b82600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600360146101000a81548160ff021916908315150217905550801561119357611192827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8573ffffffffffffffffffffffffffffffffffffffff16611e4e9092919063ffffffff16565b5b505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401611213929190613111565b602060405180830381865afa158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112549190612cd2565b611293576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128a90613186565b60405180910390fd5b61129c82611a88565b6112db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d2906131f2565b60405180910390fd5b80600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60056020528060005260406000206000915054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b81526004016113f7929190613111565b602060405180830381865afa158015611414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114389190612cd2565b611477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161146e90613186565b60405180910390fd5b61148081611a88565b6114bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b69061325e565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600360149054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401611590929190613111565b602060405180830381865afa1580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d19190612cd2565b611610576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161160790613186565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361167f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611676906132ca565b60405180910390fd5b80600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60046020528060005260406000206000915054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611711611f5d565b90506002816000015403611751576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002816000018190555050565b60006117de6040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525085856040516117a992919061331a565b60405180910390206040516020016117c29291906133ba565b6040516020818303038152906040528051906020012083611f85565b905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547f2aeb38be3df14d720aeb10a2de6df09b0fb3cd5c5ec256283a22d4593110ca40836040518363ffffffff1660e01b815260040161185b929190613111565b602060405180830381865afa158015611878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189c9190612cd2565b6118d2576040517f729d0f6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016005600086866040516118e892919061331a565b6040518091039020815260200190815260200160002060006101000a81548160ff02191690831515021790555050505050565b611923612806565b6101008383905014611961576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806000806000808a8a81019061197c9190613435565b9750975097509750975097509750975061199a818888888887611fb1565b600073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614806119db57506119d988611a88565b155b15611a12576040517f8278a71400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518061010001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff168152602001878152602001868152602001858152602001848152602001838152602001828152509850505050505050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611ade575060008273ffffffffffffffffffffffffffffffffffffffff163b14155b9050919050565b611b61848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401611b1a939291906134eb565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b50505050565b6000808303611b7857839050611cc5565b600068056bc75e2d631000008486611b909190612f47565b611b9a9190612fb8565b90503073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611c4357611c3e600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ccc9092919063ffffffff16565b611cb5565b611cb483600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ae5909392919063ffffffff16565b5b8085611cc19190613522565b9150505b9392505050565b611d46838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401611cff929190612e6d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b505050565b6000611d55611f5d565b90506001816000018190555050565b60007ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00905090565b611d94612241565b611d9c612281565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611e0b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e02906135a2565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008373ffffffffffffffffffffffffffffffffffffffff1663095ea7b38484604051602401611e7f929190612e6d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050611ecd8482612293565b611f5757611f4c848573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3866000604051602401611f059291906135fd565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b611f5684826121aa565b5b50505050565b60007f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00905090565b600080600080611f95868661235a565b925092509250611fa582826123b6565b82935050505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611fec5750600084145b80611ff75750600081145b1561202e576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8218603612090576000820361208f576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b7f175edc95deb431c7abe19847bac40d41948fd28714d8af8c93fed89eaae248c886036120fe5760008214806120c65750600083145b156120fd576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b7fec28eada7e4093a2d13c92d33b727848291ee15a6bbbffdd27f55acfa28f8aaa8603612160576000830361215f576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b8042106121a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219990613672565b60405180910390fd5b505050505050565b60006121d5828473ffffffffffffffffffffffffffffffffffffffff1661251a90919063ffffffff16565b905060008151141580156121fa5750808060200190518101906121f89190612cd2565b155b1561223c57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016122339190612b4a565b60405180910390fd5b505050565b612249612530565b61227f576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b612289612241565b612291612550565b565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516122bd9190613692565b6000604051808303816000865af19150503d80600081146122fa576040519150601f19603f3d011682016040523d82523d6000602084013e6122ff565b606091505b509150915081801561232d575060008151148061232c57508080602001905181019061232b9190612cd2565b5b5b8015612350575060008573ffffffffffffffffffffffffffffffffffffffff163b115b9250505092915050565b6000806000604184510361239f5760008060006020870151925060408701519150606087015160001a905061239188828585612571565b9550955095505050506123af565b60006002855160001b9250925092505b9250925092565b600060038111156123ca576123c96136a9565b5b8260038111156123dd576123dc6136a9565b5b031561251657600160038111156123f7576123f66136a9565b5b82600381111561240a576124096136a9565b5b03612441576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612455576124546136a9565b5b826003811115612468576124676136a9565b5b036124ad578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016124a491906136d8565b60405180910390fd5b6003808111156124c0576124bf6136a9565b5b8260038111156124d3576124d26136a9565b5b0361251557806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161250c91906136f3565b60405180910390fd5b5b5050565b606061252883836000612665565b905092915050565b600061253a611d64565b60000160089054906101000a900460ff16905090565b612558612241565b6000612562611f5d565b90506001816000018190555050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c11156125b157600060038592509250925061265b565b6000600188888888604051600081526020016040526040516125d6949392919061372a565b6020604051602081039080840390855afa1580156125f8573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361264c57600060016000801b9350935093505061265b565b8060008060001b935093509350505b9450945094915050565b6060814710156126ac57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016126a39190612b4a565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff1684866040516126d59190613692565b60006040518083038185875af1925050503d8060008114612712576040519150601f19603f3d011682016040523d82523d6000602084013e612717565b606091505b5091509150612727868383612732565b925050509392505050565b60608261274757612742826127c1565b6127b9565b6000825114801561276f575060008473ffffffffffffffffffffffffffffffffffffffff163b145b156127b157836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016127a89190612b4a565b60405180910390fd5b8190506127ba565b5b9392505050565b6000815111156127d45780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600080191681525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126128b3576128b261288e565b5b8235905067ffffffffffffffff8111156128d0576128cf612893565b5b6020830191508360018202830111156128ec576128eb612898565b5b9250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b612941826128f8565b810181811067ffffffffffffffff821117156129605761295f612909565b5b80604052505050565b600061297361287a565b905061297f8282612938565b919050565b600067ffffffffffffffff82111561299f5761299e612909565b5b6129a8826128f8565b9050602081019050919050565b82818337600083830152505050565b60006129d76129d284612984565b612969565b9050828152602081018484840111156129f3576129f26128f3565b5b6129fe8482856129b5565b509392505050565b600082601f830112612a1b57612a1a61288e565b5b8135612a2b8482602086016129c4565b91505092915050565b600080600060408486031215612a4d57612a4c612884565b5b600084013567ffffffffffffffff811115612a6b57612a6a612889565b5b612a778682870161289d565b9350935050602084013567ffffffffffffffff811115612a9a57612a99612889565b5b612aa686828701612a06565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612adb82612ab0565b9050919050565b612aeb81612ad0565b8114612af657600080fd5b50565b600081359050612b0881612ae2565b92915050565b600060208284031215612b2457612b23612884565b5b6000612b3284828501612af9565b91505092915050565b612b4481612ad0565b82525050565b6000602082019050612b5f6000830184612b3b565b92915050565b60008115159050919050565b612b7a81612b65565b8114612b8557600080fd5b50565b600081359050612b9781612b71565b92915050565b600080600060608486031215612bb657612bb5612884565b5b6000612bc486828701612af9565b9350506020612bd586828701612af9565b9250506040612be686828701612b88565b9150509250925092565b60008060408385031215612c0757612c06612884565b5b6000612c1585828601612af9565b9250506020612c2685828601612b88565b9150509250929050565b6000819050919050565b612c4381612c30565b8114612c4e57600080fd5b50565b600081359050612c6081612c3a565b92915050565b600060208284031215612c7c57612c7b612884565b5b6000612c8a84828501612c51565b91505092915050565b612c9c81612b65565b82525050565b6000602082019050612cb76000830184612c93565b92915050565b600081519050612ccc81612b71565b92915050565b600060208284031215612ce857612ce7612884565b5b6000612cf684828501612cbd565b91505092915050565b600082825260208201905092915050565b7f7061757365640000000000000000000000000000000000000000000000000000600082015250565b6000612d46600683612cff565b9150612d5182612d10565b602082019050919050565b60006020820190508181036000830152612d7581612d39565b9050919050565b7f21746f6b656e0000000000000000000000000000000000000000000000000000600082015250565b6000612db2600683612cff565b9150612dbd82612d7c565b602082019050919050565b60006020820190508181036000830152612de181612da5565b9050919050565b7f217472786e547970650000000000000000000000000000000000000000000000600082015250565b6000612e1e600983612cff565b9150612e2982612de8565b602082019050919050565b60006020820190508181036000830152612e4d81612e11565b9050919050565b6000819050919050565b612e6781612e54565b82525050565b6000604082019050612e826000830185612b3b565b612e8f6020830184612e5e565b9392505050565b6000604082019050612eab6000830185612e5e565b612eb86020830184612b3b565b9392505050565b612ec881612e54565b8114612ed357600080fd5b50565b600081519050612ee581612ebf565b92915050565b600060208284031215612f0157612f00612884565b5b6000612f0f84828501612ed6565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612f5282612e54565b9150612f5d83612e54565b9250828202612f6b81612e54565b91508282048414831517612f8257612f81612f18565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612fc382612e54565b9150612fce83612e54565b925082612fde57612fdd612f89565b5b828204905092915050565b6000604082019050612ffe6000830185612e5e565b61300b6020830184612e5e565b9392505050565b6000819050919050565b600067ffffffffffffffff82169050919050565b6000819050919050565b600061305561305061304b84613012565b613030565b61301c565b9050919050565b6130658161303a565b82525050565b6000602082019050613080600083018461305c565b92915050565b600060608201905061309b6000830186612e5e565b6130a86020830185612b3b565b6130b56040830184612b3b565b949350505050565b60006080820190506130d26000830187612b3b565b6130df6020830186612e5e565b6130ec6040830185612b3b565b6130f96060830184612b3b565b95945050505050565b61310b81612c30565b82525050565b60006040820190506131266000830185613102565b6131336020830184612b3b565b9392505050565b7f2161646d696e0000000000000000000000000000000000000000000000000000600082015250565b6000613170600683612cff565b915061317b8261313a565b602082019050919050565b6000602082019050818103600083015261319f81613163565b9050919050565b7f2161737365740000000000000000000000000000000000000000000000000000600082015250565b60006131dc600683612cff565b91506131e7826131a6565b602082019050919050565b6000602082019050818103600083015261320b816131cf565b9050919050565b7f21636f6e74726163740000000000000000000000000000000000000000000000600082015250565b6000613248600983612cff565b915061325382613212565b602082019050919050565b600060208201905081810360008301526132778161323b565b9050919050565b7f2174726561737572790000000000000000000000000000000000000000000000600082015250565b60006132b4600983612cff565b91506132bf8261327e565b602082019050919050565b600060208201905081810360008301526132e3816132a7565b9050919050565b600081905092915050565b600061330183856132ea565b935061330e8385846129b5565b82840190509392505050565b60006133278284866132f5565b91508190509392505050565b600081519050919050565b60005b8381101561335c578082015181840152602081019050613341565b60008484015250505050565b600061337382613333565b61337d81856132ea565b935061338d81856020860161333e565b80840191505092915050565b6000819050919050565b6133b46133af82612c30565b613399565b82525050565b60006133c68285613368565b91506133d282846133a3565b6020820191508190509392505050565b60006133ed82612ab0565b9050919050565b6133fd816133e2565b811461340857600080fd5b50565b60008135905061341a816133f4565b92915050565b60008135905061342f81612ebf565b92915050565b600080600080600080600080610100898b03121561345657613455612884565b5b60006134648b828c0161340b565b98505060206134758b828c0161340b565b97505060406134868b828c01613420565b96505060606134978b828c01613420565b95505060806134a88b828c01613420565b94505060a06134b98b828c01613420565b93505060c06134ca8b828c01613420565b92505060e06134db8b828c01612c51565b9150509295985092959890939650565b60006060820190506135006000830186612b3b565b61350d6020830185612b3b565b61351a6040830184612e5e565b949350505050565b600061352d82612e54565b915061353883612e54565b92508282039050818111156135505761354f612f18565b5b92915050565b7f2161646d696e6973747261746f72000000000000000000000000000000000000600082015250565b600061358c600e83612cff565b915061359782613556565b602082019050919050565b600060208201905081810360008301526135bb8161357f565b9050919050565b6000819050919050565b60006135e76135e26135dd846135c2565b613030565b612e54565b9050919050565b6135f7816135cc565b82525050565b60006040820190506136126000830185612b3b565b61361f60208301846135ee565b9392505050565b7f21646561646c696e650000000000000000000000000000000000000000000000600082015250565b600061365c600983612cff565b915061366782613626565b602082019050919050565b6000602082019050818103600083015261368b8161364f565b9050919050565b600061369e8284613368565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506136ed6000830184612e5e565b92915050565b60006020820190506137086000830184613102565b92915050565b600060ff82169050919050565b6137248161370e565b82525050565b600060808201905061373f6000830187613102565b61374c602083018661371b565b6137596040830185613102565b6137666060830184613102565b9594505050505056fea26469706673582212203a348080b081cc44b4a23d7c114f10f9e419222dec99ce21837db5ca03bd843e64736f6c63430008180033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c80639ebdf12c1161008c578063e81cc3cc11610066578063e81cc3cc14610221578063f0f442601461023f578063f11b81881461025b578063f53d0a8e1461028b576100ea565b80639ebdf12c146101b7578063c30a0f25146101d5578063df8089ef14610205576100ea565b806350fbe2d9116100c857806350fbe2d91461014557806361d027b314610161578063859a4f071461017f57806389fc437c1461019b576100ea565b8063164af1df146100ef57806319ab453c1461010b57806349bfcca114610127575b600080fd5b61010960048036038101906101049190612a34565b6102a9565b005b61012560048036038101906101209190612b0e565b61085e565b005b61012f6109ed565b60405161013c9190612b4a565b60405180910390f35b61015f600480360381019061015a9190612a34565b610a13565b005b610169610f2b565b6040516101769190612b4a565b60405180910390f35b61019960048036038101906101949190612b9d565b610f51565b005b6101b560048036038101906101b09190612bf0565b611198565b005b6101bf611336565b6040516101cc9190612b4a565b60405180910390f35b6101ef60048036038101906101ea9190612c66565b61135c565b6040516101fc9190612ca2565b60405180910390f35b61021f600480360381019061021a9190612b0e565b61137c565b005b610229611502565b6040516102369190612ca2565b60405180910390f35b61025960048036038101906102549190612b0e565b611515565b005b61027560048036038101906102709190612b0e565b6116c3565b6040516102829190612ca2565b60405180910390f35b6102936116e3565b6040516102a09190612b4a565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635b14f183306040518263ffffffff1660e01b81526004016103029190612b4a565b602060405180830381865afa15801561031f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103439190612cd2565b15610383576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037a90612d5c565b60405180910390fd5b61038b611707565b61039683838361175e565b60006103a2848461191b565b905060046000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1680156104285750610427600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611a88565b5b610467576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161045e90612dc8565b60405180910390fd5b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8218160e0015114806104bc57507f175edc95deb431c7abe19847bac40d41948fd28714d8af8c93fed89eaae248c88160e00151145b6104fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f290612e34565b60405180910390fd5b61055233600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168360400151846000015173ffffffffffffffffffffffffffffffffffffffff16611ae5909392919063ffffffff16565b6000600360149054906101000a900460ff16156106a757600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f193084608001516040518363ffffffff1660e01b81526004016105ca929190612e6d565b600060405180830381600087803b1580156105e457600080fd5b505af11580156105f8573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636e553f658360800151306040518363ffffffff1660e01b815260040161065d929190612e96565b6020604051808303816000875af115801561067c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a09190612eeb565b90506107ea565b8160600151670de0b6b3a764000083608001516106c49190612f47565b6106ce9190612fb8565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930836040518363ffffffff1660e01b815260040161072d929190612e6d565b600060405180830381600087803b15801561074757600080fd5b505af115801561075b573d6000803e3d6000fd5b50505050816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167faaefaf378e10f40556b2167ea878af7e62d89229b0bce3924630aabf1ee611ff8560400151856040516107e1929190612fe9565b60405180910390a45b60006107fb828460a0015130611b67565b905061084e836020015182600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ccc9092919063ffffffff16565b505050610859611d4b565b505050565b6000610868611d64565b905060008160000160089054906101000a900460ff1615905060008260000160009054906101000a900467ffffffffffffffff1690506000808267ffffffffffffffff161480156108b65750825b9050600060018367ffffffffffffffff161480156108eb575060003073ffffffffffffffffffffffffffffffffffffffff163b145b9050811580156108f9575080155b15610930576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018560000160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083156109805760018560000160086101000a81548160ff0219169083151502179055505b61098986611d8c565b83156109e55760008560000160086101000a81548160ff0219169083151502179055507fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260016040516109dc919061306b565b60405180910390a15b505050505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635b14f183306040518263ffffffff1660e01b8152600401610a6c9190612b4a565b602060405180830381865afa158015610a89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aad9190612cd2565b15610aed576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ae490612d5c565b60405180910390fd5b610af5611707565b610b0083838361175e565b6000610b0c848461191b565b905060046000826000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff168015610b925750610b91600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16611a88565b5b610bd1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bc890612dc8565b60405180910390fd5b7f7a8dc26796a1e50e6e190b70259f58f6a4edd5b22280ceecc82b687b8e9828698160e001511480610c2657507fec28eada7e4093a2d13c92d33b727848291ee15a6bbbffdd27f55acfa28f8aaa8160e00151145b610c65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5c90612e34565b60405180910390fd5b6000610c7a82604001518360a0015133611b67565b90506000600360149054906101000a900460ff1615610d3c57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ba0876528330336040518463ffffffff1660e01b8152600401610cf293929190613086565b6020604051808303816000875af1158015610d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d359190612eeb565b9050610e80565b670de0b6b3a7640000836060015183610d559190612f47565b610d5f9190612fb8565b9050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33846040518363ffffffff1660e01b8152600401610dbe929190612e6d565b600060405180830381600087803b158015610dd857600080fd5b505af1158015610dec573d6000803e3d6000fd5b50505050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1930836040518363ffffffff1660e01b8152600401610e4d929190612e6d565b600060405180830381600087803b158015610e6757600080fd5b505af1158015610e7b573d6000803e3d6000fd5b505050505b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663029d375c8460000151838660200151306040518563ffffffff1660e01b8152600401610ee994939291906130bd565b600060405180830381600087803b158015610f0357600080fd5b505af1158015610f17573d6000803e3d6000fd5b50505050505050610f26611d4b565b505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401610fcc929190613111565b602060405180830381865afa158015610fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100d9190612cd2565b61104c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161104390613186565b60405180910390fd5b61105583611a88565b8015611066575061106582611a88565b5b6110a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161109c90612dc8565b60405180910390fd5b82600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600360146101000a81548160ff021916908315150217905550801561119357611192827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8573ffffffffffffffffffffffffffffffffffffffff16611e4e9092919063ffffffff16565b5b505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401611213929190613111565b602060405180830381865afa158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112549190612cd2565b611293576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128a90613186565b60405180910390fd5b61129c82611a88565b6112db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d2906131f2565b60405180910390fd5b80600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60056020528060005260406000206000915054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b81526004016113f7929190613111565b602060405180830381865afa158015611414573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114389190612cd2565b611477576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161146e90613186565b60405180910390fd5b61148081611a88565b6114bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114b69061325e565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600360149054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42336040518363ffffffff1660e01b8152600401611590929190613111565b602060405180830381865afa1580156115ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d19190612cd2565b611610576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161160790613186565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361167f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611676906132ca565b60405180910390fd5b80600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60046020528060005260406000206000915054906101000a900460ff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000611711611f5d565b90506002816000015403611751576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002816000018190555050565b60006117de6040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525085856040516117a992919061331a565b60405180910390206040516020016117c29291906133ba565b6040516020818303038152906040528051906020012083611f85565b905060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d148547f2aeb38be3df14d720aeb10a2de6df09b0fb3cd5c5ec256283a22d4593110ca40836040518363ffffffff1660e01b815260040161185b929190613111565b602060405180830381865afa158015611878573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189c9190612cd2565b6118d2576040517f729d0f6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016005600086866040516118e892919061331a565b6040518091039020815260200190815260200160002060006101000a81548160ff02191690831515021790555050505050565b611923612806565b6101008383905014611961576040517fcc513c7200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806000806000808a8a81019061197c9190613435565b9750975097509750975097509750975061199a818888888887611fb1565b600073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614806119db57506119d988611a88565b155b15611a12576040517f8278a71400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518061010001604052808973ffffffffffffffffffffffffffffffffffffffff1681526020018873ffffffffffffffffffffffffffffffffffffffff168152602001878152602001868152602001858152602001848152602001838152602001828152509850505050505050505092915050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611ade575060008273ffffffffffffffffffffffffffffffffffffffff163b14155b9050919050565b611b61848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401611b1a939291906134eb565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b50505050565b6000808303611b7857839050611cc5565b600068056bc75e2d631000008486611b909190612f47565b611b9a9190612fb8565b90503073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611c4357611c3e600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1682600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ccc9092919063ffffffff16565b611cb5565b611cb483600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16611ae5909392919063ffffffff16565b5b8085611cc19190613522565b9150505b9392505050565b611d46838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8585604051602401611cff929190612e6d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b505050565b6000611d55611f5d565b90506001816000018190555050565b60007ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00905090565b611d94612241565b611d9c612281565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611e0b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e02906135a2565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008373ffffffffffffffffffffffffffffffffffffffff1663095ea7b38484604051602401611e7f929190612e6d565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050611ecd8482612293565b611f5757611f4c848573ffffffffffffffffffffffffffffffffffffffff1663095ea7b3866000604051602401611f059291906135fd565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506121aa565b611f5684826121aa565b5b50505050565b60007f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00905090565b600080600080611f95868661235a565b925092509250611fa582826123b6565b82935050505092915050565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611fec5750600084145b80611ff75750600081145b1561202e576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8218603612090576000820361208f576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b7f175edc95deb431c7abe19847bac40d41948fd28714d8af8c93fed89eaae248c886036120fe5760008214806120c65750600083145b156120fd576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b7fec28eada7e4093a2d13c92d33b727848291ee15a6bbbffdd27f55acfa28f8aaa8603612160576000830361215f576040517f036896be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b8042106121a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161219990613672565b60405180910390fd5b505050505050565b60006121d5828473ffffffffffffffffffffffffffffffffffffffff1661251a90919063ffffffff16565b905060008151141580156121fa5750808060200190518101906121f89190612cd2565b155b1561223c57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016122339190612b4a565b60405180910390fd5b505050565b612249612530565b61227f576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b612289612241565b612291612550565b565b60008060008473ffffffffffffffffffffffffffffffffffffffff16846040516122bd9190613692565b6000604051808303816000865af19150503d80600081146122fa576040519150601f19603f3d011682016040523d82523d6000602084013e6122ff565b606091505b509150915081801561232d575060008151148061232c57508080602001905181019061232b9190612cd2565b5b5b8015612350575060008573ffffffffffffffffffffffffffffffffffffffff163b115b9250505092915050565b6000806000604184510361239f5760008060006020870151925060408701519150606087015160001a905061239188828585612571565b9550955095505050506123af565b60006002855160001b9250925092505b9250925092565b600060038111156123ca576123c96136a9565b5b8260038111156123dd576123dc6136a9565b5b031561251657600160038111156123f7576123f66136a9565b5b82600381111561240a576124096136a9565b5b03612441576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026003811115612455576124546136a9565b5b826003811115612468576124676136a9565b5b036124ad578060001c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016124a491906136d8565b60405180910390fd5b6003808111156124c0576124bf6136a9565b5b8260038111156124d3576124d26136a9565b5b0361251557806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161250c91906136f3565b60405180910390fd5b5b5050565b606061252883836000612665565b905092915050565b600061253a611d64565b60000160089054906101000a900460ff16905090565b612558612241565b6000612562611f5d565b90506001816000018190555050565b60008060007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08460001c11156125b157600060038592509250925061265b565b6000600188888888604051600081526020016040526040516125d6949392919061372a565b6020604051602081039080840390855afa1580156125f8573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361264c57600060016000801b9350935093505061265b565b8060008060001b935093509350505b9450945094915050565b6060814710156126ac57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016126a39190612b4a565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff1684866040516126d59190613692565b60006040518083038185875af1925050503d8060008114612712576040519150601f19603f3d011682016040523d82523d6000602084013e612717565b606091505b5091509150612727868383612732565b925050509392505050565b60608261274757612742826127c1565b6127b9565b6000825114801561276f575060008473ffffffffffffffffffffffffffffffffffffffff163b145b156127b157836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016127a89190612b4a565b60405180910390fd5b8190506127ba565b5b9392505050565b6000815111156127d45780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806101000160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600080191681525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126128b3576128b261288e565b5b8235905067ffffffffffffffff8111156128d0576128cf612893565b5b6020830191508360018202830111156128ec576128eb612898565b5b9250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b612941826128f8565b810181811067ffffffffffffffff821117156129605761295f612909565b5b80604052505050565b600061297361287a565b905061297f8282612938565b919050565b600067ffffffffffffffff82111561299f5761299e612909565b5b6129a8826128f8565b9050602081019050919050565b82818337600083830152505050565b60006129d76129d284612984565b612969565b9050828152602081018484840111156129f3576129f26128f3565b5b6129fe8482856129b5565b509392505050565b600082601f830112612a1b57612a1a61288e565b5b8135612a2b8482602086016129c4565b91505092915050565b600080600060408486031215612a4d57612a4c612884565b5b600084013567ffffffffffffffff811115612a6b57612a6a612889565b5b612a778682870161289d565b9350935050602084013567ffffffffffffffff811115612a9a57612a99612889565b5b612aa686828701612a06565b9150509250925092565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612adb82612ab0565b9050919050565b612aeb81612ad0565b8114612af657600080fd5b50565b600081359050612b0881612ae2565b92915050565b600060208284031215612b2457612b23612884565b5b6000612b3284828501612af9565b91505092915050565b612b4481612ad0565b82525050565b6000602082019050612b5f6000830184612b3b565b92915050565b60008115159050919050565b612b7a81612b65565b8114612b8557600080fd5b50565b600081359050612b9781612b71565b92915050565b600080600060608486031215612bb657612bb5612884565b5b6000612bc486828701612af9565b9350506020612bd586828701612af9565b9250506040612be686828701612b88565b9150509250925092565b60008060408385031215612c0757612c06612884565b5b6000612c1585828601612af9565b9250506020612c2685828601612b88565b9150509250929050565b6000819050919050565b612c4381612c30565b8114612c4e57600080fd5b50565b600081359050612c6081612c3a565b92915050565b600060208284031215612c7c57612c7b612884565b5b6000612c8a84828501612c51565b91505092915050565b612c9c81612b65565b82525050565b6000602082019050612cb76000830184612c93565b92915050565b600081519050612ccc81612b71565b92915050565b600060208284031215612ce857612ce7612884565b5b6000612cf684828501612cbd565b91505092915050565b600082825260208201905092915050565b7f7061757365640000000000000000000000000000000000000000000000000000600082015250565b6000612d46600683612cff565b9150612d5182612d10565b602082019050919050565b60006020820190508181036000830152612d7581612d39565b9050919050565b7f21746f6b656e0000000000000000000000000000000000000000000000000000600082015250565b6000612db2600683612cff565b9150612dbd82612d7c565b602082019050919050565b60006020820190508181036000830152612de181612da5565b9050919050565b7f217472786e547970650000000000000000000000000000000000000000000000600082015250565b6000612e1e600983612cff565b9150612e2982612de8565b602082019050919050565b60006020820190508181036000830152612e4d81612e11565b9050919050565b6000819050919050565b612e6781612e54565b82525050565b6000604082019050612e826000830185612b3b565b612e8f6020830184612e5e565b9392505050565b6000604082019050612eab6000830185612e5e565b612eb86020830184612b3b565b9392505050565b612ec881612e54565b8114612ed357600080fd5b50565b600081519050612ee581612ebf565b92915050565b600060208284031215612f0157612f00612884565b5b6000612f0f84828501612ed6565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000612f5282612e54565b9150612f5d83612e54565b9250828202612f6b81612e54565b91508282048414831517612f8257612f81612f18565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612fc382612e54565b9150612fce83612e54565b925082612fde57612fdd612f89565b5b828204905092915050565b6000604082019050612ffe6000830185612e5e565b61300b6020830184612e5e565b9392505050565b6000819050919050565b600067ffffffffffffffff82169050919050565b6000819050919050565b600061305561305061304b84613012565b613030565b61301c565b9050919050565b6130658161303a565b82525050565b6000602082019050613080600083018461305c565b92915050565b600060608201905061309b6000830186612e5e565b6130a86020830185612b3b565b6130b56040830184612b3b565b949350505050565b60006080820190506130d26000830187612b3b565b6130df6020830186612e5e565b6130ec6040830185612b3b565b6130f96060830184612b3b565b95945050505050565b61310b81612c30565b82525050565b60006040820190506131266000830185613102565b6131336020830184612b3b565b9392505050565b7f2161646d696e0000000000000000000000000000000000000000000000000000600082015250565b6000613170600683612cff565b915061317b8261313a565b602082019050919050565b6000602082019050818103600083015261319f81613163565b9050919050565b7f2161737365740000000000000000000000000000000000000000000000000000600082015250565b60006131dc600683612cff565b91506131e7826131a6565b602082019050919050565b6000602082019050818103600083015261320b816131cf565b9050919050565b7f21636f6e74726163740000000000000000000000000000000000000000000000600082015250565b6000613248600983612cff565b915061325382613212565b602082019050919050565b600060208201905081810360008301526132778161323b565b9050919050565b7f2174726561737572790000000000000000000000000000000000000000000000600082015250565b60006132b4600983612cff565b91506132bf8261327e565b602082019050919050565b600060208201905081810360008301526132e3816132a7565b9050919050565b600081905092915050565b600061330183856132ea565b935061330e8385846129b5565b82840190509392505050565b60006133278284866132f5565b91508190509392505050565b600081519050919050565b60005b8381101561335c578082015181840152602081019050613341565b60008484015250505050565b600061337382613333565b61337d81856132ea565b935061338d81856020860161333e565b80840191505092915050565b6000819050919050565b6133b46133af82612c30565b613399565b82525050565b60006133c68285613368565b91506133d282846133a3565b6020820191508190509392505050565b60006133ed82612ab0565b9050919050565b6133fd816133e2565b811461340857600080fd5b50565b60008135905061341a816133f4565b92915050565b60008135905061342f81612ebf565b92915050565b600080600080600080600080610100898b03121561345657613455612884565b5b60006134648b828c0161340b565b98505060206134758b828c0161340b565b97505060406134868b828c01613420565b96505060606134978b828c01613420565b95505060806134a88b828c01613420565b94505060a06134b98b828c01613420565b93505060c06134ca8b828c01613420565b92505060e06134db8b828c01612c51565b9150509295985092959890939650565b60006060820190506135006000830186612b3b565b61350d6020830185612b3b565b61351a6040830184612e5e565b949350505050565b600061352d82612e54565b915061353883612e54565b92508282039050818111156135505761354f612f18565b5b92915050565b7f2161646d696e6973747261746f72000000000000000000000000000000000000600082015250565b600061358c600e83612cff565b915061359782613556565b602082019050919050565b600060208201905081810360008301526135bb8161357f565b9050919050565b6000819050919050565b60006135e76135e26135dd846135c2565b613030565b612e54565b9050919050565b6135f7816135cc565b82525050565b60006040820190506136126000830185612b3b565b61361f60208301846135ee565b9392505050565b7f21646561646c696e650000000000000000000000000000000000000000000000600082015250565b600061365c600983612cff565b915061366782613626565b602082019050919050565b6000602082019050818103600083015261368b8161364f565b9050919050565b600061369e8284613368565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006020820190506136ed6000830184612e5e565b92915050565b60006020820190506137086000830184613102565b92915050565b600060ff82169050919050565b6137248161370e565b82525050565b600060808201905061373f6000830187613102565b61374c602083018661371b565b6137596040830185613102565b6137666060830184613102565b9594505050505056fea26469706673582212203a348080b081cc44b4a23d7c114f10f9e419222dec99ce21837db5ca03bd843e64736f6c63430008180033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.