More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 1,193 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 24172309 | 43 days ago | IN | 0 ETH | 0.00000214 | ||||
| Withdraw | 24034760 | 46 days ago | IN | 0 ETH | 0.00000298 | ||||
| Withdraw | 23357125 | 63 days ago | IN | 0 ETH | 0.00000259 | ||||
| Withdraw | 22865629 | 74 days ago | IN | 0 ETH | 0.00000259 | ||||
| Withdraw | 21082239 | 119 days ago | IN | 0 ETH | 0.00000373 | ||||
| Withdraw | 20653282 | 133 days ago | IN | 0 ETH | 0.00000275 | ||||
| Approve | 20622890 | 134 days ago | IN | 0 ETH | 0.00000165 | ||||
| Withdraw | 20340144 | 144 days ago | IN | 0 ETH | 0.00000356 | ||||
| Withdraw | 19628811 | 166 days ago | IN | 0 ETH | 0.00000271 | ||||
| Withdraw | 19018736 | 186 days ago | IN | 0 ETH | 0.00000281 | ||||
| Withdraw | 19018339 | 186 days ago | IN | 0 ETH | 0.00000281 | ||||
| Withdraw | 19017910 | 186 days ago | IN | 0 ETH | 0.00000281 | ||||
| Withdraw | 18926864 | 188 days ago | IN | 0 ETH | 0.00000364 | ||||
| Withdraw | 18873783 | 190 days ago | IN | 0 ETH | 0.00000294 | ||||
| Withdraw | 18809310 | 192 days ago | IN | 0 ETH | 0.0000041 | ||||
| Withdraw | 18699481 | 195 days ago | IN | 0 ETH | 0.00000521 | ||||
| Withdraw | 18660019 | 197 days ago | IN | 0 ETH | 0.00000281 | ||||
| Withdraw | 18646128 | 197 days ago | IN | 0 ETH | 0.00000545 | ||||
| Withdraw | 17499247 | 232 days ago | IN | 0 ETH | 0.00000466 | ||||
| Withdraw | 17427845 | 234 days ago | IN | 0 ETH | 0.00000281 | ||||
| Withdraw | 17397032 | 235 days ago | IN | 0 ETH | 0.00000331 | ||||
| Withdraw | 17352222 | 236 days ago | IN | 0 ETH | 0.00000331 | ||||
| Withdraw | 17063430 | 244 days ago | IN | 0 ETH | 0.00002971 | ||||
| Withdraw | 17062934 | 244 days ago | IN | 0 ETH | 0.00000341 | ||||
| Approve | 16726765 | 253 days ago | IN | 0 ETH | 0.00000991 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 24172309 | 43 days ago | 0 ETH | ||||
| 24172294 | 43 days ago | 0 ETH | ||||
| 24034760 | 46 days ago | 0 ETH | ||||
| 24034753 | 46 days ago | 0 ETH | ||||
| 23357125 | 63 days ago | 0 ETH | ||||
| 23357116 | 63 days ago | 0 ETH | ||||
| 22865629 | 74 days ago | 0 ETH | ||||
| 22865623 | 74 days ago | 0 ETH | ||||
| 21082239 | 119 days ago | 0 ETH | ||||
| 21082224 | 119 days ago | 0 ETH | ||||
| 20796159 | 128 days ago | 0 ETH | ||||
| 20653282 | 133 days ago | 0 ETH | ||||
| 20653268 | 133 days ago | 0 ETH | ||||
| 20340144 | 144 days ago | 0 ETH | ||||
| 20340137 | 144 days ago | 0 ETH | ||||
| 19628811 | 166 days ago | 0 ETH | ||||
| 19628803 | 166 days ago | 0 ETH | ||||
| 19018736 | 186 days ago | 0 ETH | ||||
| 19018729 | 186 days ago | 0 ETH | ||||
| 19018339 | 186 days ago | 0 ETH | ||||
| 19018317 | 186 days ago | 0 ETH | ||||
| 19017910 | 186 days ago | 0 ETH | ||||
| 19017896 | 186 days ago | 0 ETH | ||||
| 18926864 | 188 days ago | 0 ETH | ||||
| 18926849 | 188 days ago | 0 ETH |
Loading...
Loading
Contract Name:
Vault
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ITokenBurn } from './interfaces/ITokenBurn.sol';
import { ITokenDecimals } from './interfaces/ITokenDecimals.sol';
import { AssetSpenderRole } from './roles/AssetSpenderRole.sol';
import { BalanceManagement } from './BalanceManagement.sol';
import { SystemVersionId } from './SystemVersionId.sol';
import { VaultBase } from './VaultBase.sol';
import { TokenBurnError } from './Errors.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './helpers/TransferHelper.sol' as TransferHelper;
/**
* @title Vault
* @notice The vault contract
*/
contract Vault is SystemVersionId, VaultBase, AssetSpenderRole, BalanceManagement {
/**
* @dev The variable token contract address, can be a zero address
*/
address public variableToken;
/**
* @dev The state of variable token and balance actions
*/
bool public variableRepaymentEnabled;
/**
* @notice Emitted when the state of variable token and balance actions is updated
* @param variableRepaymentEnabled The state of variable token and balance actions
*/
event SetVariableRepaymentEnabled(bool indexed variableRepaymentEnabled);
/**
* @notice Emitted when the variable token contract address is updated
* @param variableToken The address of the variable token contract
*/
event SetVariableToken(address indexed variableToken);
/**
* @notice Emitted when the variable tokens are redeemed for the vault asset
* @param caller The address of the vault asset receiver account
* @param amount The amount of redeemed variable tokens
*/
event RedeemVariableToken(address indexed caller, uint256 amount);
/**
* @notice Emitted when the variable token decimals do not match the vault asset
*/
error TokenDecimalsError();
/**
* @notice Emitted when a variable token or balance action is not allowed
*/
error VariableRepaymentNotEnabledError();
/**
* @notice Emitted when setting the variable token is attempted while the token is already set
*/
error VariableTokenAlreadySetError();
/**
* @notice Emitted when a variable token action is attempted while the token address is not set
*/
error VariableTokenNotSetError();
/**
* @notice Deploys the VariableToken contract
* @param _asset The vault asset address
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _assetSpenders The addresses of initial asset spenders
* @param _depositAllowed The initial state of deposit availability
* @param _variableRepaymentEnabled The initial state of variable token and balance actions
* @param _owner The address of the initial owner of the contract
* @param _managers The addresses of initial managers of the contract
* @param _addOwnerToManagers The flag to optionally add the owner to the list of managers
*/
constructor(
address _asset,
string memory _name,
string memory _symbol,
address[] memory _assetSpenders,
bool _depositAllowed,
bool _variableRepaymentEnabled,
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) VaultBase(_asset, _name, _symbol, _depositAllowed) {
for (uint256 index; index < _assetSpenders.length; index++) {
_setAssetSpender(_assetSpenders[index], true);
}
_setVariableRepaymentEnabled(_variableRepaymentEnabled);
_initRoles(_owner, _managers, _addOwnerToManagers);
}
/**
* @notice Updates the Asset Spender role status for the account
* @param _account The account address
* @param _value The Asset Spender role status flag
*/
function setAssetSpender(address _account, bool _value) external onlyManager {
_setAssetSpender(_account, _value);
}
/**
* @notice Sets the variable token contract address
* @dev Setting the address value is possible only once
* @param _variableToken The address of the variable token contract
*/
function setVariableToken(address _variableToken) external onlyManager {
if (variableToken != address(0)) {
revert VariableTokenAlreadySetError();
}
AddressHelper.requireContract(_variableToken);
if (ITokenDecimals(_variableToken).decimals() != decimals) {
revert TokenDecimalsError();
}
variableToken = _variableToken;
emit SetVariableToken(_variableToken);
}
/**
* @notice Updates the state of variable token and balance actions
* @param _variableRepaymentEnabled The state of variable token and balance actions
*/
function setVariableRepaymentEnabled(bool _variableRepaymentEnabled) external onlyManager {
_setVariableRepaymentEnabled(_variableRepaymentEnabled);
}
/**
* @notice Requests the vault asset tokens
* @param _amount The amount of the vault asset tokens
* @param _to The address of the vault asset tokens receiver
* @param _forVariableBalance True if the request is made for a variable balance repayment, otherwise false
* @return assetAddress The address of the vault asset token
*/
function requestAsset(
uint256 _amount,
address _to,
bool _forVariableBalance
) external whenNotPaused onlyAssetSpender returns (address assetAddress) {
if (_forVariableBalance && !variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
TransferHelper.safeTransfer(asset, _to, _amount);
return asset;
}
/**
* @notice Redeems variable tokens for the vault asset
* @param _amount The number of variable tokens to redeem
*/
function redeemVariableToken(uint256 _amount) external whenNotPaused nonReentrant checkCaller {
checkVariableTokenState();
bool burnSuccess = ITokenBurn(variableToken).burn(msg.sender, _amount);
if (!burnSuccess) {
revert TokenBurnError();
}
emit RedeemVariableToken(msg.sender, _amount);
TransferHelper.safeTransfer(asset, msg.sender, _amount);
}
/**
* @notice Checks the status of the variable token and balance actions and the variable token address
* @dev Throws an error if variable token actions are not allowed
* @return The address of the variable token
*/
function checkVariableTokenState() public view returns (address) {
if (!variableRepaymentEnabled) {
revert VariableRepaymentNotEnabledError();
}
if (variableToken == address(0)) {
revert VariableTokenNotSetError();
}
return variableToken;
}
/**
* @notice Getter of the reserved token flag
* @dev Returns true if the provided token address is the address of the vault asset
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/
function isReservedToken(address _tokenAddress) public view override returns (bool) {
return _tokenAddress == asset;
}
function _setVariableRepaymentEnabled(bool _variableRepaymentEnabled) private {
variableRepaymentEnabled = _variableRepaymentEnabled;
emit SetVariableRepaymentEnabled(_variableRepaymentEnabled);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ITokenBalance } from './interfaces/ITokenBalance.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
/**
* @title BalanceManagement
* @notice Base contract for the withdrawal of tokens, except for reserved ones
*/
abstract contract BalanceManagement is ManagerRole {
/**
* @notice Emitted when the specified token is reserved
*/
error ReservedTokenError();
/**
* @notice Performs the withdrawal of tokens, except for reserved ones
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @param _tokenAmount The amount of the token
*/
function cleanup(address _tokenAddress, uint256 _tokenAmount) external onlyManager {
if (isReservedToken(_tokenAddress)) {
revert ReservedTokenError();
}
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
/**
* @notice Getter of the token balance of the current contract
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @return The token balance of the current contract
*/
function tokenBalance(address _tokenAddress) public view returns (uint256) {
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
return address(this).balance;
} else {
return ITokenBalance(_tokenAddress).balanceOf(address(this));
}
}
/**
* @notice Getter of the reserved token flag
* @dev Override to add reserved token addresses
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/
function isReservedToken(address _tokenAddress) public view virtual returns (bool) {
// The function returns false by default.
// The explicit return statement is omitted to avoid the unused parameter warning.
// See https://github.com/ethereum/solidity/issues/5295
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './Constants.sol' as Constants;
import './DataStructures.sol' as DataStructures;
/**
* @title CallerGuard
* @notice Base contract to control access from other contracts
*/
abstract contract CallerGuard is ManagerRole {
/**
* @dev Caller guard mode enumeration
*/
enum CallerGuardMode {
ContractForbidden,
ContractList,
ContractAllowed
}
/**
* @dev Caller guard mode value
*/
CallerGuardMode public callerGuardMode = CallerGuardMode.ContractForbidden;
/**
* @dev Registered contract list for "ContractList" mode
*/
address[] public listedCallerGuardContractList;
/**
* @dev Registered contract list indices for "ContractList" mode
*/
mapping(address /*account*/ => DataStructures.OptionalValue /*index*/)
public listedCallerGuardContractIndexMap;
/**
* @notice Emitted when the caller guard mode is set
* @param callerGuardMode The caller guard mode
*/
event SetCallerGuardMode(CallerGuardMode indexed callerGuardMode);
/**
* @notice Emitted when a registered contract for "ContractList" mode is added or removed
* @param contractAddress The contract address
* @param isListed The registered contract list inclusion flag
*/
event SetListedCallerGuardContract(address indexed contractAddress, bool indexed isListed);
/**
* @notice Emitted when the caller is not allowed to perform the intended action
*/
error CallerGuardError(address caller);
/**
* @dev Modifier to check if the caller is allowed to perform the intended action
*/
modifier checkCaller() {
if (msg.sender != tx.origin) {
bool condition = (callerGuardMode == CallerGuardMode.ContractAllowed ||
(callerGuardMode == CallerGuardMode.ContractList &&
isListedCallerGuardContract(msg.sender)));
if (!condition) {
revert CallerGuardError(msg.sender);
}
}
_;
}
/**
* @notice Sets the caller guard mode
* @param _callerGuardMode The caller guard mode
*/
function setCallerGuardMode(CallerGuardMode _callerGuardMode) external onlyManager {
callerGuardMode = _callerGuardMode;
emit SetCallerGuardMode(_callerGuardMode);
}
/**
* @notice Updates the list of registered contracts for the "ContractList" mode
* @param _items The addresses and flags for the contracts
*/
function setListedCallerGuardContracts(
DataStructures.AccountToFlag[] calldata _items
) external onlyManager {
for (uint256 index; index < _items.length; index++) {
DataStructures.AccountToFlag calldata item = _items[index];
if (item.flag) {
AddressHelper.requireContract(item.account);
}
DataStructures.uniqueAddressListUpdate(
listedCallerGuardContractList,
listedCallerGuardContractIndexMap,
item.account,
item.flag,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
emit SetListedCallerGuardContract(item.account, item.flag);
}
}
/**
* @notice Getter of the registered contract count
* @return The registered contract count
*/
function listedCallerGuardContractCount() external view returns (uint256) {
return listedCallerGuardContractList.length;
}
/**
* @notice Getter of the complete list of registered contracts
* @return The complete list of registered contracts
*/
function fullListedCallerGuardContractList() external view returns (address[] memory) {
return listedCallerGuardContractList;
}
/**
* @notice Getter of a listed contract flag
* @param _account The contract address
* @return The listed contract flag
*/
function isListedCallerGuardContract(address _account) public view returns (bool) {
return listedCallerGuardContractIndexMap[_account].isSet;
}
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; /** * @dev The default token decimals value */ uint256 constant DECIMALS_DEFAULT = 18; /** * @dev The maximum uint256 value for swap amount limit settings */ uint256 constant INFINITY = type(uint256).max; /** * @dev The default limit of account list size */ uint256 constant LIST_SIZE_LIMIT_DEFAULT = 100; /** * @dev The limit of swap router list size */ uint256 constant LIST_SIZE_LIMIT_ROUTERS = 200; /** * @dev The factor for percentage settings. Example: 100 is 0.1% */ uint256 constant MILLIPERCENT_FACTOR = 100_000; /** * @dev The de facto standard address to denote the native token */ address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Optional value structure
* @dev Is used in mappings to allow zero values
* @param isSet Value presence flag
* @param value Numeric value
*/
struct OptionalValue {
bool isSet;
uint256 value;
}
/**
* @notice Key-to-value structure
* @dev Is used as an array parameter item to perform multiple key-value settings
* @param key Numeric key
* @param value Numeric value
*/
struct KeyToValue {
uint256 key;
uint256 value;
}
/**
* @notice Key-to-value structure for address values
* @dev Is used as an array parameter item to perform multiple key-value settings with address values
* @param key Numeric key
* @param value Address value
*/
struct KeyToAddressValue {
uint256 key;
address value;
}
/**
* @notice Address-to-flag structure
* @dev Is used as an array parameter item to perform multiple settings
* @param account Account address
* @param flag Flag value
*/
struct AccountToFlag {
address account;
bool flag;
}
/**
* @notice Emitted when a list exceeds the size limit
*/
error ListSizeLimitError();
/**
* @notice Sets or updates a value in a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @param _value The address value
* @param _sizeLimit The map and list size limit
* @return isNewKey True if the key was just added, otherwise false
*/
function combinedMapSet(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key,
address _value,
uint256 _sizeLimit
) returns (bool isNewKey) {
isNewKey = !_keyIndexMap[_key].isSet;
if (isNewKey) {
uniqueListAdd(_keyList, _keyIndexMap, _key, _sizeLimit);
}
_map[_key] = _value;
}
/**
* @notice Removes a value from a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @return isChanged True if the combined map was changed, otherwise false
*/
function combinedMapRemove(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key
) returns (bool isChanged) {
isChanged = _keyIndexMap[_key].isSet;
if (isChanged) {
delete _map[_key];
uniqueListRemove(_keyList, _keyIndexMap, _key);
}
}
/**
* @notice Adds a value to a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListAdd(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListRemove(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
uint256 lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds a value to a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListAdd(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListRemove(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
address lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds or removes a value to/from a unique address value list (a list with value index mapping)
* @dev The list size limit is checked on items adding only
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _flag The value inclusion flag
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListUpdate(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
bool _flag,
uint256 _sizeLimit
) returns (bool isChanged) {
return
_flag
? uniqueAddressListAdd(_list, _indexMap, _value, _sizeLimit)
: uniqueAddressListRemove(_list, _indexMap, _value);
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; /** * @notice Emitted when an attempt to burn a token fails */ error TokenBurnError(); /** * @notice Emitted when an attempt to mint a token fails */ error TokenMintError(); /** * @notice Emitted when a zero address is specified where it is not allowed */ error ZeroAddressError();
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Emitted when the account is not a contract
* @param account The account address
*/
error NonContractAddressError(address account);
/**
* @notice Function to check if the account is a contract
* @return The account contract status flag
*/
function isContract(address _account) view returns (bool) {
return _account.code.length > 0;
}
/**
* @notice Function to require an account to be a contract
*/
function requireContract(address _account) view {
if (!isContract(_account)) {
revert NonContractAddressError(_account);
}
}
/**
* @notice Function to require an account to be a contract or a zero address
*/
function requireContractOrZeroAddress(address _account) view {
if (_account != address(0)) {
requireContract(_account);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Emitted when an approval action fails
*/
error SafeApproveError();
/**
* @notice Emitted when a transfer action fails
*/
error SafeTransferError();
/**
* @notice Emitted when a transferFrom action fails
*/
error SafeTransferFromError();
/**
* @notice Emitted when a transfer of the native token fails
*/
error SafeTransferNativeError();
/**
* @notice Safely approve the token to the account
* @param _token The token address
* @param _to The token approval recipient address
* @param _value The token approval amount
*/
function safeApprove(address _token, address _to, uint256 _value) {
// 0x095ea7b3 is the selector for "approve(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
/**
* @notice Safely transfer the token to the account
* @param _token The token address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransfer(address _token, address _to, uint256 _value) {
// 0xa9059cbb is the selector for "transfer(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
/**
* @notice Safely transfer the token between the accounts
* @param _token The token address
* @param _from The token transfer source address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransferFrom(address _token, address _from, address _to, uint256 _value) {
// 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
/**
* @notice Safely transfer the native token to the account
* @param _to The native token transfer recipient address
* @param _value The native token transfer amount
*/
function safeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(new bytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenBalance
* @notice Token balance interface
*/
interface ITokenBalance {
/**
* @notice Getter of the token balance by the account
* @param _account The account address
* @return Token balance
*/
function balanceOf(address _account) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenBurn
* @notice Token burning interface
*/
interface ITokenBurn {
/**
* @notice Burns tokens from the account, reducing the total supply
* @param _from The token holder account address
* @param _amount The number of tokens to burn
* @return Token burning success status
*/
function burn(address _from, uint256 _amount) external returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenDecimals
* @notice Token decimals interface
*/
interface ITokenDecimals {
/**
* @notice Getter of the token decimals
* @return Token decimals
*/
function decimals() external pure returns (uint8);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ERC20 } from 'solmate/src/tokens/ERC20.sol';
import { BurnerRole } from './roles/BurnerRole.sol';
import { MinterRole } from './roles/MinterRole.sol';
import { MultichainRouterRole } from './roles/MultichainRouterRole.sol';
import { Pausable } from './Pausable.sol';
import { ZeroAddressError } from './Errors.sol';
import './Constants.sol' as Constants;
/**
* @title MultichainTokenBase
* @notice Base contract that implements the Multichain token logic
*/
abstract contract MultichainTokenBase is Pausable, ERC20, MultichainRouterRole {
/**
* @dev Anyswap ERC20 standard
*/
address public immutable underlying;
bool private immutable useExplicitAccess;
/**
* @notice Emitted when token burning is not allowed to the caller
*/
error BurnAccessError();
/**
* @notice Emitted when the token allowance is not sufficient for burning
*/
error BurnAllowanceError();
/**
* @notice Emitted when token minting is not allowed to the caller
*/
error MintAccessError();
/**
* @notice Initializes the MultichainTokenBase properties of descendant contracts
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _decimals The ERC20 token decimals
* @param _useExplicitAccess The mint and burn actions access flag
*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
bool _useExplicitAccess
) ERC20(_name, _symbol, _decimals) {
underlying = address(0);
useExplicitAccess = _useExplicitAccess;
}
/**
* @notice Updates the Multichain Router role status for the account
* @param _account The account address
* @param _value The Multichain Router role status flag
*/
function setMultichainRouter(address _account, bool _value) external onlyManager {
_setMultichainRouter(_account, _value);
}
/**
* @notice Mints tokens and assigns them to the account, increasing the total supply
* @dev The mint function returns a boolean value, as required by the Anyswap ERC20 standard
* @param _to The token receiver account address
* @param _amount The number of tokens to mint
* @return Token minting success status
*/
function mint(address _to, uint256 _amount) external whenNotPaused returns (bool) {
bool condition = isMultichainRouter(msg.sender) ||
(useExplicitAccess && _isExplicitMinter());
if (!condition) {
revert MintAccessError();
}
_mint(_to, _amount);
return true;
}
/**
* @notice Burns tokens from the account, reducing the total supply
* @dev The burn function returns a boolean value, as required by the Anyswap ERC20 standard
* @param _from The token holder account address
* @param _amount The number of tokens to burn
* @return Token burning success status
*/
function burn(address _from, uint256 _amount) external whenNotPaused returns (bool) {
bool condition = isMultichainRouter(msg.sender) ||
(useExplicitAccess && _isExplicitBurner());
if (!condition) {
revert BurnAccessError();
}
if (_from == address(0)) {
revert ZeroAddressError();
}
uint256 allowed = allowance[_from][msg.sender];
if (allowed < _amount) {
revert BurnAllowanceError();
}
if (allowed != Constants.INFINITY) {
// Cannot overflow because the allowed value
// is greater or equal to the amount
unchecked {
allowance[_from][msg.sender] = allowed - _amount;
}
}
_burn(_from, _amount);
return true;
}
/**
* @dev Override to add explicit minter access
*/
function _isExplicitMinter() internal view virtual returns (bool) {
return false;
}
/**
* @dev Override to add explicit burner access
*/
function _isExplicitBurner() internal view virtual returns (bool) {
return false;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Pausable as PausableBase } from '@openzeppelin/contracts/security/Pausable.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
/**
* @title Pausable
* @notice Base contract that implements the emergency pause mechanism
*/
abstract contract Pausable is PausableBase, ManagerRole {
/**
* @notice Enter pause state
*/
function pause() external onlyManager whenNotPaused {
_pause();
}
/**
* @notice Exit pause state
*/
function unpause() external onlyManager whenPaused {
_unpause();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
/**
* @title AssetSpenderRole
* @notice Base contract that implements the Asset Spender role
*/
abstract contract AssetSpenderRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('AssetSpender');
/**
* @notice Emitted when the Asset Spender role status for the account is updated
* @param account The account address
* @param value The Asset Spender role status flag
*/
event SetAssetSpender(address indexed account, bool indexed value);
/**
* @notice Emitted when the caller is not an Asset Spender role bearer
*/
error OnlyAssetSpenderError();
/**
* @dev Modifier to check if the caller is an Asset Spender role bearer
*/
modifier onlyAssetSpender() {
if (!isAssetSpender(msg.sender)) {
revert OnlyAssetSpenderError();
}
_;
}
/**
* @notice Getter of the Asset Spender role bearer count
* @return The Asset Spender role bearer count
*/
function assetSpenderCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Asset Spender role bearers
* @return The complete list of the Asset Spender role bearers
*/
function fullAssetSpenderList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Asset Spender role bearer status
* @param _account The account address
*/
function isAssetSpender(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setAssetSpender(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetAssetSpender(_account, _value);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
/**
* @title BurnerRole
* @notice Base contract that implements the Burner role
*/
abstract contract BurnerRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Burner');
/**
* @notice Emitted when the Burner role status for the account is updated
* @param account The account address
* @param value The Burner role status flag
*/
event SetBurner(address indexed account, bool indexed value);
/**
* @notice Getter of the Burner role bearer count
* @return The Burner role bearer count
*/
function burnerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Burner role bearers
* @return The complete list of the Burner role bearers
*/
function fullBurnerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Burner role bearer status
* @param _account The account address
*/
function isBurner(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setBurner(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetBurner(_account, _value);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from './RoleBearers.sol';
/**
* @title ManagerRole
* @notice Base contract that implements the Manager role.
* The manager role is a high-permission role for core team members only.
* Managers can set vaults and routers addresses, fees, cross-chain protocols,
* and other parameters for Interchain (cross-chain) swaps and single-network swaps.
* Please note, the manager role is unique for every contract,
* hence different addresses may be assigned as managers for different contracts.
*/
abstract contract ManagerRole is Ownable, RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Manager');
/**
* @notice Emitted when the Manager role status for the account is updated
* @param account The account address
* @param value The Manager role status flag
*/
event SetManager(address indexed account, bool indexed value);
/**
* @notice Emitted when the Manager role status for the account is renounced
* @param account The account address
*/
event RenounceManagerRole(address indexed account);
/**
* @notice Emitted when the caller is not a Manager role bearer
*/
error OnlyManagerError();
/**
* @dev Modifier to check if the caller is a Manager role bearer
*/
modifier onlyManager() {
if (!isManager(msg.sender)) {
revert OnlyManagerError();
}
_;
}
/**
* @notice Updates the Manager role status for the account
* @param _account The account address
* @param _value The Manager role status flag
*/
function setManager(address _account, bool _value) public onlyOwner {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetManager(_account, _value);
}
/**
* @notice Renounces the Manager role
*/
function renounceManagerRole() external onlyManager {
_setRoleBearer(ROLE_KEY, msg.sender, false);
emit RenounceManagerRole(msg.sender);
}
/**
* @notice Getter of the Manager role bearer count
* @return The Manager role bearer count
*/
function managerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Manager role bearers
* @return The complete list of the Manager role bearers
*/
function fullManagerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Manager role bearer status
* @param _account The account address
*/
function isManager(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _initRoles(
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) internal {
address ownerAddress = _owner == address(0) ? msg.sender : _owner;
for (uint256 index; index < _managers.length; index++) {
setManager(_managers[index], true);
}
if (_addOwnerToManagers && !isManager(ownerAddress)) {
setManager(ownerAddress, true);
}
if (ownerAddress != msg.sender) {
transferOwnership(ownerAddress);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
/**
* @title MinterRole
* @notice Base contract that implements the Minter role
*/
abstract contract MinterRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Minter');
/**
* @notice Emitted when the Minter role status for the account is updated
* @param account The account address
* @param value The Minter role status flag
*/
event SetMinter(address indexed account, bool indexed value);
/**
* @notice Getter of the Minter role bearer count
* @return The Minter role bearer count
*/
function minterCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Minter role bearers
* @return The complete list of the Minter role bearers
*/
function fullMinterList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Minter role bearer status
* @param _account The account address
*/
function isMinter(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setMinter(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMinter(_account, _value);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { RoleBearers } from './RoleBearers.sol';
/**
* @title MultichainRouterRole
* @notice Base contract that implements the Multichain Router role
*/
abstract contract MultichainRouterRole is RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('MultichainRouter');
/**
* @notice Emitted when the Multichain Router role status for the account is updated
* @param account The account address
* @param value The Multichain Router role status flag
*/
event SetMultichainRouter(address indexed account, bool indexed value);
/**
* @notice Getter of the Multichain Router role bearer count
* @return The Multichain Router role bearer count
*/
function multichainRouterCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Multichain Router role bearers
* @return The complete list of the Multichain Router role bearers
*/
function fullMultichainRouterList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Multichain Router role bearer status
* @param _account The account address
*/
function isMultichainRouter(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _setMultichainRouter(address _account, bool _value) internal {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetMultichainRouter(_account, _value);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;
/**
* @title RoleBearers
* @notice Base contract that implements role-based access control
* @dev A custom implementation providing full role bearer lists
*/
abstract contract RoleBearers {
mapping(bytes32 /*roleKey*/ => address[] /*roleBearers*/) private roleBearerTable;
mapping(bytes32 /*roleKey*/ => mapping(address /*account*/ => DataStructures.OptionalValue /*status*/))
private roleBearerIndexTable;
function _setRoleBearer(bytes32 _roleKey, address _account, bool _value) internal {
DataStructures.uniqueAddressListUpdate(
roleBearerTable[_roleKey],
roleBearerIndexTable[_roleKey],
_account,
_value,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
}
function _isRoleBearer(bytes32 _roleKey, address _account) internal view returns (bool) {
return roleBearerIndexTable[_roleKey][_account].isSet;
}
function _roleBearerCount(bytes32 _roleKey) internal view returns (uint256) {
return roleBearerTable[_roleKey].length;
}
function _fullRoleBearerList(bytes32 _roleKey) internal view returns (address[] memory) {
return roleBearerTable[_roleKey];
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title SystemVersionId
* @notice Base contract providing the system version identifier
*/
abstract contract SystemVersionId {
/**
* @dev The system version identifier
*/
uint256 public constant SYSTEM_VERSION_ID = uint256(keccak256('Initial'));
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ERC20 } from 'solmate/src/tokens/ERC20.sol';
import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { ITokenDecimals } from './interfaces/ITokenDecimals.sol';
import { CallerGuard } from './CallerGuard.sol';
import { MultichainTokenBase } from './MultichainTokenBase.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
/**
* @title VaultBase
* @notice Base contract that implements the vault logic
*/
abstract contract VaultBase is MultichainTokenBase, ReentrancyGuard, CallerGuard {
/**
* @dev The vault asset address
*/
address public immutable asset;
/**
* @dev The total vault token supply limit
*/
uint256 public totalSupplyLimit;
/**
* @notice Emitted when the total supply limit is set
* @param limit The total supply limit value
*/
event SetTotalSupplyLimit(uint256 limit);
/**
* @notice Emitted when a deposit action is performed
* @param caller The address of the depositor account
* @param assetAmount The amount of the deposited asset
*/
event Deposit(address indexed caller, uint256 assetAmount);
/**
* @notice Emitted when a withdrawal action is performed
* @param caller The address of the withdrawal account
* @param assetAmount The amount of the withdrawn asset
*/
event Withdraw(address indexed caller, uint256 assetAmount);
/**
* @notice Emitted when the total supply limit is exceeded
*/
error TotalSupplyLimitError();
/**
* @notice Emitted when a deposit is attempted with a zero amount
*/
error ZeroAmountError();
/**
* @notice Initializes the VaultBase properties of descendant contracts
* @param _asset The vault asset address
* @param _name The ERC20 token name
* @param _symbol The ERC20 token symbol
* @param _depositAllowed The initial state of deposit availability
*/
constructor(
address _asset,
string memory _name,
string memory _symbol,
bool _depositAllowed
) MultichainTokenBase(_name, _symbol, ITokenDecimals(_asset).decimals(), false) {
asset = _asset;
_setTotalSupplyLimit(_depositAllowed ? Constants.INFINITY : 0);
}
/**
* @notice Sets the total supply
* @dev Decimals = vault token decimals = asset decimals
* @param _limit The total supply limit value
*/
function setTotalSupplyLimit(uint256 _limit) external onlyManager {
_setTotalSupplyLimit(_limit);
}
/**
* @notice Performs a deposit action. User deposits usdc/usdt for iusdc/iusdt used in Stablecoin Farm.
* @param _assetAmount The amount of the deposited asset
*/
function deposit(uint256 _assetAmount) external virtual whenNotPaused nonReentrant checkCaller {
if (_assetAmount == 0) {
revert ZeroAmountError();
}
if (totalSupply + _assetAmount > totalSupplyLimit) {
revert TotalSupplyLimitError();
}
// Need to transfer before minting or ERC777s could reenter
TransferHelper.safeTransferFrom(asset, msg.sender, address(this), _assetAmount);
_mint(msg.sender, _assetAmount);
emit Deposit(msg.sender, _assetAmount);
}
/**
* @notice Performs a withdrawal action
* @param _assetAmount The amount of the withdrawn asset
*/
function withdraw(
uint256 _assetAmount
) external virtual whenNotPaused nonReentrant checkCaller {
_burn(msg.sender, _assetAmount);
emit Withdraw(msg.sender, _assetAmount);
TransferHelper.safeTransfer(asset, msg.sender, _assetAmount);
}
function _setTotalSupplyLimit(uint256 _limit) private {
totalSupplyLimit = _limit;
emit SetTotalSupplyLimit(_limit);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address[]","name":"_assetSpenders","type":"address[]"},{"internalType":"bool","name":"_depositAllowed","type":"bool"},{"internalType":"bool","name":"_variableRepaymentEnabled","type":"bool"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_managers","type":"address[]"},{"internalType":"bool","name":"_addOwnerToManagers","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BurnAccessError","type":"error"},{"inputs":[],"name":"BurnAllowanceError","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerGuardError","type":"error"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[],"name":"MintAccessError","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NonContractAddressError","type":"error"},{"inputs":[],"name":"OnlyAssetSpenderError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferFromError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"inputs":[],"name":"TokenBurnError","type":"error"},{"inputs":[],"name":"TokenDecimalsError","type":"error"},{"inputs":[],"name":"TotalSupplyLimitError","type":"error"},{"inputs":[],"name":"VariableRepaymentNotEnabledError","type":"error"},{"inputs":[],"name":"VariableTokenAlreadySetError","type":"error"},{"inputs":[],"name":"VariableTokenNotSetError","type":"error"},{"inputs":[],"name":"ZeroAddressError","type":"error"},{"inputs":[],"name":"ZeroAmountError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RedeemVariableToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RenounceManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetAssetSpender","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum CallerGuard.CallerGuardMode","name":"callerGuardMode","type":"uint8"}],"name":"SetCallerGuardMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"isListed","type":"bool"}],"name":"SetListedCallerGuardContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetMultichainRouter","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetTotalSupplyLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"variableRepaymentEnabled","type":"bool"}],"name":"SetVariableRepaymentEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"variableToken","type":"address"}],"name":"SetVariableToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SYSTEM_VERSION_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetSpenderCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"callerGuardMode","outputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkVariableTokenState","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetAmount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fullAssetSpenderList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullListedCallerGuardContractList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullManagerList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullMultichainRouterList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAssetSpender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isListedCallerGuardContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isMultichainRouter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listedCallerGuardContractCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"listedCallerGuardContractIndexMap","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"listedCallerGuardContractList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"multichainRouterCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeemVariableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_forVariableBalance","type":"bool"}],"name":"requestAsset","outputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setAssetSpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"_callerGuardMode","type":"uint8"}],"name":"setCallerGuardMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"flag","type":"bool"}],"internalType":"struct AccountToFlag[]","name":"_items","type":"tuple[]"}],"name":"setListedCallerGuardContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setMultichainRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"setTotalSupplyLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_variableRepaymentEnabled","type":"bool"}],"name":"setVariableRepaymentEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_variableToken","type":"address"}],"name":"setVariableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupplyLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"variableRepaymentEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"variableToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetAmount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610140604052600a805460ff191690553480156200001c57600080fd5b5060405162003aaf38038062003aaf8339810160408190526200003f91620009c7565b888888878282856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa919062000adf565b6000805460ff19168155838383620000c233620001b4565b6003620000d0848262000b9a565b506004620000df838262000b9a565b5060ff81166080524660a052620000f56200020d565b60c0525050600060e0525015156101005250506001600955506001600160a01b0384166101205262000137816200012e576000620002a9565b600019620002a9565b5050505060005b86518110156200018c576200017787828151811062000161576200016162000c66565b60200260200101516001620002e460201b60201c565b80620001838162000c92565b9150506200013e565b5062000198846200034d565b620001a583838362000396565b50505050505050505062000d58565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600360405162000241919062000cae565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600d8190556040518181527f95e8c9f3b9477918d3e5407ba96fac8e2084722c9562942bac414734bdf8f8049060200160405180910390a150565b620003117fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c2174838362000450565b604051811515906001600160a01b038416907fc6b049f4dc9561b397b0cef913ea5f18165b682b193be62c0bbbf9ca8763aeba90600090a35050565b600e805460ff60a01b1916600160a01b831515908102919091179091556040517fdf888ec24e9081be857eb58887c4c9e546edf94ee7dbc643c07f69dd32c0d13590600090a250565b60006001600160a01b03841615620003af5783620003b1565b335b905060005b83518110156200040457620003ef848281518110620003d957620003d962000c66565b602002602001015160016200047960201b60201c565b80620003fb8162000c92565b915050620003b6565b508180156200041b57506200041981620004ec565b155b156200042e576200042e81600162000479565b6001600160a01b03811633146200044a576200044a816200052e565b50505050565b600083815260016020908152604080832060029092529091206200044a919084846064620005b1565b62000483620005e4565b620004b07f6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6f838362000450565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff165b92915050565b62000538620005e4565b6001600160a01b038116620005a35760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b620005ae81620001b4565b50565b600082620005cc57620005c686868662000648565b620005da565b620005da868686856200077d565b9695505050505050565b6000546001600160a01b03610100909104163314620006465760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200059a565b565b6001600160a01b0381166000908152602083905260409020805460ff1690811562000775576001808201548654909160009162000686919062000d2c565b90508082146200071a576000878281548110620006a757620006a762000c66565b9060005260206000200160009054906101000a90046001600160a01b0316905080888481548110620006dd57620006dd62000c66565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806200072d576200072d62000d42565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156200082a5784548211620007c35760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b80516001600160a01b03811681146200084a57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b03811182821017156200089057620008906200084f565b604052919050565b600082601f830112620008aa57600080fd5b81516001600160401b03811115620008c657620008c66200084f565b6020620008dc601f8301601f1916820162000865565b8281528582848701011115620008f157600080fd5b60005b8381101562000911578581018301518282018401528201620008f4565b506000928101909101919091529392505050565b600082601f8301126200093757600080fd5b815160206001600160401b038211156200095557620009556200084f565b8160051b6200096682820162000865565b92835284810182019282810190878511156200098157600080fd5b83870192505b84831015620009ab576200099b8362000832565b8252918301919083019062000987565b979650505050505050565b805180151581146200084a57600080fd5b60008060008060008060008060006101208a8c031215620009e757600080fd5b620009f28a62000832565b60208b01519099506001600160401b038082111562000a1057600080fd5b62000a1e8d838e0162000898565b995060408c015191508082111562000a3557600080fd5b62000a438d838e0162000898565b985060608c015191508082111562000a5a57600080fd5b62000a688d838e0162000925565b975062000a7860808d01620009b6565b965062000a8860a08d01620009b6565b955062000a9860c08d0162000832565b945060e08c015191508082111562000aaf57600080fd5b5062000abe8c828d0162000925565b92505062000ad06101008b01620009b6565b90509295985092959850929598565b60006020828403121562000af257600080fd5b815160ff8116811462000b0457600080fd5b9392505050565b600181811c9082168062000b2057607f821691505b60208210810362000b4157634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000b9557600081815260208120601f850160051c8101602086101562000b705750805b601f850160051c820191505b8181101562000b915782815560010162000b7c565b5050505b505050565b81516001600160401b0381111562000bb65762000bb66200084f565b62000bce8162000bc7845462000b0b565b8462000b47565b602080601f83116001811462000c06576000841562000bed5750858301515b600019600386901b1c1916600185901b17855562000b91565b600085815260208120601f198616915b8281101562000c375788860151825594840194600190910190840162000c16565b508582101562000c565787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000ca75762000ca762000c7c565b5060010190565b600080835462000cbe8162000b0b565b6001828116801562000cd9576001811462000cef5762000d20565b60ff198416875282151583028701945062000d20565b8760005260208060002060005b8581101562000d175781548a82015290840190820162000cfc565b50505082870194505b50929695505050505050565b8181038181111562000528576200052862000c7c565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e0516101005161012051612cc862000de7600039600081816105cf0152818161062f01528181610cf601528181610d5601528181610f97015281816110e40152818161110d015261163d01526000818161101d015261137d015260006106dd01526000610e0a01526000610dda01526000818161054a015261122e0152612cc86000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80636f307dc3116101de578063b6b55f251161010f578063e3725b15116100ad578063f3ae24151161007c578063f3ae2415146108db578063f977350c146108ee578063fe14e8c314610901578063fe8fc8d41461091457600080fd5b8063e3725b151461089a578063eedc966a146108a2578063f00ecca3146108b5578063f2fde38b146108c857600080fd5b8063c2c518e1116100e9578063c2c518e114610841578063d505accf14610849578063d883d8b11461085c578063dd62ed3e1461086f57600080fd5b8063b6b55f2514610812578063bac21a2214610825578063c116a3cb1461082e57600080fd5b80638da5cb5b1161017c5780639dc29fac116101565780639dc29fac146107d1578063a5e90eee146107e4578063a8c9a27a146107f7578063a9059cbb146107ff57600080fd5b80638da5cb5b1461077557806395d89b411461078b5780639c90dfa11461079357600080fd5b80637b25b4d4116101b85780637b25b4d4146107275780637c3d6de11461073a5780637ecebe001461074d5780638456cb591461076d57600080fd5b80636f307dc3146106d857806370a08231146106ff578063715018a61461071f57600080fd5b8063313ce567116102c3578063440d7248116102615780635c56ca35116102305780635c56ca35146106985780635c975abb146106ab578063607ab5e5146106b65780636b56a691146106d057600080fd5b8063440d72481461061f5780634b15b2a91461065f5780634ba3bf7e146106725780635c05468b1461068557600080fd5b806338d52e0f1161029d57806338d52e0f146105ca5780633ef43212146105f15780633f4ba83a1461060457806340c10f191461060c57600080fd5b8063313ce56714610545578063341328c51461057e5780633644e515146105c257600080fd5b806318160ddd116103305780632a3ffb8a1161030a5780632a3ffb8a146104c15780632c966a34146104ff5780632e1a7d4d1461051f57806330eb12781461053257600080fd5b806318160ddd146104905780631b5c1d0e1461049957806323b872dd146104ae57600080fd5b8063095ea7b31161036c578063095ea7b3146103fb5780630f9374101461041e578063103b73971461042657806317daf0b41461046457600080fd5b806304e535e21461039357806306fdde03146103b1578063093f0e27146103c6575b600080fd5b61039b610928565b6040516103a891906126c8565b60405180910390f35b6103b961098a565b6040516103a89190612739565b6103ed7f22ad9585a395edc8067b50da4778cafbb7fa2c4bbd7619fad6aeba403857fd7481565b6040519081526020016103a8565b61040e610409366004612783565b610a18565b60405190151581526020016103a8565b61039b610a85565b600080516020612c3383398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546103ed565b61040e6104723660046127ad565b6001600160a01b03166000908152600c602052604090205460ff1690565b6103ed60055481565b6104ac6104a73660046127cf565b610aa3565b005b61040e6104bc3660046127e8565b610ad5565b600080516020612c7383398151915260005260016020527f5a35d0a0fb7e3bcb482aad5b9886840a8073f28d39a0181c254a9e207a441094546103ed565b610507610bb5565b6040516001600160a01b0390911681526020016103a8565b6104ac61052d3660046127cf565b610c1b565b6104ac610540366004612783565b610d26565b61056c7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016103a8565b6105ab61058c3660046127ad565b600c602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016103a8565b6103ed610dd6565b6105077f000000000000000000000000000000000000000000000000000000000000000081565b6104ac6105ff3660046127cf565b610e2c565b6104ac610fc8565b61040e61061a366004612783565b611000565b61040e61062d3660046127ad565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b61050761066d366004612832565b61107a565b6104ac610680366004612872565b611133565b61040e6106933660046127ad565b611163565b61040e6106a63660046127ad565b61117d565b60005460ff1661040e565b600a546106c39060ff1681565b6040516103a891906128bf565b600b546103ed565b6105077f000000000000000000000000000000000000000000000000000000000000000081565b6103ed61070d3660046127ad565b60066020526000908152604090205481565b6104ac611197565b6105076107353660046127cf565b6111a9565b6104ac6107483660046127ad565b6111d3565b6103ed61075b3660046127ad565b60086020526000908152604090205481565b6104ac61131d565b60005461010090046001600160a01b0316610507565b6103b9611353565b600080516020612c1383398151915260005260016020527fb6368b31e79ffb73a14a00fbd9c0dbbe43a3a26df7f98e18d14334693e18dfce546103ed565b61040e6107df366004612783565b611360565b6104ac6107f2366004612872565b611479565b61039b6114d6565b61040e61080d366004612783565b6114ef565b6104ac6108203660046127cf565b611555565b6103ed600d5481565b6104ac61083c366004612872565b6116ad565b6104ac6116dd565b6104ac6108573660046128f6565b61174a565b6104ac61086a366004612963565b61198e565b6103ed61087d366004612980565b600760209081526000928352604080842090915290825290205481565b61039b6119bd565b6103ed6108b03660046127ad565b6119d6565b600e54610507906001600160a01b031681565b6104ac6108d63660046127ad565b611a71565b61040e6108e93660046127ad565b611ae7565b6104ac6108fc3660046129b3565b611b01565b6104ac61090f3660046129d4565b611b89565b600e5461040e90600160a01b900460ff1681565b6060600b80548060200260200160405190810160405280929190818152602001828054801561098057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610962575b5050505050905090565b6003805461099790612a49565b80601f01602080910402602001604051908101604052809291908181526020018280546109c390612a49565b8015610a105780601f106109e557610100808354040283529160200191610a10565b820191906000526020600020905b8154815290600101906020018083116109f357829003601f168201915b505050505081565b3360008181526007602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a739086815260200190565b60405180910390a35060015b92915050565b6060610a9e600080516020612c13833981519152611c9a565b905090565b610aac33611ae7565b610ac957604051637c3ea23f60e01b815260040160405180910390fd5b610ad281611d06565b50565b6001600160a01b03831660009081526007602090815260408083203384529091528120546000198114610b3157610b0c8382612a99565b6001600160a01b03861660009081526007602090815260408083203384529091529020555b6001600160a01b03851660009081526006602052604081208054859290610b59908490612a99565b90915550506001600160a01b0380851660008181526006602052604090819020805487019055519091871690600080516020612c5383398151915290610ba29087815260200190565b60405180910390a3506001949350505050565b600e54600090600160a01b900460ff16610be257604051634dd32fa760e11b815260040160405180910390fd5b600e546001600160a01b0316610c0b57604051630d51877360e21b815260040160405180910390fd5b50600e546001600160a01b031690565b610c23611d41565b610c2b611d87565b333214610cb25760006002600a5460ff166002811115610c4d57610c4d6128a9565b1480610c8957506001600a5460ff166002811115610c6d57610c6d6128a9565b148015610c895750336000908152600c602052604090205460ff165b905080610cb057604051630fa0970d60e11b81523360048201526024015b60405180910390fd5b505b610cbc3382611de0565b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2610d1c7f00000000000000000000000000000000000000000000000000000000000000003383611e4a565b610ad26001600955565b610d2f33611ae7565b610d4c57604051637c3ea23f60e01b815260040160405180910390fd5b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811690831603610d9857604051634477699960e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610dcb57610dc73382611f3c565b5050565b610dc7823383611e4a565b60007f00000000000000000000000000000000000000000000000000000000000000004614610e0757610a9e611fca565b507f000000000000000000000000000000000000000000000000000000000000000090565b610e34611d41565b610e3c611d87565b333214610ebe5760006002600a5460ff166002811115610e5e57610e5e6128a9565b1480610e9a57506001600a5460ff166002811115610e7e57610e7e6128a9565b148015610e9a5750336000908152600c602052604090205460ff165b905080610ebc57604051630fa0970d60e11b8152336004820152602401610ca7565b505b610ec6610bb5565b50600e54604051632770a7eb60e21b8152336004820152602481018390526000916001600160a01b031690639dc29fac906044016020604051808303816000875af1158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190612aac565b905080610f5d5760405163a294042360e01b815260040160405180910390fd5b60405182815233907f16aab25bf023c1724fe661e47886a1083e99fb9533f0947445acb8974a6778c89060200160405180910390a2610fbd7f00000000000000000000000000000000000000000000000000000000000000003384611e4a565b50610ad26001600955565b610fd133611ae7565b610fee57604051637c3ea23f60e01b815260040160405180910390fd5b610ff6612064565b610ffe6120ad565b565b600061100a611d41565b600061101533611163565b8061104657507f00000000000000000000000000000000000000000000000000000000000000008015611046575060005b905080611066576040516371d2156960e01b815260040160405180910390fd5b61107084846120ff565b5060019392505050565b6000611084611d41565b61108d3361117d565b6110aa5760405163085c44cb60e31b815260040160405180910390fd5b8180156110c15750600e54600160a01b900460ff16155b156110df57604051634dd32fa760e11b815260040160405180910390fd5b61110a7f00000000000000000000000000000000000000000000000000000000000000008486611e4a565b507f00000000000000000000000000000000000000000000000000000000000000009392505050565b61113c33611ae7565b61115957604051637c3ea23f60e01b815260040160405180910390fd5b610dc78282612151565b6000610a7f600080516020612c73833981519152836121a6565b6000610a7f600080516020612c13833981519152836121a6565b61119f6121d1565b610ffe6000612231565b600b81815481106111b957600080fd5b6000918252602090912001546001600160a01b0316905081565b6111dc33611ae7565b6111f957604051637c3ea23f60e01b815260040160405180910390fd5b600e546001600160a01b0316156112235760405163b347c0ad60e01b815260040160405180910390fd5b61122c8161228a565b7f000000000000000000000000000000000000000000000000000000000000000060ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561128e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b29190612ac9565b60ff16146112d357604051637265cffd60e11b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0383169081179091556040517fb366d6f570d256c768970b0082f8d0cea95a76afa28b518f9e6eb033d84e656a90600090a250565b61132633611ae7565b61134357604051637c3ea23f60e01b815260040160405180910390fd5b61134b611d41565b610ffe6122bd565b6004805461099790612a49565b600061136a611d41565b600061137533611163565b806113a657507f000000000000000000000000000000000000000000000000000000000000000080156113a6575060005b9050806113c6576040516305fb1f3f60e51b815260040160405180910390fd5b6001600160a01b0384166113ed57604051633efa09af60e01b815260040160405180910390fd5b6001600160a01b038416600090815260076020908152604080832033845290915290205483811015611432576040516308688c9b60e01b815260040160405180910390fd5b6000198114611464576001600160a01b0385166000908152600760209081526040808320338452909152902084820390555b61146e8585611de0565b506001949350505050565b6114816121d1565b61149a600080516020612c3383398151915283836122fa565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6060610a9e600080516020612c73833981519152611c9a565b33600090815260066020526040812080548391908390611510908490612a99565b90915550506001600160a01b03831660008181526006602052604090819020805485019055513390600080516020612c5383398151915290610a739086815260200190565b61155d611d41565b611565611d87565b3332146115e75760006002600a5460ff166002811115611587576115876128a9565b14806115c357506001600a5460ff1660028111156115a7576115a76128a9565b1480156115c35750336000908152600c602052604090205460ff165b9050806115e557604051630fa0970d60e11b8152336004820152602401610ca7565b505b8060000361160857604051636e0ccc0760e01b815260040160405180910390fd5b600d54816005546116199190612ae6565b111561163857604051637872c6e360e01b815260040160405180910390fd5b6116647f0000000000000000000000000000000000000000000000000000000000000000333084612327565b61166e33826120ff565b60405181815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2610ad26001600955565b6116b633611ae7565b6116d357604051637c3ea23f60e01b815260040160405180910390fd5b610dc78282612422565b6116e633611ae7565b61170357604051637c3ea23f60e01b815260040160405180910390fd5b61171d600080516020612c338339815191523360006122fa565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b4284101561179a5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ca7565b600060016117a6610dd6565b6001600160a01b038a811660008181526008602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156118b2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906118e85750876001600160a01b0316816001600160a01b0316145b6119255760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ca7565b6001600160a01b0390811660009081526007602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b61199733611ae7565b6119b457604051637c3ea23f60e01b815260040160405180910390fd5b610ad281612477565b6060610a9e600080516020612c33833981519152611c9a565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611a04575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7f9190612af9565b919050565b611a796121d1565b6001600160a01b038116611ade5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ca7565b610ad281612231565b6000610a7f600080516020612c33833981519152836121a6565b611b0a33611ae7565b611b2757604051637c3ea23f60e01b815260040160405180910390fd5b600a805482919060ff19166001836002811115611b4657611b466128a9565b0217905550806002811115611b5d57611b5d6128a9565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b611b9233611ae7565b611baf57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015611c955736838383818110611bcd57611bcd612b12565b9050604002019050806020016020810190611be89190612963565b15611c0257611c02611bfd60208301836127ad565b61228a565b611c2d600b600c611c1660208501856127ad565b611c266040860160208701612963565b60646124c0565b50611c3e6040820160208301612963565b1515611c4d60208301836127ad565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a35080611c8d81612b28565b915050611bb2565b505050565b600081815260016020908152604091829020805483518184028101840190945280845260609392830182828015611cfa57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cdc575b50505050509050919050565b600d8190556040518181527f95e8c9f3b9477918d3e5407ba96fac8e2084722c9562942bac414734bdf8f8049060200160405180910390a150565b60005460ff1615610ffe5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ca7565b600260095403611dd95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ca7565b6002600955565b6001600160a01b03821660009081526006602052604081208054839290611e08908490612a99565b90915550506005805482900390556040518181526000906001600160a01b03841690600080516020612c53833981519152906020015b60405180910390a35050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611ea69190612b41565b6000604051808303816000865af19150503d8060008114611ee3576040519150601f19603f3d011682016040523d82523d6000602084013e611ee8565b606091505b50915091506000828015611f14575081511580611f14575081806020019051810190611f149190612aac565b905080611f3457604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b604080516000808252602082019092526001600160a01b038416908390604051611f669190612b41565b60006040518083038185875af1925050503d8060008114611fa3576040519150601f19603f3d011682016040523d82523d6000602084013e611fa8565b606091505b5050905080611c9557604051632e05b05360e21b815260040160405180910390fd5b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6003604051611ffc9190612b5d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60005460ff16610ffe5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ca7565b6120b5612064565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b80600560008282546121119190612ae6565b90915550506001600160a01b038216600081815260066020908152604080832080548601905551848152600080516020612c538339815191529101611e3e565b61216a600080516020612c7383398151915283836122fa565b604051811515906001600160a01b038416907f2b535dea3b8ec7fb244a57e39a42aee5f6f4871306457173aa18f49a96e8c78090600090a35050565b60009182526002602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000546001600160a01b03610100909104163314610ffe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca7565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6001600160a01b0381163b610ad257604051638c50d7cd60e01b81526001600160a01b0382166004820152602401610ca7565b6122c5611d41565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586120e23390565b600083815260016020908152604080832060029092529091206123219190848460646124c0565b50505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161238b9190612b41565b6000604051808303816000865af19150503d80600081146123c8576040519150601f19603f3d011682016040523d82523d6000602084013e6123cd565b606091505b509150915060008280156123f95750815115806123f95750818060200190518101906123f99190612aac565b90508061241957604051632d9d5b4160e01b815260040160405180910390fd5b50505050505050565b61243b600080516020612c1383398151915283836122fa565b604051811515906001600160a01b038416907fc6b049f4dc9561b397b0cef913ea5f18165b682b193be62c0bbbf9ca8763aeba90600090a35050565b600e805460ff60a01b1916600160a01b831515908102919091179091556040517fdf888ec24e9081be857eb58887c4c9e546edf94ee7dbc643c07f69dd32c0d13590600090a250565b6000826124d7576124d28686866124ed565b6124e3565b6124e386868685612615565b9695505050505050565b6001600160a01b0381166000908152602083905260409020805460ff1690811561260d57600180820154865490916000916125289190612a99565b90508082146125b557600087828154811061254557612545612b12565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811061257857612578612b12565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806125c5576125c5612bfc565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156126c057845482116126595760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156127095783516001600160a01b0316835292840192918401916001016126e4565b50909695505050505050565b60005b83811015612730578181015183820152602001612718565b50506000910152565b6020815260008251806020840152612758816040850160208701612715565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114611a6c57600080fd5b6000806040838503121561279657600080fd5b61279f8361276c565b946020939093013593505050565b6000602082840312156127bf57600080fd5b6127c88261276c565b9392505050565b6000602082840312156127e157600080fd5b5035919050565b6000806000606084860312156127fd57600080fd5b6128068461276c565b92506128146020850161276c565b9150604084013590509250925092565b8015158114610ad257600080fd5b60008060006060848603121561284757600080fd5b833592506128576020850161276c565b9150604084013561286781612824565b809150509250925092565b6000806040838503121561288557600080fd5b61288e8361276c565b9150602083013561289e81612824565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600383106128e157634e487b7160e01b600052602160045260246000fd5b91905290565b60ff81168114610ad257600080fd5b600080600080600080600060e0888a03121561291157600080fd5b61291a8861276c565b96506129286020890161276c565b955060408801359450606088013593506080880135612946816128e7565b9699959850939692959460a0840135945060c09093013592915050565b60006020828403121561297557600080fd5b81356127c881612824565b6000806040838503121561299357600080fd5b61299c8361276c565b91506129aa6020840161276c565b90509250929050565b6000602082840312156129c557600080fd5b8135600381106127c857600080fd5b600080602083850312156129e757600080fd5b823567ffffffffffffffff808211156129ff57600080fd5b818501915085601f830112612a1357600080fd5b813581811115612a2257600080fd5b8660208260061b8501011115612a3757600080fd5b60209290920196919550909350505050565b600181811c90821680612a5d57607f821691505b602082108103612a7d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a7f57610a7f612a83565b600060208284031215612abe57600080fd5b81516127c881612824565b600060208284031215612adb57600080fd5b81516127c8816128e7565b80820180821115610a7f57610a7f612a83565b600060208284031215612b0b57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600060018201612b3a57612b3a612a83565b5060010190565b60008251612b53818460208701612715565b9190910192915050565b600080835481600182811c915080831680612b7957607f831692505b60208084108203612b9857634e487b7160e01b86526022600452602486fd5b818015612bac5760018114612bc157612bee565b60ff1986168952841515850289019650612bee565b60008a81526020902060005b86811015612be65781548b820152908501908301612bcd565b505084890196505b509498975050505050505050565b634e487b7160e01b600052603160045260246000fdfeab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c21746d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef98e2d91934cad395982d17afdb76da8ef5d5f4e6341e368f19914b44485e5886a26469706673582212200ee1c95fd02a3e4bf7c8f95fb4361be5f6a2de2d0ceacf240da7a42286527e5f64736f6c63430008130033000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b930000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000e496e746572706f727420555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005695553445400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000007b2e3fc7510d1a51b3bef735f9854465892193540000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80636f307dc3116101de578063b6b55f251161010f578063e3725b15116100ad578063f3ae24151161007c578063f3ae2415146108db578063f977350c146108ee578063fe14e8c314610901578063fe8fc8d41461091457600080fd5b8063e3725b151461089a578063eedc966a146108a2578063f00ecca3146108b5578063f2fde38b146108c857600080fd5b8063c2c518e1116100e9578063c2c518e114610841578063d505accf14610849578063d883d8b11461085c578063dd62ed3e1461086f57600080fd5b8063b6b55f2514610812578063bac21a2214610825578063c116a3cb1461082e57600080fd5b80638da5cb5b1161017c5780639dc29fac116101565780639dc29fac146107d1578063a5e90eee146107e4578063a8c9a27a146107f7578063a9059cbb146107ff57600080fd5b80638da5cb5b1461077557806395d89b411461078b5780639c90dfa11461079357600080fd5b80637b25b4d4116101b85780637b25b4d4146107275780637c3d6de11461073a5780637ecebe001461074d5780638456cb591461076d57600080fd5b80636f307dc3146106d857806370a08231146106ff578063715018a61461071f57600080fd5b8063313ce567116102c3578063440d7248116102615780635c56ca35116102305780635c56ca35146106985780635c975abb146106ab578063607ab5e5146106b65780636b56a691146106d057600080fd5b8063440d72481461061f5780634b15b2a91461065f5780634ba3bf7e146106725780635c05468b1461068557600080fd5b806338d52e0f1161029d57806338d52e0f146105ca5780633ef43212146105f15780633f4ba83a1461060457806340c10f191461060c57600080fd5b8063313ce56714610545578063341328c51461057e5780633644e515146105c257600080fd5b806318160ddd116103305780632a3ffb8a1161030a5780632a3ffb8a146104c15780632c966a34146104ff5780632e1a7d4d1461051f57806330eb12781461053257600080fd5b806318160ddd146104905780631b5c1d0e1461049957806323b872dd146104ae57600080fd5b8063095ea7b31161036c578063095ea7b3146103fb5780630f9374101461041e578063103b73971461042657806317daf0b41461046457600080fd5b806304e535e21461039357806306fdde03146103b1578063093f0e27146103c6575b600080fd5b61039b610928565b6040516103a891906126c8565b60405180910390f35b6103b961098a565b6040516103a89190612739565b6103ed7f22ad9585a395edc8067b50da4778cafbb7fa2c4bbd7619fad6aeba403857fd7481565b6040519081526020016103a8565b61040e610409366004612783565b610a18565b60405190151581526020016103a8565b61039b610a85565b600080516020612c3383398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546103ed565b61040e6104723660046127ad565b6001600160a01b03166000908152600c602052604090205460ff1690565b6103ed60055481565b6104ac6104a73660046127cf565b610aa3565b005b61040e6104bc3660046127e8565b610ad5565b600080516020612c7383398151915260005260016020527f5a35d0a0fb7e3bcb482aad5b9886840a8073f28d39a0181c254a9e207a441094546103ed565b610507610bb5565b6040516001600160a01b0390911681526020016103a8565b6104ac61052d3660046127cf565b610c1b565b6104ac610540366004612783565b610d26565b61056c7f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff90911681526020016103a8565b6105ab61058c3660046127ad565b600c602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016103a8565b6103ed610dd6565b6105077f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b9381565b6104ac6105ff3660046127cf565b610e2c565b6104ac610fc8565b61040e61061a366004612783565b611000565b61040e61062d3660046127ad565b7f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b936001600160a01b0390811691161490565b61050761066d366004612832565b61107a565b6104ac610680366004612872565b611133565b61040e6106933660046127ad565b611163565b61040e6106a63660046127ad565b61117d565b60005460ff1661040e565b600a546106c39060ff1681565b6040516103a891906128bf565b600b546103ed565b6105077f000000000000000000000000000000000000000000000000000000000000000081565b6103ed61070d3660046127ad565b60066020526000908152604090205481565b6104ac611197565b6105076107353660046127cf565b6111a9565b6104ac6107483660046127ad565b6111d3565b6103ed61075b3660046127ad565b60086020526000908152604090205481565b6104ac61131d565b60005461010090046001600160a01b0316610507565b6103b9611353565b600080516020612c1383398151915260005260016020527fb6368b31e79ffb73a14a00fbd9c0dbbe43a3a26df7f98e18d14334693e18dfce546103ed565b61040e6107df366004612783565b611360565b6104ac6107f2366004612872565b611479565b61039b6114d6565b61040e61080d366004612783565b6114ef565b6104ac6108203660046127cf565b611555565b6103ed600d5481565b6104ac61083c366004612872565b6116ad565b6104ac6116dd565b6104ac6108573660046128f6565b61174a565b6104ac61086a366004612963565b61198e565b6103ed61087d366004612980565b600760209081526000928352604080842090915290825290205481565b61039b6119bd565b6103ed6108b03660046127ad565b6119d6565b600e54610507906001600160a01b031681565b6104ac6108d63660046127ad565b611a71565b61040e6108e93660046127ad565b611ae7565b6104ac6108fc3660046129b3565b611b01565b6104ac61090f3660046129d4565b611b89565b600e5461040e90600160a01b900460ff1681565b6060600b80548060200260200160405190810160405280929190818152602001828054801561098057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610962575b5050505050905090565b6003805461099790612a49565b80601f01602080910402602001604051908101604052809291908181526020018280546109c390612a49565b8015610a105780601f106109e557610100808354040283529160200191610a10565b820191906000526020600020905b8154815290600101906020018083116109f357829003601f168201915b505050505081565b3360008181526007602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610a739086815260200190565b60405180910390a35060015b92915050565b6060610a9e600080516020612c13833981519152611c9a565b905090565b610aac33611ae7565b610ac957604051637c3ea23f60e01b815260040160405180910390fd5b610ad281611d06565b50565b6001600160a01b03831660009081526007602090815260408083203384529091528120546000198114610b3157610b0c8382612a99565b6001600160a01b03861660009081526007602090815260408083203384529091529020555b6001600160a01b03851660009081526006602052604081208054859290610b59908490612a99565b90915550506001600160a01b0380851660008181526006602052604090819020805487019055519091871690600080516020612c5383398151915290610ba29087815260200190565b60405180910390a3506001949350505050565b600e54600090600160a01b900460ff16610be257604051634dd32fa760e11b815260040160405180910390fd5b600e546001600160a01b0316610c0b57604051630d51877360e21b815260040160405180910390fd5b50600e546001600160a01b031690565b610c23611d41565b610c2b611d87565b333214610cb25760006002600a5460ff166002811115610c4d57610c4d6128a9565b1480610c8957506001600a5460ff166002811115610c6d57610c6d6128a9565b148015610c895750336000908152600c602052604090205460ff165b905080610cb057604051630fa0970d60e11b81523360048201526024015b60405180910390fd5b505b610cbc3382611de0565b60405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a2610d1c7f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b933383611e4a565b610ad26001600955565b610d2f33611ae7565b610d4c57604051637c3ea23f60e01b815260040160405180910390fd5b6001600160a01b037f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b93811690831603610d9857604051634477699960e11b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610dcb57610dc73382611f3c565b5050565b610dc7823383611e4a565b60007f000000000000000000000000000000000000000000000000000000000000e7084614610e0757610a9e611fca565b507f8f19f7d49a2511f56b718adf810887e6ff121a5629f617f05aea6e78168a777390565b610e34611d41565b610e3c611d87565b333214610ebe5760006002600a5460ff166002811115610e5e57610e5e6128a9565b1480610e9a57506001600a5460ff166002811115610e7e57610e7e6128a9565b148015610e9a5750336000908152600c602052604090205460ff165b905080610ebc57604051630fa0970d60e11b8152336004820152602401610ca7565b505b610ec6610bb5565b50600e54604051632770a7eb60e21b8152336004820152602481018390526000916001600160a01b031690639dc29fac906044016020604051808303816000875af1158015610f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3d9190612aac565b905080610f5d5760405163a294042360e01b815260040160405180910390fd5b60405182815233907f16aab25bf023c1724fe661e47886a1083e99fb9533f0947445acb8974a6778c89060200160405180910390a2610fbd7f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b933384611e4a565b50610ad26001600955565b610fd133611ae7565b610fee57604051637c3ea23f60e01b815260040160405180910390fd5b610ff6612064565b610ffe6120ad565b565b600061100a611d41565b600061101533611163565b8061104657507f00000000000000000000000000000000000000000000000000000000000000008015611046575060005b905080611066576040516371d2156960e01b815260040160405180910390fd5b61107084846120ff565b5060019392505050565b6000611084611d41565b61108d3361117d565b6110aa5760405163085c44cb60e31b815260040160405180910390fd5b8180156110c15750600e54600160a01b900460ff16155b156110df57604051634dd32fa760e11b815260040160405180910390fd5b61110a7f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b938486611e4a565b507f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b939392505050565b61113c33611ae7565b61115957604051637c3ea23f60e01b815260040160405180910390fd5b610dc78282612151565b6000610a7f600080516020612c73833981519152836121a6565b6000610a7f600080516020612c13833981519152836121a6565b61119f6121d1565b610ffe6000612231565b600b81815481106111b957600080fd5b6000918252602090912001546001600160a01b0316905081565b6111dc33611ae7565b6111f957604051637c3ea23f60e01b815260040160405180910390fd5b600e546001600160a01b0316156112235760405163b347c0ad60e01b815260040160405180910390fd5b61122c8161228a565b7f000000000000000000000000000000000000000000000000000000000000000660ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561128e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b29190612ac9565b60ff16146112d357604051637265cffd60e11b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0383169081179091556040517fb366d6f570d256c768970b0082f8d0cea95a76afa28b518f9e6eb033d84e656a90600090a250565b61132633611ae7565b61134357604051637c3ea23f60e01b815260040160405180910390fd5b61134b611d41565b610ffe6122bd565b6004805461099790612a49565b600061136a611d41565b600061137533611163565b806113a657507f000000000000000000000000000000000000000000000000000000000000000080156113a6575060005b9050806113c6576040516305fb1f3f60e51b815260040160405180910390fd5b6001600160a01b0384166113ed57604051633efa09af60e01b815260040160405180910390fd5b6001600160a01b038416600090815260076020908152604080832033845290915290205483811015611432576040516308688c9b60e01b815260040160405180910390fd5b6000198114611464576001600160a01b0385166000908152600760209081526040808320338452909152902084820390555b61146e8585611de0565b506001949350505050565b6114816121d1565b61149a600080516020612c3383398151915283836122fa565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6060610a9e600080516020612c73833981519152611c9a565b33600090815260066020526040812080548391908390611510908490612a99565b90915550506001600160a01b03831660008181526006602052604090819020805485019055513390600080516020612c5383398151915290610a739086815260200190565b61155d611d41565b611565611d87565b3332146115e75760006002600a5460ff166002811115611587576115876128a9565b14806115c357506001600a5460ff1660028111156115a7576115a76128a9565b1480156115c35750336000908152600c602052604090205460ff165b9050806115e557604051630fa0970d60e11b8152336004820152602401610ca7565b505b8060000361160857604051636e0ccc0760e01b815260040160405180910390fd5b600d54816005546116199190612ae6565b111561163857604051637872c6e360e01b815260040160405180910390fd5b6116647f000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b93333084612327565b61166e33826120ff565b60405181815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2610ad26001600955565b6116b633611ae7565b6116d357604051637c3ea23f60e01b815260040160405180910390fd5b610dc78282612422565b6116e633611ae7565b61170357604051637c3ea23f60e01b815260040160405180910390fd5b61171d600080516020612c338339815191523360006122fa565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b4284101561179a5760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610ca7565b600060016117a6610dd6565b6001600160a01b038a811660008181526008602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156118b2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906118e85750876001600160a01b0316816001600160a01b0316145b6119255760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610ca7565b6001600160a01b0390811660009081526007602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b61199733611ae7565b6119b457604051637c3ea23f60e01b815260040160405180910390fd5b610ad281612477565b6060610a9e600080516020612c33833981519152611c9a565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611a04575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7f9190612af9565b919050565b611a796121d1565b6001600160a01b038116611ade5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ca7565b610ad281612231565b6000610a7f600080516020612c33833981519152836121a6565b611b0a33611ae7565b611b2757604051637c3ea23f60e01b815260040160405180910390fd5b600a805482919060ff19166001836002811115611b4657611b466128a9565b0217905550806002811115611b5d57611b5d6128a9565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b611b9233611ae7565b611baf57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015611c955736838383818110611bcd57611bcd612b12565b9050604002019050806020016020810190611be89190612963565b15611c0257611c02611bfd60208301836127ad565b61228a565b611c2d600b600c611c1660208501856127ad565b611c266040860160208701612963565b60646124c0565b50611c3e6040820160208301612963565b1515611c4d60208301836127ad565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a35080611c8d81612b28565b915050611bb2565b505050565b600081815260016020908152604091829020805483518184028101840190945280845260609392830182828015611cfa57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cdc575b50505050509050919050565b600d8190556040518181527f95e8c9f3b9477918d3e5407ba96fac8e2084722c9562942bac414734bdf8f8049060200160405180910390a150565b60005460ff1615610ffe5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610ca7565b600260095403611dd95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ca7565b6002600955565b6001600160a01b03821660009081526006602052604081208054839290611e08908490612a99565b90915550506005805482900390556040518181526000906001600160a01b03841690600080516020612c53833981519152906020015b60405180910390a35050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611ea69190612b41565b6000604051808303816000865af19150503d8060008114611ee3576040519150601f19603f3d011682016040523d82523d6000602084013e611ee8565b606091505b50915091506000828015611f14575081511580611f14575081806020019051810190611f149190612aac565b905080611f3457604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b604080516000808252602082019092526001600160a01b038416908390604051611f669190612b41565b60006040518083038185875af1925050503d8060008114611fa3576040519150601f19603f3d011682016040523d82523d6000602084013e611fa8565b606091505b5050905080611c9557604051632e05b05360e21b815260040160405180910390fd5b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6003604051611ffc9190612b5d565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60005460ff16610ffe5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ca7565b6120b5612064565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b80600560008282546121119190612ae6565b90915550506001600160a01b038216600081815260066020908152604080832080548601905551848152600080516020612c538339815191529101611e3e565b61216a600080516020612c7383398151915283836122fa565b604051811515906001600160a01b038416907f2b535dea3b8ec7fb244a57e39a42aee5f6f4871306457173aa18f49a96e8c78090600090a35050565b60009182526002602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6000546001600160a01b03610100909104163314610ffe5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610ca7565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6001600160a01b0381163b610ad257604051638c50d7cd60e01b81526001600160a01b0382166004820152602401610ca7565b6122c5611d41565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586120e23390565b600083815260016020908152604080832060029092529091206123219190848460646124c0565b50505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b179052915160009283929088169161238b9190612b41565b6000604051808303816000865af19150503d80600081146123c8576040519150601f19603f3d011682016040523d82523d6000602084013e6123cd565b606091505b509150915060008280156123f95750815115806123f95750818060200190518101906123f99190612aac565b90508061241957604051632d9d5b4160e01b815260040160405180910390fd5b50505050505050565b61243b600080516020612c1383398151915283836122fa565b604051811515906001600160a01b038416907fc6b049f4dc9561b397b0cef913ea5f18165b682b193be62c0bbbf9ca8763aeba90600090a35050565b600e805460ff60a01b1916600160a01b831515908102919091179091556040517fdf888ec24e9081be857eb58887c4c9e546edf94ee7dbc643c07f69dd32c0d13590600090a250565b6000826124d7576124d28686866124ed565b6124e3565b6124e386868685612615565b9695505050505050565b6001600160a01b0381166000908152602083905260409020805460ff1690811561260d57600180820154865490916000916125289190612a99565b90508082146125b557600087828154811061254557612545612b12565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811061257857612578612b12565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806125c5576125c5612bfc565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156126c057845482116126595760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156127095783516001600160a01b0316835292840192918401916001016126e4565b50909695505050505050565b60005b83811015612730578181015183820152602001612718565b50506000910152565b6020815260008251806020840152612758816040850160208701612715565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114611a6c57600080fd5b6000806040838503121561279657600080fd5b61279f8361276c565b946020939093013593505050565b6000602082840312156127bf57600080fd5b6127c88261276c565b9392505050565b6000602082840312156127e157600080fd5b5035919050565b6000806000606084860312156127fd57600080fd5b6128068461276c565b92506128146020850161276c565b9150604084013590509250925092565b8015158114610ad257600080fd5b60008060006060848603121561284757600080fd5b833592506128576020850161276c565b9150604084013561286781612824565b809150509250925092565b6000806040838503121561288557600080fd5b61288e8361276c565b9150602083013561289e81612824565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600383106128e157634e487b7160e01b600052602160045260246000fd5b91905290565b60ff81168114610ad257600080fd5b600080600080600080600060e0888a03121561291157600080fd5b61291a8861276c565b96506129286020890161276c565b955060408801359450606088013593506080880135612946816128e7565b9699959850939692959460a0840135945060c09093013592915050565b60006020828403121561297557600080fd5b81356127c881612824565b6000806040838503121561299357600080fd5b61299c8361276c565b91506129aa6020840161276c565b90509250929050565b6000602082840312156129c557600080fd5b8135600381106127c857600080fd5b600080602083850312156129e757600080fd5b823567ffffffffffffffff808211156129ff57600080fd5b818501915085601f830112612a1357600080fd5b813581811115612a2257600080fd5b8660208260061b8501011115612a3757600080fd5b60209290920196919550909350505050565b600181811c90821680612a5d57607f821691505b602082108103612a7d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a7f57610a7f612a83565b600060208284031215612abe57600080fd5b81516127c881612824565b600060208284031215612adb57600080fd5b81516127c8816128e7565b80820180821115610a7f57610a7f612a83565b600060208284031215612b0b57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600060018201612b3a57612b3a612a83565b5060010190565b60008251612b53818460208701612715565b9190910192915050565b600080835481600182811c915080831680612b7957607f831692505b60208084108203612b9857634e487b7160e01b86526022600452602486fd5b818015612bac5760018114612bc157612bee565b60ff1986168952841515850289019650612bee565b60008a81526020902060005b86811015612be65781548b820152908501908301612bcd565b505084890196505b509498975050505050505050565b634e487b7160e01b600052603160045260246000fdfeab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c21746d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef98e2d91934cad395982d17afdb76da8ef5d5f4e6341e368f19914b44485e5886a26469706673582212200ee1c95fd02a3e4bf7c8f95fb4361be5f6a2de2d0ceacf240da7a42286527e5f64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b930000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000e496e746572706f727420555344540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005695553445400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000007b2e3fc7510d1a51b3bef735f9854465892193540000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _asset (address): 0xA219439258ca9da29E9Cc4cE5596924745e12B93
Arg [1] : _name (string): Interport USDT
Arg [2] : _symbol (string): iUSDT
Arg [3] : _assetSpenders (address[]): 0x7b2E3FC7510D1A51b3bef735F985446589219354
Arg [4] : _depositAllowed (bool): False
Arg [5] : _variableRepaymentEnabled (bool): True
Arg [6] : _owner (address): 0x72E28c7F34100AfefC399fcc0AE041B8fe5841AE
Arg [7] : _managers (address[]):
Arg [8] : _addOwnerToManagers (bool): True
-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 000000000000000000000000a219439258ca9da29e9cc4ce5596924745e12b93
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [6] : 00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [10] : 496e746572706f72742055534454000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [12] : 6955534454000000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 0000000000000000000000007b2e3fc7510d1a51b3bef735f985446589219354
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| SCROLL | 67.19% | $0.9993 | 1,133.0962 | $1,132.3 | |
| LINEA | 24.46% | $0.999281 | 412.5902 | $412.29 | |
| ETH | 7.36% | $0.999278 | 124.0879 | $124 | |
| OP | 0.70% | $0.999253 | 11.8621 | $11.85 | |
| BSC | 0.20% | $0.999341 | 3.3218 | $3.32 | |
| AVAX | 0.03% | $0.9993 | 0.5185 | $0.5181 | |
| OPBNB | 0.03% | $1.01 | 0.4245 | $0.4279 | |
| POL | 0.02% | $0.999282 | 0.295 | $0.2947 | |
| ARB | 0.01% | $0.998279 | 0.2452 | $0.2447 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.