ERC-20
Overview
Max Total Supply
88,354.762212086682675441 dGM
Holders
1
Total Transfers
-
Market
Price
$0.00 @ 0.000000 ETH
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x24C9121C...2C27c614D The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
GmxV2IsolationModeVaultFactory
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; // solhint-disable max-line-length import { SimpleIsolationModeVaultFactory } from "@dolomite-exchange/modules-base/contracts/isolation-mode/SimpleIsolationModeVaultFactory.sol"; import { AsyncFreezableIsolationModeVaultFactory } from "@dolomite-exchange/modules-base/contracts/isolation-mode/abstract/AsyncFreezableIsolationModeVaultFactory.sol"; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { GmxV2Library } from "./GmxV2Library.sol"; import { IGmxV2IsolationModeVaultFactory } from "./interfaces/IGmxV2IsolationModeVaultFactory.sol"; import { IGmxV2Registry } from "./interfaces/IGmxV2Registry.sol"; // solhint-enable max-line-length /** * @title GmxV2IsolationModeVaultFactory * @author Dolomite * * @notice The wrapper around the GM token that is used to create user vaults and manage the entry points that a * user can use to interact with DolomiteMargin from the vault. * @dev Swap-only GMX markets ARE NOT supported by this vault factory */ contract GmxV2IsolationModeVaultFactory is IGmxV2IsolationModeVaultFactory, AsyncFreezableIsolationModeVaultFactory, SimpleIsolationModeVaultFactory { using EnumerableSet for EnumerableSet.UintSet; using GmxV2Library for GmxV2IsolationModeVaultFactory; // ============= Structs ============= struct ConstructorParams { address gmxV2Registry; uint256 executionFee; MarketInfoConstructorParams tokenAndMarketAddresses; bool skipLongToken; uint256[] initialAllowableDebtMarketIds; uint256[] initialAllowableCollateralMarketIds; address borrowPositionProxyV2; address userVaultImplementation; address dolomiteRegistry; address dolomiteMargin; } // ============ Constants ============ bytes32 private constant _FILE = "GmxV2IsolationModeVaultFactory"; // needed to be shortened to fit into 32 bytes // ============ Immutable Variables ============ address public immutable override SHORT_TOKEN; // solhint-disable-line var-name-mixedcase address public immutable override LONG_TOKEN; // solhint-disable-line var-name-mixedcase address public immutable override INDEX_TOKEN; // solhint-disable-line var-name-mixedcase uint256 public immutable SHORT_TOKEN_MARKET_ID; // solhint-disable-line var-name-mixedcase uint256 public immutable LONG_TOKEN_MARKET_ID; // solhint-disable-line var-name-mixedcase // ============ Constructor ============ constructor( ConstructorParams memory _params ) SimpleIsolationModeVaultFactory( _params.initialAllowableDebtMarketIds, _params.initialAllowableCollateralMarketIds, _params.tokenAndMarketAddresses.marketToken, _params.borrowPositionProxyV2, _params.userVaultImplementation, _params.dolomiteRegistry, _params.dolomiteMargin ) AsyncFreezableIsolationModeVaultFactory( _params.executionFee, _params.gmxV2Registry ) { INDEX_TOKEN = _params.tokenAndMarketAddresses.indexToken; SHORT_TOKEN = _params.tokenAndMarketAddresses.shortToken; SHORT_TOKEN_MARKET_ID = DOLOMITE_MARGIN().getMarketIdByTokenAddress(SHORT_TOKEN); LONG_TOKEN = _params.tokenAndMarketAddresses.longToken; LONG_TOKEN_MARKET_ID = _params.skipLongToken ? type(uint256).max : DOLOMITE_MARGIN().getMarketIdByTokenAddress(LONG_TOKEN); GmxV2Library.validateInitialMarketIds( _params.initialAllowableDebtMarketIds, LONG_TOKEN_MARKET_ID, SHORT_TOKEN_MARKET_ID ); GmxV2Library.validateInitialMarketIds( _params.initialAllowableCollateralMarketIds, LONG_TOKEN_MARKET_ID, SHORT_TOKEN_MARKET_ID ); } function gmxV2Registry() external view returns (IGmxV2Registry) { return IGmxV2Registry(address(handlerRegistry)); } // ==================================================== // ================ Internal Functions ================ // ==================================================== function _afterInitialize() internal override { _allowableCollateralMarketIds.push(marketId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.9; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** * @title MinimalERC20 * @author OpenZeppelin * * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract MinimalERC20 is IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_, uint8 decimals_) { _initializeTokenInfo(name_, symbol_, decimals_); } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = msg.sender; _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = msg.sender; _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = msg.sender; _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } function _initializeTokenInfo(string memory name_, string memory symbol_, uint8 decimals_) internal { _name = name_; _symbol = symbol_; _decimals = decimals_; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require( from != address(0), "ERC20: Transfer from the zero address" ); require( to != address(0), "ERC20: Transfer to the zero address" ); uint256 fromBalance = _balances[from]; require( fromBalance >= amount, "ERC20: Transfer amount exceeds balance" ); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require( account != address(0), "ERC20: Mint to the zero address" ); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require( account != address(0), "ERC20: Burn from the zero address" ); uint256 accountBalance = _balances[account]; require( accountBalance >= amount, "ERC20: Burn amount exceeds balance" ); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require( owner != address(0), "ERC20: Approve from the zero address" ); require( spender != address(0), "ERC20: Approve to the zero address" ); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); require( currentAllowance >= amount, "ERC20: Insufficient allowance" ); unchecked { _approve(owner, spender, currentAllowance - amount); } } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { OnlyDolomiteMarginForUpgradeable } from "./OnlyDolomiteMarginForUpgradeable.sol"; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; /** * @title OnlyDolomiteMargin * @author Dolomite * * @notice Inheritable contract that restricts the calling of certain functions to `DolomiteMargin`, the owner of * `DolomiteMargin` or a `DolomiteMargin` global operator */ abstract contract OnlyDolomiteMargin is OnlyDolomiteMarginForUpgradeable { // ============ Constants ============ bytes32 private constant _FILE = "OnlyDolomiteMargin"; // ============ Storage ============ IDolomiteMargin private immutable _DOLOMITE_MARGIN; // solhint-disable-line var-name-mixedcase // ============ Constructor ============ constructor (address _dolomiteMargin) { _DOLOMITE_MARGIN = IDolomiteMargin(_dolomiteMargin); } // ============ Functions ============ function DOLOMITE_MARGIN() public override view returns (IDolomiteMargin) { return _DOLOMITE_MARGIN; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { ProxyContractHelpers } from "./ProxyContractHelpers.sol"; import { IOnlyDolomiteMargin } from "../interfaces/IOnlyDolomiteMargin.sol"; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; import { Require } from "../protocol/lib/Require.sol"; /** * @title OnlyDolomiteMarginForUpgradeable * @author Dolomite * * @notice Inheritable contract that restricts the calling of certain functions to `DolomiteMargin`, the owner of * `DolomiteMargin` or a `DolomiteMargin` global operator */ abstract contract OnlyDolomiteMarginForUpgradeable is IOnlyDolomiteMargin, ProxyContractHelpers { // ============ Constants ============ bytes32 private constant _FILE = "OnlyDolomiteMargin"; bytes32 private constant _DOLOMITE_MARGIN_SLOT = bytes32(uint256(keccak256("eip1967.proxy.dolomiteMargin")) - 1); // ============ Modifiers ============ modifier onlyDolomiteMargin(address _from) { Require.that( _from == address(DOLOMITE_MARGIN()), _FILE, "Only Dolomite can call function", _from ); _; } modifier onlyDolomiteMarginOwner(address _from) { Require.that( _from == DOLOMITE_MARGIN_OWNER(), _FILE, "Caller is not owner of Dolomite", _from ); _; } modifier onlyDolomiteMarginGlobalOperator(address _from) { Require.that( DOLOMITE_MARGIN().getIsGlobalOperator(_from), _FILE, "Caller is not a global operator", _from ); _; } // ============ Functions ============ function DOLOMITE_MARGIN() public virtual view returns (IDolomiteMargin) { return IDolomiteMargin(_getAddress(_DOLOMITE_MARGIN_SLOT)); } function DOLOMITE_MARGIN_OWNER() public view returns (address) { return DOLOMITE_MARGIN().owner(); } function _setDolomiteMarginViaSlot(address _dolomiteMargin) internal { _setAddress(_DOLOMITE_MARGIN_SLOT, _dolomiteMargin); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title ProxyContractHelpers * @author Dolomite * * @notice Helper functions for upgradeable proxy contracts to use */ abstract contract ProxyContractHelpers { // ================ Internal Functions ================== function _callImplementation(address _implementation) internal { // solhint-disable-next-line no-inline-assembly assembly { // Copy msg.data. We take full control of memory in this inline assembly // block because it will not return to Solidity code. We overwrite the // Solidity scratch pad at memory position 0. calldatacopy(0, 0, calldatasize()) // Call the implementation. // out and outsize are 0 because we don't know the size yet. let result := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0) // Copy the returned data. returndatacopy(0, 0, returndatasize()) switch result // delegatecall returns 0 on error. case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } function _setAddress(bytes32 slot, address _value) internal { // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, _value) } } function _setUint256(bytes32 slot, uint256 _value) internal { // solhint-disable-next-line no-inline-assembly assembly { sstore(slot, _value) } } function _setUint256InMap(bytes32 slot, address key, uint256 _value) internal { // solhint-disable-next-line no-inline-assembly bytes32 mappingSlot = keccak256(abi.encode(key, slot)); assembly { sstore(mappingSlot, _value) } } function _setUint256InNestedMap(bytes32 slot, address key1, address key2, uint256 _value) internal { bytes32 mappingSlot = keccak256(abi.encode(key2, keccak256(abi.encode(key1, slot)))); assembly { sstore(mappingSlot, _value) } } function _getAddress(bytes32 slot) internal view returns (address value) { // solhint-disable-next-line no-inline-assembly assembly { value := sload(slot) } } function _getUint256(bytes32 slot) internal view returns (uint256 value) { // solhint-disable-next-line no-inline-assembly assembly { value := sload(slot) } } function _getUint256FromMap(bytes32 slot, address key) internal view returns (uint256 value) { // solhint-disable-next-line no-inline-assembly bytes32 mappingSlot = keccak256(abi.encode(key, slot)); assembly { value := sload(mappingSlot) } } function _getUint256InNestedMap(bytes32 slot, address key1, address key2) internal view returns (uint256 value) { bytes32 mappingSlot = keccak256(abi.encode(key2, keccak256(abi.encode(key1, slot)))); assembly { value := sload(mappingSlot) } } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title IAuthorizationBase * @author Dolomite * * @notice Interface for allowing only trusted callers to invoke functions that use the `requireIsCallerAuthorized` * modifier. */ interface IAuthorizationBase { function setIsCallerAuthorized(address _caller, bool _isAuthorized) external; function isCallerAuthorized(address _caller) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteRegistry } from "./IDolomiteRegistry.sol"; /** * @title IBaseRegistry * @author Dolomite * * @notice Interface for base storage variables that should be in all registry contracts */ interface IBaseRegistry { // ======================================================== // ======================== Events ======================== // ======================================================== event DolomiteRegistrySet(address indexed _dolomiteRegistry); // ======================================================== // =================== Admin Functions ==================== // ======================================================== function ownerSetDolomiteRegistry(address _dolomiteRegistry) external; // ======================================================== // =================== Getter Functions =================== // ======================================================== function dolomiteRegistry() external view returns (IDolomiteRegistry); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { AccountBalanceLib } from "../lib/AccountBalanceLib.sol"; /** * @title IBorrowPositionProxyV1 * @author Dolomite * * @notice Interface for allowing the transfer of assets between account numbers. Emits an event to allow for easy * indexing of a subgraph for getting active borrow positions. */ interface IBorrowPositionProxyV1 { // ========================= Events ========================= event BorrowPositionOpen(address indexed _borrower, uint256 indexed _borrowAccountNumber); // ========================= Functions ========================= /** * * @param _fromAccountNumber The index from which `msg.sender` will be sourcing the deposit * @param _toAccountNumber The index into which `msg.sender` will be depositing * @param _collateralMarketId The ID of the market being deposited * @param _amountWei The amount, in Wei, to deposit * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_toAccountNumber`, or both accounts can * go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function openBorrowPosition( uint256 _fromAccountNumber, uint256 _toAccountNumber, uint256 _collateralMarketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * @notice This method can only be called once the user's debt has been reduced to zero. Sends all * `_collateralMarketIds` from `_borrowAccountNumber` to `_toAccountNumber`. * * @param _borrowAccountNumber The index from which `msg.sender` collateral will be withdrawn * @param _toAccountNumber The index into which `msg.sender` will be depositing leftover collateral * @param _collateralMarketIds The IDs of the markets being withdrawn, to close the position */ function closeBorrowPosition( uint256 _borrowAccountNumber, uint256 _toAccountNumber, uint256[] calldata _collateralMarketIds ) external; /** * * @param _fromAccountNumber The index from which `msg.sender` will be withdrawing assets * @param _toAccountNumber The index into which `msg.sender` will be depositing assets * @param _marketId The ID of the market being transferred * @param _amountWei The amount, in Wei, to transfer * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_toAccountNumber`, or both accounts can * go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function transferBetweenAccounts( uint256 _fromAccountNumber, uint256 _toAccountNumber, uint256 _marketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * * @param _fromAccountNumber The index from which `msg.sender` will be depositing assets * @param _borrowAccountNumber The index of the borrow position for that will receive the deposited assets * @param _marketId The ID of the market being transferred * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_borrowAccountNumber`, or both accounts * can go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function repayAllForBorrowPosition( uint256 _fromAccountNumber, uint256 _borrowAccountNumber, uint256 _marketId, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IAuthorizationBase } from "./IAuthorizationBase.sol"; import { IBorrowPositionProxyV1 } from "./IBorrowPositionProxyV1.sol"; import { AccountBalanceLib } from "../lib/AccountBalanceLib.sol"; /** * @title IBorrowPositionProxyV2 * @author Dolomite * * @notice Interface for allowing only trusted callers to invoke borrow related functions for transferring funds * between account owners. */ interface IBorrowPositionProxyV2 is IAuthorizationBase, IBorrowPositionProxyV1 { // ========================= Functions ========================= /** * * @param _fromAccountOwner The account from which the user will be sourcing the deposit * @param _fromAccountNumber The index from which `_toAccountOwner` will be sourcing the deposit * @param _toAccountOwner The account into which `_fromAccountOwner` will be depositing * @param _toAccountNumber The index into which `_fromAccountOwner` will be depositing * @param _collateralMarketId The ID of the market being deposited * @param _amountWei The amount, in Wei, to deposit * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_toAccountNumber`, or both accounts can * go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function openBorrowPositionWithDifferentAccounts( address _fromAccountOwner, uint256 _fromAccountNumber, address _toAccountOwner, uint256 _toAccountNumber, uint256 _collateralMarketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * @notice This method can only be called once the user's debt has been reduced to zero. Sends all * `_collateralMarketIds` from `_borrowAccountNumber` to `_toAccountNumber`. * * @param _borrowAccountOwner The account from which collateral will be withdrawn * @param _borrowAccountNumber The index from which `msg.sender` collateral will be withdrawn * @param _toAccountOwner The account into which `_borrowAccountOwner` will be depositing leftover collateral * @param _toAccountNumber The index into which `_borrowAccountOwner` will be depositing leftover collateral * @param _collateralMarketIds The IDs of the markets being withdrawn, to close the position */ function closeBorrowPositionWithDifferentAccounts( address _borrowAccountOwner, uint256 _borrowAccountNumber, address _toAccountOwner, uint256 _toAccountNumber, uint256[] calldata _collateralMarketIds ) external; /** * * @param _fromAccountOwner The account from which assets will be withdrawn * @param _fromAccountNumber The index from which `msg.sender` will be withdrawing assets * @param _toAccountOwner The account to which assets will be deposited * @param _toAccountNumber The index into which `msg.sender` will be depositing assets * @param _marketId The ID of the market being transferred * @param _amountWei The amount, in Wei, to transfer * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_toAccountNumber`, or both accounts can * go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function transferBetweenAccountsWithDifferentAccounts( address _fromAccountOwner, uint256 _fromAccountNumber, address _toAccountOwner, uint256 _toAccountNumber, uint256 _marketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * * @param _fromAccountOwner The account from which assets will be withdrawn for repayment * @param _fromAccountNumber The index from which `msg.sender` will be depositing assets * @param _borrowAccountOwner The account of the borrow position that will receive the deposited assets * @param _borrowAccountNumber The index of the borrow position for that will receive the deposited assets * @param _marketId The ID of the market being transferred * @param _balanceCheckFlag Flag used to check if `_fromAccountNumber`, `_borrowAccountNumber`, or both accounts * can go negative after the transfer settles. Setting the flag to * `AccountBalanceLib.BalanceCheckFlag.None=3` results in neither account being * checked. */ function repayAllForBorrowPositionWithDifferentAccounts( address _fromAccountOwner, uint256 _fromAccountNumber, address _borrowAccountOwner, uint256 _borrowAccountNumber, uint256 _marketId, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; /** * @title IDolomiteAccountRegistry * @author Dolomite * * @notice A registry contract for storing restricted Dolomite ERC20 accounts */ interface IDolomiteAccountRegistry { struct AccountInformation { mapping(address => bool) restrictedAccounts; mapping(address => EnumerableSet.AddressSet) accountToVaults; mapping(address => address) vaultToAccount; address[] factories; } // ================================================ // ==================== Events ==================== // ================================================ event RestrictedAccountSet(address _account, bool _isRestricted); event VaultAddedToAccount(address _account, address _vault); // =================================================== // ==================== Functions ==================== // =================================================== function registerVault( address _account, address _vault ) external; function ownerSetRestrictedAccount( address _account, bool _isRestricted ) external; function isIsolationModeVault(address _vault) external view returns (bool); function isRestrictedAccount(address _account) external view returns (bool); /** * @notice Future-proof function for checking inclusivity for an address to be in the registry. This is mainly * useful for general-purpose contracts like dERC20 tokens that don't want to send assets to accounts that * don't want to be receivable * * @param _account The account to check if it's in this registry as a restricted account or isolation mode vault * @return True if this account is an isolation mode vault or restricted */ function isAccountInRegistry(address _account) external view returns (bool); function getAccountByVault(address _vault) external view returns (address); function getVaultsByAccount(address _account) external view returns (address[] memory); function getFactories() external view returns (address[] memory); function isMarketIdIsolationMode(uint256 _marketId) external view returns (bool); function isTokenIsolationMode(address _token) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; /** * @title IDolomiteMigrator * @author Dolomite * * Interface for a migrator contract, which can migrate funds out of users isolation mode vaults */ interface IDolomiteMigrator { // ================================================ // ==================== Structs =================== // ================================================ struct Transformer { address transformer; bool soloAllowable; } // ================================================ // ==================== Events ==================== // ================================================ event MigrationComplete( address indexed _accountOwner, uint256 _accountNumber, uint256 _fromMarketId, uint256 _toMarketId ); event TransformerSet(uint256 _fromMarketId, uint256 _toMarketId, address _transformer); event HandlerSet(address _handler); // ================================================ // ================== Functions =================== // ================================================ function migrate( IDolomiteStructs.AccountInfo[] calldata _accounts, uint256 _fromMarketId, uint256 _toMarketId, bytes calldata _extraData ) external; function selfMigrate( uint256 _accountNumber, uint256 _fromMarketId, uint256 _toMarketId, bytes calldata _extraData ) external; function ownerSetTransformer( uint256 _fromMarketId, uint256 _toMarketId, address _transformer, bool _soloAllowable ) external; function ownerSetHandler(address _handler) external; function getTransformerByMarketIds( uint256 _fromMarketId, uint256 _toMarketId ) external view returns (Transformer memory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteAccountRegistry } from "./IDolomiteAccountRegistry.sol"; import { IDolomiteMigrator } from "./IDolomiteMigrator.sol"; import { IEventEmitterRegistry } from "./IEventEmitterRegistry.sol"; import { IExpiry } from "./IExpiry.sol"; import { IGenericTraderProxyV1 } from "./IGenericTraderProxyV1.sol"; import { ILiquidatorAssetRegistry } from "./ILiquidatorAssetRegistry.sol"; import { IDolomitePriceOracle } from "../protocol/interfaces/IDolomitePriceOracle.sol"; /** * @title IDolomiteRegistry * @author Dolomite * * @notice A registry contract for storing all of the addresses that can interact with Umami's Delta Neutral vaults */ interface IDolomiteRegistry { struct IsolationModeStorage { bytes4[] isolationModeMulticallFunctions; } // ======================================================== // ======================== Events ======================== // ======================================================== event GenericTraderProxySet(address indexed _genericTraderProxy); event ExpirySet(address indexed _expiry); event SlippageToleranceForPauseSentinelSet(uint256 _slippageTolerance); event LiquidatorAssetRegistrySet(address indexed _liquidatorAssetRegistry); event EventEmitterSet(address indexed _eventEmitter); event ChainlinkPriceOracleSet(address indexed _chainlinkPriceOracle); event DolomiteMigratorSet(address indexed _dolomiteMigrator); event RedstonePriceOracleSet(address indexed _redstonePriceOracle); event OracleAggregatorSet(address indexed _oracleAggregator); event DolomiteAccountRegistrySet(address indexed _dolomiteAccountRegistry); event IsolationModeMulticallFunctionsSet(bytes4[] _selectors); // ======================================================== // =================== Write Functions ==================== // ======================================================== function lazyInitialize(address _dolomiteMigrator, address _oracleAggregator) external; /** * * @param _genericTraderProxy The new address of the generic trader proxy */ function ownerSetGenericTraderProxy(address _genericTraderProxy) external; /** * * @param _expiry The new address of the expiry contract */ function ownerSetExpiry(address _expiry) external; /** * * @param _slippageToleranceForPauseSentinel The slippage tolerance (using 1e18 as the base) for zaps when pauses * are enabled */ function ownerSetSlippageToleranceForPauseSentinel(uint256 _slippageToleranceForPauseSentinel) external; /** * * @param _liquidatorRegistry The new address of the liquidator registry */ function ownerSetLiquidatorAssetRegistry(address _liquidatorRegistry) external; /** * * @param _eventEmitter The new address of the event emitter */ function ownerSetEventEmitter(address _eventEmitter) external; /** * * @param _chainlinkPriceOracle The new address of the Chainlink price oracle that's compatible with * DolomiteMargin. */ function ownerSetChainlinkPriceOracle(address _chainlinkPriceOracle) external; function ownerSetDolomiteMigrator(address _dolomiteMigrator) external; /** * * @param _redstonePriceOracle The new address of the Redstone price oracle that's compatible with * DolomiteMargin. */ function ownerSetRedstonePriceOracle(address _redstonePriceOracle) external; /** * * @param _oracleAggregator The new address of the oracle aggregator that's compatible with * DolomiteMargin. */ function ownerSetOracleAggregator(address _oracleAggregator) external; /** * * @param _dolomiteAccountRegistry The new address of the Dolomite address registry */ function ownerSetDolomiteAccountRegistry(address _dolomiteAccountRegistry) external; /** * * @param _selectors Allowed function selectors for isolation mode multicall */ function ownerSetIsolationModeMulticallFunctions(bytes4[] memory _selectors) external; // ======================================================== // =================== Getter Functions =================== // ======================================================== /** * @return The address of the generic trader proxy for making zaps */ function genericTraderProxy() external view returns (IGenericTraderProxyV1); /** * @return The address of the expiry contract */ function expiry() external view returns (IExpiry); /** * @return The slippage tolerance (using 1e18 as the base) for zaps when pauses are enabled */ function slippageToleranceForPauseSentinel() external view returns (uint256); /** * @return The address of the liquidator asset registry contract */ function liquidatorAssetRegistry() external view returns (ILiquidatorAssetRegistry); /** * @return The address of the emitter contract that can emit certain events for indexing */ function eventEmitter() external view returns (IEventEmitterRegistry); /** * @return The address of the Chainlink price oracle that's compatible with DolomiteMargin */ function chainlinkPriceOracle() external view returns (IDolomitePriceOracle); /** * @return The address of the migrator contract */ function dolomiteMigrator() external view returns (IDolomiteMigrator); /** * @return The address of the Redstone price oracle that's compatible with DolomiteMargin */ function redstonePriceOracle() external view returns (IDolomitePriceOracle); /** * @return The address of the oracle aggregator that's compatible with DolomiteMargin */ function oracleAggregator() external view returns (IDolomitePriceOracle); /** * @return The address of the Dolomite address registry */ function dolomiteAccountRegistry() external view returns (IDolomiteAccountRegistry); /** * @return The array of allowed function selectors for isolation mode multicall */ function isolationModeMulticallFunctions() external view returns (bytes4[] memory); /** * @return The base (denominator) for the slippage tolerance variable. Always 1e18. */ function slippageToleranceForPauseSentinelBase() external pure returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IGenericTraderBase } from "./IGenericTraderBase.sol"; import { IUpgradeableAsyncIsolationModeUnwrapperTrader } from "../isolation-mode/interfaces/IUpgradeableAsyncIsolationModeUnwrapperTrader.sol"; // solhint-disable-line max-line-length import { IUpgradeableAsyncIsolationModeWrapperTrader } from "../isolation-mode/interfaces/IUpgradeableAsyncIsolationModeWrapperTrader.sol"; // solhint-disable-line max-line-length import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; /** * @title IEventEmitterRegistry * @author Dolomite * * Interface for a a singleton event emission contract, which makes tracking events easier for the Subgraph. */ interface IEventEmitterRegistry { // ================================================ // ==================== Structs =================== // ================================================ struct BalanceUpdate { IDolomiteStructs.Wei deltaWei; IDolomiteStructs.Par newPar; } // ================================================ // ==================== Events ==================== // ================================================ /** * @notice This is emitted when a zap is executed * * @param accountOwner The address of the account that executed the zap * @param accountNumber The sub account of the address that executed the zap * @param marketIdsPath The path of market IDs that was executed * @param tradersPath The path of traders that was executed */ event ZapExecuted( address indexed accountOwner, uint256 accountNumber, uint256[] marketIdsPath, IGenericTraderBase.TraderParam[] tradersPath ); /** * @notice This is emitted when a borrow position is initially opened * * @param borrower The address of the account that opened the position * @param borrowAccountNumber The account number of the account that opened the position */ event BorrowPositionOpen( address indexed borrower, uint256 indexed borrowAccountNumber ); /** * @notice This is emitted when a margin position is initially opened * * @param accountOwner The address of the account that opened the position * @param accountNumber The account number of the account that opened the position * @param inputToken The token that was sold to purchase the collateral. This should be the owed token * @param outputToken The token that was purchased with the debt. This should be the held token * @param depositToken The token that was deposited as collateral. This should be the held token * @param inputBalanceUpdate The amount of inputToken that was sold to purchase the outputToken * @param outputBalanceUpdate The amount of outputToken that was purchased with the inputToken * @param marginDepositUpdate The amount of depositToken that was deposited as collateral */ event MarginPositionOpen( address indexed accountOwner, uint256 indexed accountNumber, address inputToken, address outputToken, address depositToken, BalanceUpdate inputBalanceUpdate, BalanceUpdate outputBalanceUpdate, BalanceUpdate marginDepositUpdate ); /** * @notice This is emitted when a margin position is (partially) closed * * @param accountOwner The address of the account that opened the position * @param accountNumber The account number of the account that opened the position * @param inputToken The token that was sold to purchase the debt. This should be the held token * @param outputToken The token that was purchased with the collateral. This should be the owed token * @param withdrawalToken The token that was withdrawn as collateral. This should be the held token * @param inputBalanceUpdate The amount of inputToken that was sold to purchase the outputToken * @param outputBalanceUpdate The amount of outputToken that was purchased with the inputToken * @param marginWithdrawalUpdate The amount of withdrawalToken that was deposited as collateral */ event MarginPositionClose( address indexed accountOwner, uint256 indexed accountNumber, address inputToken, address outputToken, address withdrawalToken, BalanceUpdate inputBalanceUpdate, BalanceUpdate outputBalanceUpdate, BalanceUpdate marginWithdrawalUpdate ); event AsyncDepositCreated( bytes32 indexed key, address indexed token, IUpgradeableAsyncIsolationModeWrapperTrader.DepositInfo deposit ); event AsyncDepositOutputAmountUpdated( bytes32 indexed key, address indexed token, uint256 outputAmount ); event AsyncDepositExecuted(bytes32 indexed key, address indexed token); event AsyncDepositFailed(bytes32 indexed key, address indexed token, string reason); event AsyncDepositCancelled(bytes32 indexed key, address indexed token); event AsyncDepositCancelledFailed(bytes32 indexed key, address indexed token, string reason); event AsyncWithdrawalCreated( bytes32 indexed key, address indexed token, IUpgradeableAsyncIsolationModeUnwrapperTrader.WithdrawalInfo withdrawal ); event AsyncWithdrawalOutputAmountUpdated( bytes32 indexed key, address indexed token, uint256 outputAmount ); event AsyncWithdrawalExecuted(bytes32 indexed key, address indexed token); event AsyncWithdrawalFailed(bytes32 indexed key, address indexed token, string reason); event AsyncWithdrawalCancelled(bytes32 indexed key, address indexed token); event DistributorRegistered( address oTokenAddress, address pairToken, address paymentToken ); event RewardClaimed( address indexed distributor, address indexed user, uint256 epoch, uint256 amount ); // ================================================ // ================== Functions =================== // ================================================ /** * @notice Emits a ZapExecuted event * * @param _accountOwner The address of the account that executed the zap * @param _accountNumber The sub account of the address that executed the zap * @param _marketIdsPath The path of market IDs that was executed * @param _tradersPath The path of traders that was executed */ function emitZapExecuted( address _accountOwner, uint256 _accountNumber, uint256[] calldata _marketIdsPath, IGenericTraderBase.TraderParam[] calldata _tradersPath ) external; /** * @notice Emits a MarginPositionOpen event * * @param _accountOwner The address of the account that opened the position * @param _accountNumber The account number of the account that opened the position */ function emitBorrowPositionOpen( address _accountOwner, uint256 _accountNumber ) external; /** * @notice Emits a MarginPositionOpen event * * @param _accountOwner The address of the account that opened the position * @param _accountNumber The account number of the account that opened the position * @param _inputToken The token that was sold to purchase the collateral. This should be the owed token * @param _outputToken The token that was purchased with the debt. This should be the held token * @param _depositToken The token that was deposited as collateral. This should be the held token * @param _inputBalanceUpdate The amount of inputToken that was sold to purchase the outputToken * @param _outputBalanceUpdate The amount of outputToken that was purchased with the inputToken * @param _marginDepositUpdate The amount of depositToken that was deposited as collateral */ function emitMarginPositionOpen( address _accountOwner, uint256 _accountNumber, address _inputToken, address _outputToken, address _depositToken, BalanceUpdate calldata _inputBalanceUpdate, BalanceUpdate calldata _outputBalanceUpdate, BalanceUpdate calldata _marginDepositUpdate ) external; /** * @notice Emits a MarginPositionClose event * * @param _accountOwner The address of the account that opened the position * @param _accountNumber The account number of the account that opened the position * @param _inputToken The token that was sold to purchase the debt. This should be the held token * @param _outputToken The token that was purchased with the collateral. This should be the owed token * @param _withdrawalToken The token that was withdrawn as collateral. This should be the held token * @param _inputBalanceUpdate The amount of inputToken that was sold to purchase the outputToken * @param _outputBalanceUpdate The amount of outputToken that was purchased with the inputToken * @param _marginWithdrawalUpdate The amount of withdrawalToken that was deposited as collateral */ function emitMarginPositionClose( address _accountOwner, uint256 _accountNumber, address _inputToken, address _outputToken, address _withdrawalToken, BalanceUpdate calldata _inputBalanceUpdate, BalanceUpdate calldata _outputBalanceUpdate, BalanceUpdate calldata _marginWithdrawalUpdate ) external; function emitAsyncDepositCreated( bytes32 _key, address _token, IUpgradeableAsyncIsolationModeWrapperTrader.DepositInfo calldata _deposit ) external; function emitAsyncDepositOutputAmountUpdated( bytes32 _key, address _token, uint256 _outputAmount ) external; function emitAsyncDepositExecuted(bytes32 _key, address _token) external; function emitAsyncDepositFailed(bytes32 _key, address _token, string calldata _reason) external; function emitAsyncDepositCancelled(bytes32 _key, address _token) external; function emitAsyncDepositCancelledFailed(bytes32 _key, address _token, string calldata _reason) external; function emitAsyncWithdrawalCreated( bytes32 _key, address _token, IUpgradeableAsyncIsolationModeUnwrapperTrader.WithdrawalInfo calldata _withdrawal ) external; function emitAsyncWithdrawalOutputAmountUpdated( bytes32 _key, address _token, uint256 _outputAmount ) external; function emitAsyncWithdrawalExecuted(bytes32 _key, address _token) external; function emitAsyncWithdrawalFailed(bytes32 _key, address _token, string calldata _reason) external; function emitAsyncWithdrawalCancelled(bytes32 _key, address _token) external; function emitDistributorRegistered(address _oTokenAddress, address _pairToken, address _paymentToken) external; function emitRewardClaimed(address _user, uint256 _epoch, uint256 _amount) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; /** * @title IExpiry * @author Dolomite * * @notice Interface for getting, setting, and executing the expiry of a position. */ interface IExpiry { // ============ Enums ============ enum CallFunctionType { SetExpiry, SetApproval } // ============ Structs ============ struct SetExpiryArg { IDolomiteMargin.AccountInfo account; uint256 marketId; uint32 timeDelta; bool forceUpdate; } struct SetApprovalArg { address sender; uint32 minTimeDelta; } function getSpreadAdjustedPrices( uint256 heldMarketId, uint256 owedMarketId, uint32 expiry ) external view returns (IDolomiteMargin.MonetaryPrice memory heldPrice, IDolomiteMargin.MonetaryPrice memory owedPriceAdj); function getExpiry( IDolomiteMargin.AccountInfo calldata account, uint256 marketId ) external view returns (uint32); function g_expiryRampTime() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; /** * @title IExpiryV2 * @author Dolomite * * @notice Interface for getting, setting, and executing the expiry of a position. */ interface IExpiryV2 { // ============ Enums ============ enum CallFunctionType { SetExpiry, SetApproval } // ============ Structs ============ struct SetExpiryArg { IDolomiteMargin.AccountInfo account; uint256 marketId; uint32 timeDelta; bool forceUpdate; } struct SetApprovalArg { address sender; uint32 minTimeDelta; } function getLiquidationSpreadAdjustedPrices( IDolomiteStructs.AccountInfo calldata liquidAccount, uint256 heldMarketId, uint256 owedMarketId, uint32 expiry ) external view returns (IDolomiteStructs.MonetaryPrice memory heldPrice, IDolomiteStructs.MonetaryPrice memory owedPriceAdj); function getExpiry( IDolomiteMargin.AccountInfo calldata account, uint256 marketId ) external view returns (uint32); function g_expiryRampTime() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; /** * @title IGenericTraderBase * @author Dolomite * * @notice Base contract structs/params for a generic trader contract. */ interface IGenericTraderBase { // ============ Enums ============ enum TraderType { /// @dev The trade will be conducted using external liquidity, using an `ActionType.Sell` or `ActionType.Buy` /// action. ExternalLiquidity, /// @dev The trade will be conducted using internal liquidity, using an `ActionType.Trade` action. InternalLiquidity, /// @dev The trade will be conducted using external liquidity using an `ActionType.Sell` or `ActionType.Buy` /// action. If this TradeType is used, the trader must be validated using /// the `IIsolationModeToken#isTokenConverterTrusted` function on the IsolationMode token. IsolationModeUnwrapper, /// @dev The trade will be conducted using external liquidity using an `ActionType.Sell` or `ActionType.Buy` /// action. If this TradeType is used, the trader must be validated using /// the `IIsolationModeToken#isTokenConverterTrusted` function on the IsolationMode token. IsolationModeWrapper } // ============ Structs ============ struct TraderParam { /// @dev The type of trade to conduct TraderType traderType; /// @dev The index into the `_makerAccounts` array of the maker account to trade with. Should be set to 0 if /// the traderType is not `TraderType.InternalLiquidity`. uint256 makerAccountIndex; /// @dev The address of IAutoTrader or IExchangeWrapper that will be used to conduct the trade. address trader; /// @dev The data that will be passed through to the trader contract. bytes tradeData; } struct GenericTraderProxyCache { IDolomiteMargin dolomiteMargin; /// @dev True if the user is making a margin deposit, false if they are withdrawing. False if the variable is /// unused too. bool isMarginDeposit; /// @dev The other account number that is not `_traderAccountNumber`. Only used for TransferCollateralParams. uint256 otherAccountNumber; /// @dev The index into the account array at which traders start. uint256 traderAccountStartIndex; /// @dev The cursor for the looping through the operation's actions. uint256 actionsCursor; /// @dev The balance of `inputMarket` that the trader has before the call to `dolomiteMargin.operate` IDolomiteMargin.Wei inputBalanceWeiBeforeOperate; /// @dev The balance of `outputMarket` that the trader has before the call to `dolomiteMargin.operate` IDolomiteMargin.Wei outputBalanceWeiBeforeOperate; /// @dev The balance of `transferMarket` that the trader has before the call to `dolomiteMargin.operate` IDolomiteMargin.Wei transferBalanceWeiBeforeOperate; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; import { IGenericTraderBase } from "./IGenericTraderBase.sol"; import { AccountBalanceLib } from "../lib/AccountBalanceLib.sol"; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; /** * @title IGenericTraderProxyV1 * @author Dolomite * * Trader proxy interface for trading assets using any trader from msg.sender */ interface IGenericTraderProxyV1 is IGenericTraderBase { // ============ Structs ============ enum EventEmissionType { None, BorrowPosition, MarginPosition } struct TransferAmount { /// @dev The market ID to transfer uint256 marketId; /// @dev Note, setting to uint(-1) will transfer all of the user's balance. uint256 amountWei; } struct TransferCollateralParam { /// @dev The account number from which collateral will be transferred. uint256 fromAccountNumber; /// @dev The account number to which collateral will be transferred. uint256 toAccountNumber; /// @dev The transfers to execute after all of the trades. TransferAmount[] transferAmounts; } struct ExpiryParam { /// @dev The market ID whose expiry will be updated. uint256 marketId; /// @dev The new expiry time delta for the market. Setting this to `0` will reset the expiration. uint32 expiryTimeDelta; } struct UserConfig { /// @dev The timestamp at which the zap request fails uint256 deadline; /// @dev Setting this to `BalanceCheckFlag.Both` or `BalanceCheckFlag.From` will check the /// `_tradeAccountNumber` is not negative after the trade for the input market (_marketIdsPath[0]). /// Setting this to `BalanceCheckFlag.Both` or `BalanceCheckFlag.To` will check the /// `_transferAccountNumber` is not negative after the trade for any of the transfers in /// `TransferCollateralParam.transferAmounts`. AccountBalanceLib.BalanceCheckFlag balanceCheckFlag; EventEmissionType eventType; } // ============ Functions ============ /** * @dev Swaps an exact amount of input for a minimum amount of output. * * @param _tradeAccountNumber The account number to use for msg.sender's trade * @param _marketIdsPath The path of market IDs to use for each trade action. Length should be equal * to `_tradersPath.length + 1`. * @param _inputAmountWei The input amount (in wei) to use for the initial trade action. Setting this * value to `uint(-1)` will use the user's full balance. * @param _minOutputAmountWei The minimum output amount expected to be received by the user. * @param _tradersPath The path of traders to use for each trade action. Length should be equal to * `_marketIdsPath.length - 1`. * @param _makerAccounts The accounts that will be used for the maker side of the trades involving * `TraderType.InternalLiquidity`. * @param _userConfig The user configuration for the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.From` will check that the user's `_tradeAccountNumber` * is non-negative after the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.To` has no effect. */ function swapExactInputForOutput( uint256 _tradeAccountNumber, uint256[] calldata _marketIdsPath, uint256 _inputAmountWei, uint256 _minOutputAmountWei, IGenericTraderBase.TraderParam[] calldata _tradersPath, IDolomiteMargin.AccountInfo[] calldata _makerAccounts, UserConfig calldata _userConfig ) external; /** * @dev The same function as `swapExactInputForOutput`, but allows the caller to transfer collateral and modify * the position's expiration in the same transaction. * * @param _tradeAccountNumber The account number to use for msg.sender's trade * @param _marketIdsPath The path of market IDs to use for each trade action. Length should be equal * to `_tradersPath.length + 1`. * @param _inputAmountWei The input amount (in wei) to use for the initial trade action. Setting this * value to `uint(-1)` will use the user's full balance. * @param _minOutputAmountWei The minimum output amount expected to be received by the user. * @param _tradersPath The path of traders to use for each trade action. Length should be equal to * `_marketIdsPath.length - 1`. * @param _makerAccounts The accounts that will be used for the maker side of the trades involving `TraderType.InternalLiquidity`. * @param _transferCollateralParams The parameters for transferring collateral in/out of the * `_tradeAccountNumber` once the trades settle. One of * `_params.fromAccountNumber` or `_params.toAccountNumber` must be equal to * `_tradeAccountNumber`. * @param _expiryParams The parameters for modifying the expiration of the debt in the position. * @param _userConfig The user configuration for the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.From` will check that the user's balance for inputMarket * for `_tradeAccountNumber` is non-negative after the trade. Setting the * `balanceCheckFlag` to `BalanceCheckFlag.To` will check that the user's * balance for each `transferMarket` for `transferAccountNumber` is * non-negative after. */ function swapExactInputForOutputAndModifyPosition( uint256 _tradeAccountNumber, uint256[] calldata _marketIdsPath, uint256 _inputAmountWei, uint256 _minOutputAmountWei, IGenericTraderBase.TraderParam[] calldata _tradersPath, IDolomiteMargin.AccountInfo[] calldata _makerAccounts, TransferCollateralParam calldata _transferCollateralParams, ExpiryParam calldata _expiryParams, UserConfig calldata _userConfig ) external; function ownerSetEventEmitterRegistry( address _eventEmitterRegistry ) external; function EVENT_EMITTER_REGISTRY() external view returns (address); function EXPIRY() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IBaseRegistry } from "./IBaseRegistry.sol"; import { IIsolationModeVaultFactory } from "../isolation-mode/interfaces/IIsolationModeVaultFactory.sol"; import { IUpgradeableAsyncIsolationModeUnwrapperTrader } from "../isolation-mode/interfaces/IUpgradeableAsyncIsolationModeUnwrapperTrader.sol"; // solhint-disable-line max-line-length import { IUpgradeableAsyncIsolationModeWrapperTrader } from "../isolation-mode/interfaces/IUpgradeableAsyncIsolationModeWrapperTrader.sol"; // solhint-disable-line max-line-length /** * @title IHandlerRegistry * @author Dolomite * * @notice A registry contract for storing whether or not a handler is trusted for executing a function */ interface IHandlerRegistry is IBaseRegistry { // ================================================ // ==================== Events ==================== // ================================================ event HandlerSet(address _handler, bool _isTrusted); event CallbackGasLimitSet(uint256 _callbackGasLimit); event UnwrapperTraderSet(address _token, address _unwrapperTrader); event WrapperTraderSet(address _token, address _wrapperTrader); // =================================================== // ==================== Functions ==================== // =================================================== function ownerSetIsHandler( address _handler, bool _isTrusted ) external; function ownerSetCallbackGasLimit( uint256 _callbackGasLimit ) external; function ownerSetUnwrapperByToken( IIsolationModeVaultFactory _factoryToken, IUpgradeableAsyncIsolationModeUnwrapperTrader _unwrapperTrader ) external; function ownerSetWrapperByToken( IIsolationModeVaultFactory _factoryToken, IUpgradeableAsyncIsolationModeWrapperTrader _wrapperTrader ) external; function isHandler(address _handler) external view returns (bool); function callbackGasLimit() external view returns (uint256); function getUnwrapperByToken( IIsolationModeVaultFactory _factoryToken ) external view returns (IUpgradeableAsyncIsolationModeUnwrapperTrader); function getWrapperByToken( IIsolationModeVaultFactory _factoryToken ) external view returns (IUpgradeableAsyncIsolationModeWrapperTrader); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title ILiquidatorAssetRegistry * @author Dolomite * * Interface for a registry that tracks which assets can be liquidated and by each contract */ interface ILiquidatorAssetRegistry { /** * * @param _marketId The market ID of the asset * @param _liquidator The address of the liquidator to add */ function ownerAddLiquidatorToAssetWhitelist( uint256 _marketId, address _liquidator ) external; /** * * @param _marketId The market ID of the asset * @param _liquidator The address of the liquidator to remove */ function ownerRemoveLiquidatorFromAssetWhitelist( uint256 _marketId, address _liquidator ) external; /** * * @param _marketId The market ID of the asset to check * @return An array of whitelisted liquidators for the asset. An empty array is returned if any * liquidator can be used for this asset */ function getLiquidatorsForAsset( uint256 _marketId ) external view returns (address[] memory); /** * * @param _marketId The market ID of the asset to check * @param _liquidator The address of the liquidator to check * @return True if the liquidator is whitelisted for the asset, false otherwise. Returns true if there * are no whitelisted liquidators for the asset. Should ALWAYS have at least ONE whitelisted * liquidator for IsolationMode assets. */ function isAssetWhitelistedForLiquidation( uint256 _marketId, address _liquidator ) external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; /** * @title IOnlyDolomiteMargin * @author Dolomite * * @notice This interface is for contracts that need to add modifiers for only DolomiteMargin / Owner caller. */ interface IOnlyDolomiteMargin { function DOLOMITE_MARGIN() external view returns (IDolomiteMargin); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IsolationModeVaultFactory } from "./IsolationModeVaultFactory.sol"; import { IHandlerRegistry } from "../../interfaces/IHandlerRegistry.sol"; import { AccountActionLib } from "../../lib/AccountActionLib.sol"; import { IDolomiteStructs } from "../../protocol/interfaces/IDolomiteStructs.sol"; import { Require } from "../../protocol/lib/Require.sol"; import { TypesLib } from "../../protocol/lib/TypesLib.sol"; import { IAsyncFreezableIsolationModeVaultFactory } from "../interfaces/IAsyncFreezableIsolationModeVaultFactory.sol"; import { IIsolationModeTokenVaultV1WithAsyncFreezable } from "../interfaces/IIsolationModeTokenVaultV1WithAsyncFreezable.sol"; // solhint-disable-line max-line-length /** * @title AsyncFreezableIsolationModeVaultFactory * @author Dolomite * * @notice Abstract contract for allowing freezable vaults (usually for handling async requests) */ abstract contract AsyncFreezableIsolationModeVaultFactory is IAsyncFreezableIsolationModeVaultFactory, IsolationModeVaultFactory { using TypesLib for IDolomiteStructs.Wei; // ========================================================= // ======================= Constants ======================= // ========================================================= bytes32 private constant _FILE = "FreezableVaultFactory"; // ========================================================= // ==================== Field Variables ==================== // ========================================================= /// Vault ==> Account Number ==> Freeze Type ==> Pending Amount mapping(address => mapping(uint256 => mapping(FreezeType => uint256))) private _accountInfoToPendingAmountWeiMap; mapping(address => mapping(uint256 => address)) private _accountInfoToOutputTokenMap; /// Vault ==> Freeze Type ==> Pending Amount mapping(address => mapping(FreezeType => uint256)) private _vaultToPendingAmountWeiMap; uint256 public maxExecutionFee = 1 ether; uint256 public override executionFee; IHandlerRegistry public override handlerRegistry; // =========================================================== // ======================= Modifiers ====================== // =========================================================== modifier requireIsTokenConverterOrVaultOrDolomiteMarginOwner(address _caller) { Require.that( _tokenConverterToIsTrustedMap[_caller] || _vaultToUserMap[_caller] != address(0) || DOLOMITE_MARGIN().owner() == _caller, _FILE, "Caller is not a authorized", _caller ); _; } // =========================================================== // ======================= Constructors ====================== // =========================================================== constructor(uint256 _executionFee, address _handlerRegistry) { _ownerSetExecutionFee(_executionFee); _ownerSetHandlerRegistry(_handlerRegistry); } // =========================================================== // ===================== Public Functions ==================== // =========================================================== function ownerSetExecutionFee( uint256 _executionFee ) external override onlyDolomiteMarginOwner(msg.sender) { _ownerSetExecutionFee(_executionFee); } function ownerSetMaxExecutionFee( uint256 _maxExecutionFee ) external override onlyDolomiteMarginOwner(msg.sender) { _ownerSetMaxExecutionFee(_maxExecutionFee); } function ownerSetHandlerRegistry( address _handlerRegistry ) external override onlyDolomiteMarginOwner(msg.sender) { _ownerSetHandlerRegistry(_handlerRegistry); } function setIsVaultDepositSourceWrapper( address _vault, bool _isDepositSourceWrapper ) external requireIsTokenConverter(msg.sender) requireIsVault(_vault) { _setIsVaultDepositSourceWrapper(_vault, _isDepositSourceWrapper); } function setShouldVaultSkipTransfer( address _vault, bool _shouldSkipTransfer ) external requireIsTokenConverter(msg.sender) requireIsVault(_vault) { IIsolationModeTokenVaultV1WithAsyncFreezable(_vault).setShouldVaultSkipTransfer(_shouldSkipTransfer); } function depositIntoDolomiteMarginFromTokenConverter( address _vault, uint256 _vaultAccountNumber, uint256 _amountWei ) external requireIsTokenConverter(msg.sender) requireIsVault(_vault) { _depositIntoDolomiteMarginFromTokenConverter( _vault, _vaultAccountNumber, _amountWei ); } function setVaultAccountPendingAmountForFrozenStatus( address _vault, uint256 _accountNumber, FreezeType _freezeType, IDolomiteStructs.Wei calldata _amountDeltaWei, address _conversionToken ) external requireIsTokenConverterOrVaultOrDolomiteMarginOwner(msg.sender) requireIsVault(_vault) { address expectedConversionToken = _accountInfoToOutputTokenMap[_vault][_accountNumber]; Require.that( expectedConversionToken == address(0) || expectedConversionToken == _conversionToken, _FILE, "Invalid output token", _conversionToken ); if (_amountDeltaWei.isNegative()) { _accountInfoToPendingAmountWeiMap[_vault][_accountNumber][_freezeType] -= _amountDeltaWei.value; _vaultToPendingAmountWeiMap[_vault][_freezeType] -= _amountDeltaWei.value; } else if (_amountDeltaWei.isPositive()) { _accountInfoToPendingAmountWeiMap[_vault][_accountNumber][_freezeType] += _amountDeltaWei.value; _vaultToPendingAmountWeiMap[_vault][_freezeType] += _amountDeltaWei.value; } bool isFrozen = isVaultAccountFrozen(_vault, _accountNumber); if (isFrozen) { _accountInfoToOutputTokenMap[_vault][_accountNumber] = _conversionToken; } else { _accountInfoToOutputTokenMap[_vault][_accountNumber] = address(0); } emit VaultAccountFrozen(_vault, _accountNumber, isFrozen); } function isVaultFrozen( address _vault ) external view returns (bool) { return _vaultToPendingAmountWeiMap[_vault][FreezeType.Deposit] != 0 || _vaultToPendingAmountWeiMap[_vault][FreezeType.Withdrawal] != 0; } function getPendingAmountByAccount( address _vault, uint256 _accountNumber, FreezeType _freezeType ) external view returns (uint256) { return _accountInfoToPendingAmountWeiMap[_vault][_accountNumber][_freezeType]; } function getPendingAmountByVault( address _vault, FreezeType _freezeType ) external view returns (uint256) { return _vaultToPendingAmountWeiMap[_vault][_freezeType]; } function getOutputTokenByAccount( address _vault, uint256 _accountNumber ) external view returns (address) { return _accountInfoToOutputTokenMap[_vault][_accountNumber]; } function isVaultAccountFrozen( address _vault, uint256 _accountNumber ) public view returns (bool) { return _accountInfoToPendingAmountWeiMap[_vault][_accountNumber][FreezeType.Deposit] != 0 || _accountInfoToPendingAmountWeiMap[_vault][_accountNumber][FreezeType.Withdrawal] != 0; } // =========================================================== // ==================== Internal Functions =================== // =========================================================== function _ownerSetExecutionFee( uint256 _executionFee ) internal { Require.that( _executionFee <= maxExecutionFee, _FILE, "Invalid execution fee" ); executionFee = _executionFee; emit ExecutionFeeSet(_executionFee); } function _ownerSetMaxExecutionFee( uint256 _maxExecutionFee ) internal { maxExecutionFee = _maxExecutionFee; emit MaxExecutionFeeSet(_maxExecutionFee); } function _ownerSetHandlerRegistry( address _handlerRegistry ) internal { handlerRegistry = IHandlerRegistry(_handlerRegistry); emit HandlerRegistrySet(_handlerRegistry); } function _depositIntoDolomiteMarginFromTokenConverter( address _vault, uint256 _vaultAccountNumber, uint256 _amountWei ) internal virtual { _setIsVaultDepositSourceWrapper(_vault, /* _isDepositSourceWrapper = */ true); _enqueueTransfer( _vault, address(DOLOMITE_MARGIN()), _amountWei, _vault ); AccountActionLib.deposit( DOLOMITE_MARGIN(), /* _accountOwner = */ _vault, /* _fromAccount = */ _vault, _vaultAccountNumber, marketId, IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountWei }) ); } function _setIsVaultDepositSourceWrapper( address _vault, bool _isDepositSourceWrapper ) internal { IIsolationModeTokenVaultV1WithAsyncFreezable(_vault).setIsVaultDepositSourceWrapper(_isDepositSourceWrapper); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; import { IsolationModeUpgradeableProxy } from "../IsolationModeUpgradeableProxy.sol"; import { MinimalERC20 } from "../../general/MinimalERC20.sol"; import { OnlyDolomiteMargin } from "../../helpers/OnlyDolomiteMargin.sol"; import { IBorrowPositionProxyV2 } from "../../interfaces/IBorrowPositionProxyV2.sol"; import { IDolomiteRegistry } from "../../interfaces/IDolomiteRegistry.sol"; import { AccountActionLib } from "../../lib/AccountActionLib.sol"; import { AccountBalanceLib } from "../../lib/AccountBalanceLib.sol"; import { IDolomiteStructs } from "../../protocol/interfaces/IDolomiteStructs.sol"; import { Require } from "../../protocol/lib/Require.sol"; import { IIsolationModeTokenVaultV1 } from "../interfaces/IIsolationModeTokenVaultV1.sol"; import { IIsolationModeUpgradeableProxy } from "../interfaces/IIsolationModeUpgradeableProxy.sol"; import { IIsolationModeVaultFactory } from "../interfaces/IIsolationModeVaultFactory.sol"; /** * @title IsolationModeVaultFactory * @author Dolomite * * @notice Abstract contract for wrapping tokens via a per-user vault that credits a user's balance within * DolomiteMargin */ abstract contract IsolationModeVaultFactory is IIsolationModeVaultFactory, OnlyDolomiteMargin, MinimalERC20 { // =================================================== // ==================== Constants ==================== // =================================================== bytes32 private constant _FILE = "IsolationModeVaultFactory"; address private constant _DEAD_VAULT = 0x000000000000000000000000000000000000dEaD; // ================================================== // ================ Immutable Fields ================ // ================================================== address public immutable override UNDERLYING_TOKEN; // solhint-disable-line var-name-mixedcase IBorrowPositionProxyV2 public immutable override BORROW_POSITION_PROXY; // solhint-disable-line var-name-mixedcase IDolomiteRegistry public immutable DOLOMITE_REGISTRY; // ================================================ // ==================== Fields ==================== // ================================================ address public override userVaultImplementation; bool public isInitialized; uint256 public override marketId; // can't be immutable because it's set in the call to #initialize uint256 public transferCursor; mapping(uint256 => QueuedTransfer) internal _cursorToQueuedTransferMap; mapping(address => address) internal _vaultToUserMap; mapping(address => address) internal _userToVaultMap; mapping(address => bool) internal _tokenConverterToIsTrustedMap; // =================================================== // ==================== Modifiers ==================== // =================================================== modifier requireIsInitialized { Require.that( isInitialized, _FILE, "Not initialized" ); _; } modifier requireIsVault(address _vault) { Require.that( address(_vaultToUserMap[_vault]) != address(0), _FILE, "Invalid vault", _vault ); _; } modifier requireIsTokenConverter(address _tokenConverter) { Require.that( _tokenConverterToIsTrustedMap[_tokenConverter], _FILE, "Caller is not a token converter", _tokenConverter ); _; } modifier requireIsTokenConverterOrVault(address _tokenConverterOrVault) { Require.that( _tokenConverterToIsTrustedMap[_tokenConverterOrVault] || _vaultToUserMap[_tokenConverterOrVault] != address(0), _FILE, "Caller is not a authorized", _tokenConverterOrVault ); _; } constructor( address _underlyingToken, address _borrowPositionProxyV2, address _userVaultImplementation, address _dolomiteRegistry, address _dolomiteMargin ) MinimalERC20( /* name_ = */ string(abi.encodePacked("Dolomite Isolation: ", MinimalERC20(_underlyingToken).name())), /* symbol_ = */ string(abi.encodePacked("d", MinimalERC20(_underlyingToken).symbol())), /* decimals_ = */ MinimalERC20(_underlyingToken).decimals() ) OnlyDolomiteMargin(_dolomiteMargin) { DOLOMITE_REGISTRY = IDolomiteRegistry(_dolomiteRegistry); UNDERLYING_TOKEN = _underlyingToken; BORROW_POSITION_PROXY = IBorrowPositionProxyV2(_borrowPositionProxyV2); userVaultImplementation = _userVaultImplementation; _createVault(_DEAD_VAULT); } // ================================================= // ================ Write Functions ================ // ================================================= function ownerInitialize( address[] calldata _tokenConverters ) external override onlyDolomiteMarginOwner(msg.sender) { Require.that( !isInitialized, _FILE, "Already initialized" ); marketId = DOLOMITE_MARGIN().getMarketIdByTokenAddress(address(this)); Require.that( DOLOMITE_MARGIN().getMarketIsClosing(marketId), _FILE, "Market cannot allow borrowing" ); _initializeVault(_DEAD_VAULT, _userToVaultMap[_DEAD_VAULT]); for (uint256 i = 0; i < _tokenConverters.length; i++) { _ownerSetIsTokenConverterTrusted(_tokenConverters[i], true); } isInitialized = true; emit Initialized(); _afterInitialize(); } function createVault( address _account ) external override requireIsInitialized returns (address) { return _createVault(_account); } function createVaultAndDepositIntoDolomiteMargin( uint256 _toAccountNumber, uint256 _amountWei ) external override requireIsInitialized returns (address) { address vault = _createVault(msg.sender); IIsolationModeTokenVaultV1(vault).depositIntoVaultForDolomiteMargin(_toAccountNumber, _amountWei); return vault; } function ownerSetUserVaultImplementation( address _userVaultImplementation ) external override requireIsInitialized onlyDolomiteMarginOwner(msg.sender) { Require.that( _userVaultImplementation != address(0), _FILE, "Invalid user implementation" ); address _oldUserVaultImplementation = userVaultImplementation; userVaultImplementation = _userVaultImplementation; emit UserVaultImplementationSet(_oldUserVaultImplementation, _userVaultImplementation); } function ownerSetIsTokenConverterTrusted( address _tokenConverter, bool _isTrusted ) external override requireIsInitialized onlyDolomiteMarginOwner(msg.sender) { _ownerSetIsTokenConverterTrusted(_tokenConverter, _isTrusted); } function depositOtherTokenIntoDolomiteMarginForVaultOwner( uint256 _toAccountNumber, uint256 _otherMarketId, uint256 _amountWei ) external override requireIsVault(msg.sender) { Require.that( _otherMarketId != marketId, _FILE, "Invalid market", _otherMarketId ); // we have to deposit into the vault first and then transfer to vault.owner, because the deposit is not // coming from the factory address or the vault owner. IDolomiteStructs.AccountInfo[] memory accounts = new IDolomiteStructs.AccountInfo[](2); accounts[0] = IDolomiteStructs.AccountInfo({ owner: msg.sender, number: 0 }); accounts[1] = IDolomiteStructs.AccountInfo({ owner: _vaultToUserMap[msg.sender], number: _toAccountNumber }); IDolomiteStructs.ActionArgs[] memory actions = new IDolomiteStructs.ActionArgs[](2); actions[0] = AccountActionLib.encodeDepositAction( /* _accountId = */ 0, _otherMarketId, IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountWei }), /* _fromAccount = */ msg.sender ); actions[1] = AccountActionLib.encodeTransferAction( /* _fromAccountId = */ 0, /* _toAccountId = */ 1, _otherMarketId, IDolomiteStructs.AssetDenomination.Wei, AccountActionLib.all() ); DOLOMITE_MARGIN().operate(accounts, actions); } function enqueueTransferIntoDolomiteMargin( address _vault, uint256 _amountWei ) external override requireIsTokenConverter(msg.sender) requireIsVault(_vault) { _enqueueTransfer(msg.sender, address(DOLOMITE_MARGIN()), _amountWei, _vault); } function enqueueTransferFromDolomiteMargin( address _vault, uint256 _amountWei ) external override requireIsTokenConverter(msg.sender) requireIsVault(_vault) { _enqueueTransfer(address(DOLOMITE_MARGIN()), msg.sender, _amountWei, _vault); } function depositIntoDolomiteMargin( uint256 _toAccountNumber, uint256 _amountWei ) external override requireIsVault(msg.sender) { address vault = msg.sender; _enqueueTransfer( vault, address(DOLOMITE_MARGIN()), _amountWei, vault ); AccountActionLib.deposit( DOLOMITE_MARGIN(), /* _accountOwner = */ vault, /* _fromAccount = */ vault, _toAccountNumber, marketId, IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountWei }) ); } function withdrawFromDolomiteMargin( uint256 _fromAccountNumber, uint256 _amountWei ) external override requireIsVault(msg.sender) { address vault = msg.sender; _enqueueTransfer( address(DOLOMITE_MARGIN()), vault, _amountWei, vault ); AccountActionLib.withdraw( DOLOMITE_MARGIN(), /* _accountOwner = */ vault, _fromAccountNumber, /* _toAccount = */ vault, marketId, IDolomiteStructs.AssetAmount({ sign: false, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountWei }), AccountBalanceLib.BalanceCheckFlag.From ); } // ================================================ // ================ Read Functions ================ // ================================================ function getQueuedTransferByCursor(uint256 _transferCursor) external view returns (QueuedTransfer memory) { Require.that( _transferCursor <= transferCursor, _FILE, "Invalid transfer cursor" ); return _cursorToQueuedTransferMap[_transferCursor]; } function isTokenConverterTrusted(address _tokenConverter) external view override returns (bool) { return _tokenConverterToIsTrustedMap[_tokenConverter]; } function getVaultByAccount(address _account) external view override returns (address _vault) { _vault = _userToVaultMap[_account]; } function calculateVaultByAccount(address _account) external view override returns (address _vault) { _vault = Create2.computeAddress( keccak256(abi.encodePacked(_account)), getProxyVaultInitCodeHash() ); } function getAccountByVault(address _vault) external view override returns (address _account) { _account = _vaultToUserMap[_vault]; } function isIsolationAsset() external pure returns (bool) { return true; } // ==================================================== // ================= Public Functions ================= // ==================================================== function getProxyVaultInitCodeHash() public pure override returns (bytes32) { return keccak256(type(IsolationModeUpgradeableProxy).creationCode); } // ==================================================== // ================ Internal Functions ================ // ==================================================== function _afterInitialize() internal virtual { // solhint-disable-previous-line no-empty-blocks } function _ownerSetIsTokenConverterTrusted(address _tokenConverter, bool _isTrusted) internal { Require.that( _tokenConverter != address(0), _FILE, "Invalid token converter" ); _tokenConverterToIsTrustedMap[_tokenConverter] = _isTrusted; emit TokenConverterSet(_tokenConverter, _isTrusted); } function _createVault(address _account) internal virtual returns (address) { Require.that( _account != address(0), _FILE, "Invalid account" ); Require.that( _userToVaultMap[_account] == address(0), _FILE, "Vault already exists" ); address vault = Create2.deploy( /* amount = */ 0, keccak256(abi.encodePacked(_account)), type(IsolationModeUpgradeableProxy).creationCode ); assert(vault != address(0)); emit VaultCreated(_account, vault); _vaultToUserMap[vault] = _account; _userToVaultMap[_account] = vault; if (_account != _DEAD_VAULT) { _initializeVault(_account, vault); } return vault; } function _initializeVault(address _account, address _vault) internal { assert(_account != address(0) && _vault != address(0)); IIsolationModeUpgradeableProxy(_vault).initialize(_account); BORROW_POSITION_PROXY.setIsCallerAuthorized(_vault, true); DOLOMITE_REGISTRY.dolomiteAccountRegistry().registerVault(_account, _vault); } function _enqueueTransfer( address _from, address _to, uint256 _amount, address _vault ) internal { QueuedTransfer memory oldTransfer = _cursorToQueuedTransferMap[transferCursor]; if (!oldTransfer.isExecuted && oldTransfer.to == address(DOLOMITE_MARGIN())) { // remove the approval if the previous transfer was not executed and was to DolomiteMargin _approve(oldTransfer.vault, oldTransfer.to, 0); } if (_from == _vault && _to == address(DOLOMITE_MARGIN())) { // Approve the queued transfer amount from the vault contract into DolomiteMargin from this contract _approve(_vault, _to, _amount); } // add 1 to the cursor for any enqueue, allowing anyone to overwrite stale enqueues in case a developer // doesn't integrate with this contract properly transferCursor += 1; _cursorToQueuedTransferMap[transferCursor] = QueuedTransfer({ from: _from, to: _to, amount: _amount, vault: _vault, isExecuted: false }); emit TransferQueued(transferCursor, _from, _to, _amount, _vault); } function _transfer( address _from, address _to, uint256 _amount ) internal override onlyDolomiteMargin(msg.sender) { Require.that( _from != address(0), _FILE, "Transfer from the zero address" ); Require.that( _to != address(0), _FILE, "Transfer to the zero address" ); // Since this must be called from DolomiteMargin via Exchange#transferIn/Exchange#transferOut, we can assume // that it's non-reentrant address dolomiteMargin = address(DOLOMITE_MARGIN()); Require.that( _from == dolomiteMargin || _to == dolomiteMargin, _FILE, "from/to must eq DolomiteMargin" ); uint256 _transferCursor = transferCursor; QueuedTransfer memory queuedTransfer = _cursorToQueuedTransferMap[_transferCursor]; Require.that( queuedTransfer.from == _from && queuedTransfer.to == _to && queuedTransfer.amount == _amount && _vaultToUserMap[queuedTransfer.vault] != address(0), _FILE, "Invalid queued transfer" ); Require.that( !queuedTransfer.isExecuted, _FILE, "Transfer already executed", _transferCursor ); _cursorToQueuedTransferMap[_transferCursor].isExecuted = true; if (_to == dolomiteMargin) { // transfers TO DolomiteMargin must be made FROM a vault or a tokenConverter address vaultOwner = _vaultToUserMap[_from]; Require.that( (vaultOwner != address(0) && _from == queuedTransfer.vault) || _tokenConverterToIsTrustedMap[_from], _FILE, "Invalid from" ); IIsolationModeTokenVaultV1(queuedTransfer.vault).executeDepositIntoVault( vaultOwner != address(0) ? vaultOwner : _from, _amount ); _mint(_to, _amount); } else { assert(_from == dolomiteMargin); // transfers FROM DolomiteMargin must be made TO a vault OR to a tokenConverter address vaultOwner = _vaultToUserMap[_to]; Require.that( vaultOwner != address(0) || _tokenConverterToIsTrustedMap[_to], _FILE, "Invalid to" ); IIsolationModeTokenVaultV1(queuedTransfer.vault).executeWithdrawalFromVault( vaultOwner != address(0) ? vaultOwner : _to, _amount ); _burn(_from, _amount); } } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeVaultFactory } from "./IIsolationModeVaultFactory.sol"; import { IHandlerRegistry } from "../../interfaces/IHandlerRegistry.sol"; import { IDolomiteStructs } from "../../protocol/interfaces/IDolomiteStructs.sol"; /** * @title IAsyncFreezableIsolationModeVaultFactory * @author Dolomite * * @notice A wrapper contract around a certain token to offer isolation mode features for DolomiteMargin and freezable * vaults. */ interface IAsyncFreezableIsolationModeVaultFactory is IIsolationModeVaultFactory { // ========================================================== // ========================= Enums ========================== // ========================================================== enum FreezeType { Deposit, Withdrawal } // ========================================================== // ========================= Events ========================= // ========================================================== event ExecutionFeeSet(uint256 _executionFee); event MaxExecutionFeeSet(uint256 _maxExecutionFee); event HandlerRegistrySet(address _handlerRegistry); event VaultAccountFrozen( address indexed vault, uint256 indexed accountNumber, bool isFrozen ); // =========================================================== // ======================== Functions ======================== // =========================================================== /** * * @param _executionFee The amount of gas (in ETH) that should be sent with a position so the user can pay the * gas fees to be liquidated. The gas fees are refunded when a position is closed. */ function ownerSetExecutionFee(uint256 _executionFee) external; /** * * @param _maxExecutionFee The max amount of gas (in ETH) that can be sent with a position so the user can pay * the gas fees to be liquidated. The gas fees are refunded when a position is closed. */ function ownerSetMaxExecutionFee(uint256 _maxExecutionFee) external; /** * * @param _handlerRegistry The new address of the handler registry contract */ function ownerSetHandlerRegistry(address _handlerRegistry) external; /** * @dev Sets whether or not the vault should use the GmxV2IsolationModeWrapperTraderV2 as the ERC20 transfer * source when the call to `depositIntoVault` occurs. This value is unset once it is consumed by the call * to `depositIntoVault`. * * @param _vault The vault whose `_isDepositSourceWrapper` value is being set. * @param _isDepositSourceWrapper Whether or not the vault should use the `GmxV2IsolationModeWrapperTraderV2` as * deposit source. */ function setIsVaultDepositSourceWrapper(address _vault, bool _isDepositSourceWrapper) external; /** * @dev Sets whether or not the vault should skip the transferFrom call when depositing into Dolomite Margin. * This enables the protocol to not revert if there are no tokens in the vault, since no ERC20 event is * emitted with the underlying tokens. This value is unset after it is consumed in `depositIntoVault` * or `withdrawFromVault`. * * @param _vault The vault whose shouldSkipTransfer value is being set. * @param _shouldSkipTransfer Whether or not the vault should skip the ERC20 transfer for the underlying token. */ function setShouldVaultSkipTransfer(address _vault, bool _shouldSkipTransfer) external; /** * Performs the deposit from a token wrapper/unwrapper contract into the vault. * * @param _vault The address of the vault making the deposit * @param _vaultAccountNumber The account number (sub account) for the corresponding vault * @param _amountWei The amount of the token to deposit */ function depositIntoDolomiteMarginFromTokenConverter( address _vault, uint256 _vaultAccountNumber, uint256 _amountWei ) external; /** * * @param _vault The address of the vault whose frozen status should change * @param _accountNumber The account number (sub account) for the corresponding vault * @param _freezeType The type of freeze that may have a pending callback amount (Deposit or Withdrawal) * @param _amountDeltaWei The amount that is pending for this sub account. Set to positive to add to the pending * amount or negative to subtract from it. * @param _conversionToken The token being used to convert into/from the freezable token */ function setVaultAccountPendingAmountForFrozenStatus( address _vault, uint256 _accountNumber, FreezeType _freezeType, IDolomiteStructs.Wei calldata _amountDeltaWei, address _conversionToken ) external; /** * * @param _vault The address of the vault that may be frozen * @return True if any sub account for the corresponding `_vault` is frozen, or false if none are. */ function isVaultFrozen( address _vault ) external view returns (bool); /** * * @param _vault The address of the vault that may be frozen * @param _accountNumber The account number (sub account) for the corresponding vault * @return True if the corresponding sub account is frozen, or false if it is not. */ function isVaultAccountFrozen( address _vault, uint256 _accountNumber ) external view returns (bool); /** * * @param _vault The address of the vault that may have a pending callback amount * @param _accountNumber The account number (sub account) for the corresponding vault * @param _freezeType The type of freeze that may have a pending callback amount (Deposit or Withdrawal) * @return The pending amount for this account. 0 means nothing is pending. FreezeType.ForDeposit * means the pending amount is positive, and FreezeType.ForWithdrawal means the pending * amount is negative. */ function getPendingAmountByAccount( address _vault, uint256 _accountNumber, FreezeType _freezeType ) external view returns (uint256); /** * * @param _vault The address of the vault that may have a pending callback amount * @param _freezeType The type of freeze that may have a pending callback amount (Deposit or Withdrawal) * @return The pending amount for this account. 0 means nothing is pending. FreezeType.ForDeposit * means the pending amount is positive, and FreezeType.ForWithdrawal means the pending * amount is negative. */ function getPendingAmountByVault( address _vault, FreezeType _freezeType ) external view returns (uint256); /** * * @param _vault The address of the vault that may have a pending conversion token selected * @param _accountNumber The account number (sub account) for the corresponding vault * @return The pending conversion token for this account. address(0) means nothing is pending. * Users must do any follow-up conversions (for liquidations) using the same conversion * token to maintain uniformity. */ function getOutputTokenByAccount( address _vault, uint256 _accountNumber ) external view returns (address); /** * * @return The address of the handler registry contract */ function handlerRegistry() external view returns (IHandlerRegistry); /** * @dev The amount of gas (in ETH) that should be sent with a position so the user can pay the gas fees to be * liquidated. The gas fees are refunded when a position is closed. */ function executionFee() external view returns (uint256); /** * @dev The max amount of gas (in ETH) that should be sent with a position so the user can pay the gas fees to * be liquidated. The gas fees are refunded when a position is closed. */ function maxExecutionFee() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IHandlerRegistry } from "../../interfaces/IHandlerRegistry.sol"; import { IWETH } from "../../protocol/interfaces/IWETH.sol"; /** * @title IAsyncIsolationModeTraderBase * @author Dolomite * */ interface IAsyncIsolationModeTraderBase { // ================================================ // ==================== Events ==================== // ================================================ event OwnerWithdrawETH(address _receiver, uint256 _bal); // =================================================== // ==================== Functions ==================== // =================================================== function ownerWithdrawETH(address _receiver) external; function callbackGasLimit() external view returns (uint256); function isHandler(address _handler) external view returns (bool); function HANDLER_REGISTRY() external view returns (IHandlerRegistry); function WETH() external view returns (IWETH); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IBorrowPositionProxyV2 } from "../../interfaces/IBorrowPositionProxyV2.sol"; import { IDolomiteRegistry } from "../../interfaces/IDolomiteRegistry.sol"; import { IGenericTraderBase } from "../../interfaces/IGenericTraderBase.sol"; import { IGenericTraderProxyV1 } from "../../interfaces/IGenericTraderProxyV1.sol"; import { AccountBalanceLib } from "../../lib/AccountBalanceLib.sol"; import { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteStructs } from "../../protocol/interfaces/IDolomiteStructs.sol"; /** * @title IIsolationModeTokenVaultV1 * @author Dolomite * * @notice Interface for the implementation contract used by proxy user vault contracts. */ interface IIsolationModeTokenVaultV1 { struct SwapExactInputForOutputParams { uint256 tradeAccountNumber; uint256[] marketIdsPath; uint256 inputAmountWei; uint256 minOutputAmountWei; IGenericTraderProxyV1.TraderParam[] tradersPath; IDolomiteStructs.AccountInfo[] makerAccounts; IGenericTraderProxyV1.UserConfig userConfig; } // =========================================================== // ======================== Functions ======================== // =========================================================== /** * @notice Initializes the vault contract. Should only be executable once by the proxy. */ function initialize() external; /** * @notice End-user function for calling more than one vault function at a time. Should only * be executable by the vault owner. */ function multicall(bytes[] calldata _calls) external; /** * @notice End-user function for depositing the vault factory's underlying token into DolomiteMargin. Should only * be executable by the vault owner OR the vault factory. */ function depositIntoVaultForDolomiteMargin(uint256 _toAccountNumber, uint256 _amountWei) external; /** * @notice End-user function for withdrawing the vault factory's underlying token from DolomiteMargin. Should only * be executable by the vault owner. */ function withdrawFromVaultForDolomiteMargin(uint256 _fromAccountNumber, uint256 _amountWei) external; /** * @notice End-user function for opening a borrow position involving the vault factory's underlying token. Should * only be executable by the vault owner. Reverts if `_fromAccountNumber` is not 0 or if `_toAccountNumber` * is 0. */ function openBorrowPosition( uint256 _fromAccountNumber, uint256 _toAccountNumber, uint256 _amountWei ) external payable; /** * @notice End-user function for opening a margin position involving the vault factory's underlying token. Should * only be executable by the vault owner. Reverts if `_fromAccountNumber` is not 0 or if `_toAccountNumber` * is 0. The `_borrowMarketId` is unused except for emitting the event needed to index the Subgraph. */ function openMarginPosition( uint256 _fromAccountNumber, uint256 _toAccountNumber, uint256 _borrowMarketId, uint256 _amountWei ) external payable; /** * @notice End-user function for closing a borrow position involving the vault factory's underlying token. Should * only be executable by the vault owner. Reverts if `_borrowAccountNumber` is 0 or if `_toAccountNumber` * is not 0. */ function closeBorrowPositionWithUnderlyingVaultToken( uint256 _borrowAccountNumber, uint256 _toAccountNumber ) external; /** * @notice End-user function for closing a borrow position involving anything BUT the vault factory's underlying * token. Should only be executable by the vault owner. Throws if any of the `collateralMarketIds` is set * to the vault factory's underlying token. Reverts if `_borrowAccountNumber` is 0. */ function closeBorrowPositionWithOtherTokens( uint256 _borrowAccountNumber, uint256 _toAccountNumber, uint256[] calldata collateralMarketIds ) external; /** * @notice End-user function for transferring collateral into a position using the vault factory's underlying * token. Should only be executable by the vault owner. Reverts if `_fromAccountNumber` is not 0 or if * `_borrowAccountNumber` is 0. */ function transferIntoPositionWithUnderlyingToken( uint256 _fromAccountNumber, uint256 _borrowAccountNumber, uint256 _amountWei ) external; /** * @notice End-user function for transferring collateral into a position using anything BUT the vault factory's * underlying token. Should only be executable by the vault owner. Throws if the `_marketId` is set to the * vault factory's underlying token. Reverts if `_borrowAccountNumber` is 0. */ function transferIntoPositionWithOtherToken( uint256 _fromAccountNumber, uint256 _borrowAccountNumber, uint256 _marketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * @notice End-user function for transferring collateral from a position using the vault factory's underlying * token. Should only be executable by the vault owner. Reverts if `_borrowAccountNumber` is 0 or if * `_toAccountNumber` is not 0. */ function transferFromPositionWithUnderlyingToken( uint256 _borrowAccountNumber, uint256 _toAccountNumber, uint256 _amountWei ) external; /** * @notice End-user function for transferring collateral from a position using anything BUT the vault factory's * underlying token. Should only be executable by the vault owner. Throws if the `_marketId` is set to the * vault factory's underlying token. Reverts if `_borrowAccountNumber` is 0. */ function transferFromPositionWithOtherToken( uint256 _borrowAccountNumber, uint256 _toAccountNumber, uint256 _marketId, uint256 _amountWei, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * @notice End-user function for transferring collateral involving anything BUT the vault factory's underlying * token. Should only be executable by the vault owner. Throws if the `_marketId` is set to the vault * factory's underlying token. Reverts if `_borrowAccountNumber` is 0. */ function repayAllForBorrowPosition( uint256 _fromAccountNumber, uint256 _borrowAccountNumber, uint256 _marketId, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) external; /** * @dev End-user function for adding collateral from the vault (in the case where `_marketIdsPath[0]` is the * underlying marketId) or the vault owner (in the case where `_marketIdsPath[0]` is not the underlying * marketId), then trading an exact amount of input for a minimum amount of output. Reverts if * `_borrowAccountNumber` is 0 or if `_fromAccountNumber` is not 0 (and the `_marketIdsPath[0]` is the * underlying). Reverts if the user has a negative balance for `_marketIdsPath[0]`. * * @param _fromAccountNumber The account number to use for the source of the transfer. * @param _borrowAccountNumber The account number to use for the vault's trade. Cannot be 0. * @param _marketIdsPath The path of market IDs to use for each trade action. Length should be equal * to `_tradersPath.length + 1`. * @param _inputAmountWei The input amount (in wei) to use for the initial trade action. Setting this * value to `uint(-1)` will use the user's full balance. * @param _minOutputAmountWei The minimum output amount expected to be received by the user. * @param _tradersPath The path of traders to use for each trade action. Length should be equal to * `_marketIdsPath.length - 1`. * @param _makerAccounts The accounts that will be used for the maker side of the trades involving * `TraderType.InternalLiquidity`. * @param _userConfig The user configuration for the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.From` will check that the user's `_borrowAccountNumber` * and `_fromAccountNumber` is non-negative after the trade. */ function addCollateralAndSwapExactInputForOutput( uint256 _fromAccountNumber, uint256 _borrowAccountNumber, uint256[] calldata _marketIdsPath, uint256 _inputAmountWei, uint256 _minOutputAmountWei, IGenericTraderBase.TraderParam[] calldata _tradersPath, IDolomiteStructs.AccountInfo[] calldata _makerAccounts, IGenericTraderProxyV1.UserConfig calldata _userConfig ) external payable; /** * @dev End-user function for removing collateral from the vault (in the case where `_marketIdsPath[last]` is * the underlying marketId) or the vault owner (in the case where `_marketIdsPath[last]` is not the * underlying marketId). Reverts if `_borrowAccountNumber` is 0 or if `_toAccountNumber` is not 0 (and * the `_marketIdsPath[0]` is the underlying). Reverts if the user has a negative balance before the swap * for `_marketIdsPath[last]`. * * @param _toAccountNumber The account number to receive the collateral transfer after the trade. * @param _borrowAccountNumber The account number to use for the vault's trade. * @param _marketIdsPath The path of market IDs to use for each trade action. Length should be equal * to `_tradersPath.length + 1`. * @param _inputAmountWei The input amount (in wei) to use for the initial trade action. Setting this * value to `uint(-1)` will use the user's full balance. * @param _minOutputAmountWei The minimum output amount expected to be received by the user. * @param _tradersPath The path of traders to use for each trade action. Length should be equal to * `_marketIdsPath.length - 1`. * @param _makerAccounts The accounts that will be used for the maker side of the trades involving * `TraderType.InternalLiquidity`. * @param _userConfig The user configuration for the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.From` will check that the user's `_tradeAccountNumber` * is non-negative after the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.To` has no effect. */ function swapExactInputForOutputAndRemoveCollateral( uint256 _toAccountNumber, uint256 _borrowAccountNumber, uint256[] calldata _marketIdsPath, uint256 _inputAmountWei, uint256 _minOutputAmountWei, IGenericTraderBase.TraderParam[] calldata _tradersPath, IDolomiteStructs.AccountInfo[] calldata _makerAccounts, IGenericTraderProxyV1.UserConfig calldata _userConfig ) external payable; /** * @dev End-user function for swapping an exact amount of input for a minimum amount of output. Reverts if * `_tradeAccountNumber` is 0. * * @param _tradeAccountNumber The account number to use for the vault's trade. Cannot be 0. * @param _marketIdsPath The path of market IDs to use for each trade action. Length should be equal * to `_tradersPath.length + 1`. * @param _inputAmountWei The input amount (in wei) to use for the initial trade action. Setting this * value to `uint(-1)` will use the user's full balance. * @param _minOutputAmountWei The minimum output amount expected to be received by the user. * @param _tradersPath The path of traders to use for each trade action. Length should be equal to * `_marketIdsPath.length - 1`. * @param _makerAccounts The accounts that will be used for the maker side of the trades involving * `TraderType.InternalLiquidity`. * @param _userConfig The user configuration for the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.From` will check that the user's `_tradeAccountNumber` * is non-negative after the trade. Setting the `balanceCheckFlag` to * `BalanceCheckFlag.To` has no effect. */ function swapExactInputForOutput( uint256 _tradeAccountNumber, uint256[] calldata _marketIdsPath, uint256 _inputAmountWei, uint256 _minOutputAmountWei, IGenericTraderBase.TraderParam[] calldata _tradersPath, IDolomiteStructs.AccountInfo[] calldata _makerAccounts, IGenericTraderProxyV1.UserConfig calldata _userConfig ) external payable; // ==================== Does not modify balances ==================== /** * @notice Attempts to deposit assets into this vault from the vault's owner. Reverts if the caller is not the * Vault Factory. * * @param _from The sender of the tokens into this vault. * @param _amount The amount of the vault's underlying token to transfer. */ function executeDepositIntoVault(address _from, uint256 _amount) external; /** * @notice Attempts to withdraw assets from this vault to the recipient. Reverts if the caller is not the * Vault Factory. * * @param _recipient The address to receive the withdrawal. * @param _amount The amount of the vault's underlying token to transfer out. */ function executeWithdrawalFromVault(address _recipient, uint256 _amount) external; /** * @return The amount of `UNDERLYING_TOKEN` that are currently in this vault. */ function underlyingBalanceOf() external view returns (uint256); /** * @return The registry used to discover important addresses for Dolomite */ function dolomiteRegistry() external view returns (IDolomiteRegistry); function marketId() external view returns (uint256); function BORROW_POSITION_PROXY() external view returns (IBorrowPositionProxyV2); function DOLOMITE_MARGIN() external view returns (IDolomiteMargin); function VAULT_FACTORY() external view returns (address); function OWNER() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeTokenVaultV1WithFreezable } from "./IIsolationModeTokenVaultV1WithFreezable.sol"; import { IHandlerRegistry } from "../../interfaces/IHandlerRegistry.sol"; import { IWETH } from "../../protocol/interfaces/IWETH.sol"; /** * @title IIsolationModeTokenVaultV1WithAsyncFreezable * @author Dolomite * * @notice Interface for the implementation contract used by proxy user vault contracts. */ interface IIsolationModeTokenVaultV1WithAsyncFreezable is IIsolationModeTokenVaultV1WithFreezable { // ================================================ // ==================== Events ==================== // ================================================ event IsDepositSourceWrapperSet(bool _isDepositSourceWrapper); event ShouldSkipTransferSet(bool _shouldSkipTransfer); event ExecutionFeeSet(uint256 _accountNumber, uint256 _executionFee); event VirtualBalanceSet(uint256 _balance); // =================================================== // ==================== Functions ==================== // =================================================== function initiateUnwrapping( uint256 _tradeAccountNumber, uint256 _inputAmount, address _outputToken, uint256 _minOutputAmount, bytes calldata _extraData ) external payable; // =========================================================== // ======================== Functions ======================== // =========================================================== /** * @dev Throws if the inputAmount is too large the user's whole balance, or if the * outputToken is invalid. */ function initiateUnwrappingForLiquidation( uint256 _tradeAccountNumber, uint256 _inputAmount, address _outputToken, uint256 _minOutputAmount, bytes calldata _extraData ) external payable; /** * This should only ever be true in the middle of a call. This value should be unset after it is consumed. If this * is called around a try-catch block, it should be unset in the `catch` block. * * @param _isDepositSourceWrapper True if the vault should should pull the deposit from the corresponding Wrapper * contract in the next call to `executeDepositIntoVault`. */ function setIsVaultDepositSourceWrapper(bool _isDepositSourceWrapper) external; /** * * @param _shouldSkipTransfer True if the vault should skip the transfer in/out of the vault when * `executeDepositIntoVault` or `executeWithdrawalFromVault` is called. * This should only ever be true in the middle of a call. This value should be unset * after it is consumed. If this is called around a try-catch block, it should be unset * in the catch block. */ function setShouldVaultSkipTransfer(bool _shouldSkipTransfer) external; /** * * @return True if the vault should pull the deposit from the corresponding Wrapper contract in the next call to * `executeDepositIntoVault`. This should only ever be true in the middle of a call. Otherwise, this should * always return `false`. */ function isDepositSourceWrapper() external view returns (bool); /** * * @return True if the vault should skip the transfer in/out of the vault when `executeDepositIntoVault` or * when `executeWithdrawalFromVault` is called. This should only ever be true in the middle of a call. * Otherwise, this should always return `false`. */ function shouldSkipTransfer() external view returns (bool); /** * * @return The registry contract for this token vault */ function handlerRegistry() external view returns (IHandlerRegistry); /** * * @param _accountNumber The sub account whose gas/execution fees should be retrieved * @return The execution fee that's saved for the given account number */ function getExecutionFeeForAccountNumber(uint256 _accountNumber) external view returns (uint256); /** * * @param _accountNumber The account number of the vault to check. * @return The pending conversion token for this account. address(0) means nothing is pending. * Users must do any follow-up conversions (for liquidations) using the same conversion * token to maintain uniformity. */ function getOutputTokenByVaultAccount(uint256 _accountNumber) external view returns (address); /** * @return The balance of the assets in this vault assuming no pending withdrawals (but includes pending deposits). */ function virtualBalance() external view returns (uint256); /** * * @param _accountNumber The account number of the vault to check. * @return True if the vault account is frozen, false otherwise. */ function isVaultAccountFrozen(uint256 _accountNumber) external view returns (bool); function WETH() external view returns (IWETH); function CHAIN_ID() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeTokenVaultV1WithAsyncFreezable } from "./IIsolationModeTokenVaultV1WithAsyncFreezable.sol"; import { IIsolationModeTokenVaultV1WithPausable } from "./IIsolationModeTokenVaultV1WithPausable.sol"; /** * @title IIsolationModeTokenVaultV1WithAsyncFreezableAndPausable * @author Dolomite * * @notice Interface for the implementation contract used by proxy user vault contracts. */ interface IIsolationModeTokenVaultV1WithAsyncFreezableAndPausable is // solhint-disable-line no-empty-blocks IIsolationModeTokenVaultV1WithAsyncFreezable, IIsolationModeTokenVaultV1WithPausable {}
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeTokenVaultV1 } from "./IIsolationModeTokenVaultV1.sol"; /** * @title IIsolationModeTokenVaultV1WithFreezable * @author Dolomite * * @notice Interface for the implementation contract used by proxy user vault contracts. */ interface IIsolationModeTokenVaultV1WithFreezable is IIsolationModeTokenVaultV1 { // ================================================ // ==================== Events ==================== // ================================================ event IsVaultFrozenSet(bool _isVaultFrozen); /** /** * @return True if the entire vault is frozen, false otherwise. */ function isVaultFrozen() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeTokenVaultV1 } from "./IIsolationModeTokenVaultV1.sol"; /** * @title IIsolationModeTokenVaultV1WithPausable * @author Dolomite * * @notice Interface for the implementation contract used by proxy user vault contracts. */ interface IIsolationModeTokenVaultV1WithPausable is IIsolationModeTokenVaultV1 { // =================================================== // ==================== Functions ==================== // =================================================== /** * @return true if redemptions (conversion) from this isolated token to its underlying are paused or are in a * distressed state. Resolving this function to true actives the Pause Sentinel, which prevents further * contamination of this market across Dolomite. */ function isExternalRedemptionPaused() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteMarginExchangeWrapper } from "../../protocol/interfaces/IDolomiteMarginExchangeWrapper.sol"; /** * @title IIsolationModeUnwrapperTraderV2 * @author Dolomite * * V2 Interface for a contract that can convert an isolation mode token into an underlying component token. */ interface IIsolationModeUnwrapperTraderV2 is IDolomiteMarginExchangeWrapper { struct CreateActionsForUnwrappingParams { /// @dev The index of the account (according the Accounts[] array) that is performing the sell. uint256 primaryAccountId; /// @dev The index of the account (according the Accounts[] array) that is being liquidated. This is set to /// `_primaryAccountId` if a liquidation is not occurring. uint256 otherAccountId; /// @dev The address of the owner of the account that is performing the sell. address primaryAccountOwner; /// @dev The account number of the owner of the account that is performing the sell. uint256 primaryAccountNumber; /// @dev The address of the owner of the account that is being liquidated. This is set to /// `_primaryAccountOwner` if a liquidation is not occurring. address otherAccountOwner; /// @dev The account number of the owner of the account that is being liquidated. This is set to /// `_primaryAccountNumber` if a liquidation is not occurring. uint256 otherAccountNumber; /// @dev The market that is being outputted by the unwrapping. uint256 outputMarket; /// @dev The market that is being unwrapped, should be equal to `token()`. uint256 inputMarket; /// @dev The min amount of `_outputMarket` that must be outputted by the unwrapping. uint256 minOutputAmount; /// @dev The amount of the `_inputMarket` that the _primaryAccountId must sell. uint256 inputAmount; /// @dev The calldata to pass through to any external sales that occur. bytes orderData; } /** * @return The isolation mode token that this contract can unwrap (the input token). */ function token() external view returns (address); /** * @return True if the `_outputToken` is a valid output token for this contract, to be unwrapped by `token()`. */ function isValidOutputToken(address _outputToken) external view returns (bool); /** * @notice Creates the necessary actions for selling the `_inputMarket` into `_outputMarket`. Note, the * `_inputMarket` should be equal to `token()` and `_outputMarket` should be validated to be a correct * market that can be transformed into `token()`. * * @param _params The parameters for creating the actions for unwrapping. * @return The actions that will be executed to unwrap the `_inputMarket` into `_outputMarket`. */ function createActionsForUnwrapping( CreateActionsForUnwrappingParams calldata _params ) external view returns (IDolomiteMargin.ActionArgs[] memory); /** * @return The number of actions used to unwrap the isolation mode token. */ function actionsLength() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title IIsolationModeUpgradeableProxy * @author Dolomite * * @notice The interface for the upgradeable proxy contract that holds each user's tokens that are wrapped by the * IsolationModeVaultFactory. */ interface IIsolationModeUpgradeableProxy { /** * * @param _account The owner of this vault contract */ function initialize(address _account) external; function isInitialized() external view returns (bool); function implementation() external view returns (address); function vaultFactory() external view returns (address); function owner() external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IBorrowPositionProxyV2 } from "../../interfaces/IBorrowPositionProxyV2.sol"; import { IOnlyDolomiteMargin } from "../../interfaces/IOnlyDolomiteMargin.sol"; /** * @title IIsolationModeVaultFactory * @author Dolomite * * @notice A wrapper contract around a certain token to offer isolation mode features for DolomiteMargin. */ interface IIsolationModeVaultFactory is IOnlyDolomiteMargin { // ================================================= // ==================== Structs ==================== // ================================================= struct QueuedTransfer { address from; address to; uint256 amount; address vault; bool isExecuted; } // ================================================ // ==================== Events ==================== // ================================================ event UserVaultImplementationSet( address indexed previousUserVaultImplementation, address indexed newUserVaultImplementation ); event TokenConverterSet(address indexed tokenConverter, bool isTrusted); event VaultCreated(address indexed account, address vault); event Initialized(); event TransferQueued( uint256 indexed transferCursor, address from, address to, uint256 amountWei, address vault ); // ====================================================== // ================== Admin Functions =================== // ====================================================== /** * @notice Initializes this contract's variables that are dependent on this token being added to DolomiteMargin. */ function ownerInitialize(address[] calldata _tokenConverters) external; /** * * @param _userVaultImplementation The address of the new vault implementation contract */ function ownerSetUserVaultImplementation(address _userVaultImplementation) external; /** * @notice A token converter is used to convert this underlying token into a Dolomite-compatible one for deposit * or withdrawal * * @param _tokenConverter The address of the token converter contract to set whether or not it's trusted for * executing transfers to/from vaults * @param _isTrusted True if the token converter is trusted, false otherwise */ function ownerSetIsTokenConverterTrusted(address _tokenConverter, bool _isTrusted) external; // ====================================================== // ================== User Functions =================== // ====================================================== /** * @notice Creates the vault for `_account` * * @param _account The account owner to create the vault for */ function createVault(address _account) external returns (address); /** * @notice Creates the vault for `msg.sender` * * @param _toAccountNumber The account number of the account to which the tokens will be deposited * @param _amountWei The amount of tokens to deposit */ function createVaultAndDepositIntoDolomiteMargin( uint256 _toAccountNumber, uint256 _amountWei ) external returns (address); /** * @notice Deposits a token into the vault owner's account at `_toAccountNumber`. This function can only be called * by a user's vault contract. Reverts if `_marketId` is set to the market ID of this vault. * * @param _toAccountNumber The account number of the account to which the tokens will be deposited * @param _marketId The market ID of the token to deposit * @param _amountWei The amount of tokens to deposit */ function depositOtherTokenIntoDolomiteMarginForVaultOwner( uint256 _toAccountNumber, uint256 _marketId, uint256 _amountWei ) external; /** * @notice Enqueues a transfer into Dolomite Margin from the vault. Assumes msg.sender is a trusted token * converter, else reverts. Reverts if `_vault` is not a valid vault contract. * * @param _vault The address of the vault that the token converter is interacting with * @param _amountWei The amount of tokens to transfer into Dolomite Margin */ function enqueueTransferIntoDolomiteMargin( address _vault, uint256 _amountWei ) external; /** * @notice Enqueues a transfer from Dolomite Margin to the token converter. Assumes msg.sender is a trusted token * converter, else reverts. Reverts if `_vault` is not a valid vault contract. * * @param _vault The address of the vault that the token converter is interacting with * @param _amountWei The amount of tokens to transfer from Dolomite Margin to the token converter */ function enqueueTransferFromDolomiteMargin( address _vault, uint256 _amountWei ) external; /** * @notice This function should only be called by a user's vault contract * * @param _toAccountNumber The account number of the account to which the tokens will be deposited * @param _amountWei The amount of tokens to deposit */ function depositIntoDolomiteMargin( uint256 _toAccountNumber, uint256 _amountWei ) external; /** * @notice This function should only be called by a user's vault contract * * @param _fromAccountNumber The account number of the account from which the tokens will be withdrawn * @param _amountWei The amount of tokens to withdraw */ function withdrawFromDolomiteMargin( uint256 _fromAccountNumber, uint256 _amountWei ) external; // ============================================ // ================= Constants ================ // ============================================ /** * @return The address of the token that this vault wraps around */ function UNDERLYING_TOKEN() external view returns (address); /** * @return The address of the BorrowPositionProxyV2 contract */ function BORROW_POSITION_PROXY() external view returns (IBorrowPositionProxyV2); // ================================================= // ================= View Functions ================ // ================================================= /** * @return The market ID of this token contract according to DolomiteMargin. This value is initializes in the * #initialize function */ function marketId() external view returns (uint256); /** * @return This function should always return `true`. It's used by The Graph to index this contract as a Wrapper. */ function isIsolationAsset() external view returns (bool); /** * @return Returns the current transfer cursor */ function transferCursor() external view returns (uint256); /** * * @param _transferCursor The cursor used to key into the mapping of queued transfers * @return The transfer enqueued in the mapping at the cursor's position */ function getQueuedTransferByCursor(uint256 _transferCursor) external view returns (QueuedTransfer memory); /** * @return The market IDs of the assets that can be borrowed in a position with this wrapped asset. An empty array * indicates that any non-isolation mode asset can be borrowed against it. */ function allowableDebtMarketIds() external view returns (uint256[] memory); /** * @return The market IDs of the assets that can be used as collateral in a position with this wrapped asset. An * empty array indicates that any non-isolation mode asset can be borrowed against it. To indicate that no * assets can be used as collateral, return an array with a single element containing #marketId(). */ function allowableCollateralMarketIds() external view returns (uint256[] memory); /** * @return The address of the current vault implementation contract */ function userVaultImplementation() external view returns (address); /** * * @param _account The account owner to get the vault for * @return _vault The address of the vault created for `_account`. Returns address(0) if no vault has been * created yet for this account. */ function getVaultByAccount(address _account) external view returns (address _vault); /** * @notice Same as `getVaultByAccount`, but always returns the user's non-zero vault address. */ function calculateVaultByAccount(address _account) external view returns (address _vault); /** * * @param _vault The vault that's used by an account for depositing/withdrawing * @return _account The address of the account that owns the `_vault` */ function getAccountByVault(address _vault) external view returns (address _account); /** * @notice A token converter is used to convert this underlying token into a Dolomite-compatible one for deposit * or withdrawal * @return True if the token converter is currently in-use by this contract. */ function isTokenConverterTrusted(address _tokenConverter) external view returns (bool); function getProxyVaultInitCodeHash() external pure returns (bytes32); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteMarginExchangeWrapper } from "../../protocol/interfaces/IDolomiteMarginExchangeWrapper.sol"; /** * @title IIsolationModeWrapperTraderV2 * @author Dolomite * * Interface for a contract that can convert a token into an isolation mode token. */ interface IIsolationModeWrapperTraderV2 is IDolomiteMarginExchangeWrapper { struct CreateActionsForWrappingParams { /// @dev The index of the account (according the Accounts[] array) that is performing the sell. uint256 primaryAccountId; /// @dev The index of the account (according the Accounts[] array) that is being liquidated. This is set to /// `_primaryAccountId` if a liquidation is not occurring. uint256 otherAccountId; /// @dev The address of the owner of the account that is performing the sell. address primaryAccountOwner; /// @dev The account number of the owner of the account that is performing the sell. uint256 primaryAccountNumber; /// @dev The address of the owner of the account that is being liquidated. This is set to /// `_primaryAccountOwner` if a liquidation is not occurring. address otherAccountOwner; /// @dev The account number of the owner of the account that is being liquidated. This is set to /// `_primaryAccountNumber` if a liquidation is not occurring. uint256 otherAccountNumber; /// @dev The market that is being outputted by the wrapping, should be equal to `token(). uint256 outputMarket; /// @dev The market that is being used to wrap into `token()`. uint256 inputMarket; /// @dev The min amount of `_outputMarket` that must be outputted by the wrapping. uint256 minOutputAmount; /// @dev The amount of the `_inputMarket` that the _primaryAccountId must sell. uint256 inputAmount; /// @dev The calldata to pass through to any external sales that occur. bytes orderData; } /** * @return The isolation mode token that this contract can wrap (the output token) */ function token() external view returns (address); /** * @return True if the `_inputToken` is a valid input token for this contract, to be wrapped into `token()` */ function isValidInputToken(address _inputToken) external view returns (bool); /** * @notice Creates the necessary actions for selling the `_inputMarket` into `_outputMarket`. Note, the * `_outputMarket` should be equal to `token()` and `_inputMarket` should be validated to be a correct * market that can be transformed into `token()`. * * @param _params The parameters for creating the actions for wrapping. * @return The actions that will be executed to unwrap the `_inputMarket` into `_outputMarket`. */ function createActionsForWrapping( CreateActionsForWrappingParams calldata _params ) external view returns (IDolomiteMargin.ActionArgs[] memory); /** * @return The number of Actions used to wrap a valid input token into the this wrapper's Isolation Mode token. */ function actionsLength() external pure returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeUnwrapperTraderV2 } from "./IIsolationModeUnwrapperTraderV2.sol"; import { IIsolationModeVaultFactory } from "./IIsolationModeVaultFactory.sol"; import { IOnlyDolomiteMargin } from "../../interfaces/IOnlyDolomiteMargin.sol"; /** * @title IUpgradeableAsyncIsolationModeUnwrapperTrader * @author Dolomite * * Interface for an upgradeable contract that can convert an isolation mode token into another token. */ interface IUpgradeableAsyncIsolationModeUnwrapperTrader is IIsolationModeUnwrapperTraderV2, IOnlyDolomiteMargin { // ================================================ // ==================== Structs =================== // ================================================ struct WithdrawalInfo { bytes32 key; address vault; uint256 accountNumber; /// @dev The amount of FACTORY tokens that is being sold uint256 inputAmount; address outputToken; /// @dev initially 0 until the withdrawal is executed uint256 outputAmount; bool isRetryable; bool isLiquidation; bytes extraData; } struct State { uint256 actionsLength; uint256 reentrancyGuard; address vaultFactory; address handlerRegistry; mapping(bytes32 => WithdrawalInfo) withdrawalInfo; } // ================================================ // ===================== Enums ==================== // ================================================ enum TradeType { FromWithdrawal, FromDeposit, NoOp } // =================================================== // ==================== Functions ==================== // =================================================== function executeWithdrawalForRetry(bytes32 _key) external; function executeWithdrawalCancellation(bytes32 _key) external; function emitWithdrawalExecuted(bytes32 _key) external; /** * Notifies the unwrapper that it'll be entered for a trade from the unwrapper. This allows it to modify the action * length */ function handleCallbackFromWrapperBefore() external; /** * Reverts any changes made in `handleCallbackFromWrapperBefore`. Can only be called by a corresponding Wrapper * trader. */ function handleCallbackFromWrapperAfter() external; /** * Transfers underlying tokens from the vault (msg.sender) to this contract to initiate a redemption. */ function vaultInitiateUnwrapping( uint256 _tradeAccountNumber, uint256 _inputAmount, address _outputToken, uint256 _minOutputAmount, bool _isLiquidation, bytes calldata _extraData ) external payable; /** * * @param _key The key of the withdrawal that should be cancelled */ function initiateCancelWithdrawal(bytes32 _key) external; function getWithdrawalInfo(bytes32 _key) external view returns (WithdrawalInfo memory); function VAULT_FACTORY() external view returns (IIsolationModeVaultFactory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeVaultFactory } from "./IIsolationModeVaultFactory.sol"; import { IIsolationModeWrapperTraderV2 } from "./IIsolationModeWrapperTraderV2.sol"; import { IOnlyDolomiteMargin } from "../../interfaces/IOnlyDolomiteMargin.sol"; /** * @title IUpgradeableAsyncIsolationModeWrapperTrader * @author Dolomite * * Interface for an upgradeable contract that can convert a token into an isolation mode token. */ interface IUpgradeableAsyncIsolationModeWrapperTrader is IIsolationModeWrapperTraderV2, IOnlyDolomiteMargin { // ================================================ // ==================== Structs =================== // ================================================ struct State { mapping(bytes32 => DepositInfo) depositInfo; address vaultFactory; address handlerRegistry; } struct DepositInfo { bytes32 key; address vault; uint256 accountNumber; address inputToken; uint256 inputAmount; uint256 outputAmount; bool isRetryable; } // =================================================== // ==================== Functions ==================== // =================================================== /** * This should be called by the vault to initiate a cancellation for a deposit. * * @param _key The key of the deposit that should be cancelled */ function initiateCancelDeposit(bytes32 _key) external; function setDepositInfoAndReducePendingAmountFromUnwrapper( bytes32 _key, uint256 _outputAmountDeltaWei, DepositInfo calldata _depositInfo ) external; function emitDepositCancelled(bytes32 _key) external; function getDepositInfo(bytes32 _key) external view returns (DepositInfo memory); function VAULT_FACTORY() external view returns (IIsolationModeVaultFactory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { ProxyContractHelpers } from "../helpers/ProxyContractHelpers.sol"; import { Require } from "../protocol/lib/Require.sol"; import { IIsolationModeTokenVaultV1 } from "./interfaces/IIsolationModeTokenVaultV1.sol"; import { IIsolationModeUpgradeableProxy } from "./interfaces/IIsolationModeUpgradeableProxy.sol"; import { IIsolationModeVaultFactory } from "./interfaces/IIsolationModeVaultFactory.sol"; /** * @title IsolationModeUpgradeableProxy * @author Dolomite * * @notice Abstract "implementation" (for an upgradeable proxy) contract for wrapping tokens via a per-user vault that * can be used with DolomiteMargin */ contract IsolationModeUpgradeableProxy is IIsolationModeUpgradeableProxy, ProxyContractHelpers { using Address for address; // ============ Constants ============ bytes32 private constant _FILE = "IsolationModeUpgradeableProxy"; bytes32 private constant _IS_INITIALIZED_SLOT = bytes32(uint256(keccak256("eip1967.proxy.isInitialized")) - 1); bytes32 private constant _VAULT_FACTORY_SLOT = bytes32(uint256(keccak256("eip1967.proxy.vaultFactory")) - 1); bytes32 private constant _OWNER_SLOT = bytes32(uint256(keccak256("eip1967.proxy.owner")) - 1); // ======== Modifiers ========= modifier requireIsInitialized() { Require.that( isInitialized(), _FILE, "Not initialized" ); _; } // ============ Constructor ============ constructor() { _setAddress(_VAULT_FACTORY_SLOT, msg.sender); } // ============ Functions ============ receive() external payable requireIsInitialized { _callImplementation(implementation()); } // solhint-disable-next-line payable-fallback fallback() external payable requireIsInitialized { _callImplementation(implementation()); } function initialize( address _account ) external { Require.that( !isInitialized(), _FILE, "Already initialized" ); Require.that( IIsolationModeVaultFactory(vaultFactory()).getVaultByAccount(_account) == address(this), _FILE, "Invalid account", _account ); _setAddress(_OWNER_SLOT, _account); _safeDelegateCall(implementation(), abi.encodePacked(IIsolationModeTokenVaultV1.initialize.selector)); _setUint256(_IS_INITIALIZED_SLOT, 1); } function implementation() public override view returns (address) { return IIsolationModeVaultFactory(vaultFactory()).userVaultImplementation(); } function isInitialized() public override view returns (bool) { return _getUint256(_IS_INITIALIZED_SLOT) == 1; } function vaultFactory() public override view returns (address) { return _getAddress(_VAULT_FACTORY_SLOT); } function owner() public override view returns (address) { return _getAddress(_OWNER_SLOT); } function _safeDelegateCall(address _target, bytes memory _calldata) internal returns (bytes memory) { // solhint-disable-next-line avoid-low-level-calls (bool isSuccessful, bytes memory result) = _target.delegatecall(_calldata); assert(isSuccessful); return result; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { Require } from "../protocol/lib/Require.sol"; import { IsolationModeVaultFactory } from "./abstract/IsolationModeVaultFactory.sol"; /** * @title SimpleIsolationModeVaultFactory * @author Dolomite * * @notice Contract for wrapping tokens via a per-user vault that credits a user's balance within DolomiteMargin */ abstract contract SimpleIsolationModeVaultFactory is IsolationModeVaultFactory { // =================================================== // ==================== Constants ==================== // =================================================== bytes32 private constant _FILE = "SimpleIsolationModeVaultFactory"; // ================================================ // ==================== Fields ==================== // ================================================ uint256[] internal _allowableDebtMarketIds; uint256[] internal _allowableCollateralMarketIds; // =================================================== // ===================== Events ====================== // =================================================== event AllowableDebtMarketIdsSet(uint256[] allowableDebtMarketIds); event AllowableCollateralMarketIdsSet(uint256[] allowableCollateralMarketIds); // ================================================ // ================== Constructor ================= // ================================================ constructor( uint256[] memory _initialAllowableDebtMarketIds, uint256[] memory _initialAllowableCollateralMarketIds, address _underlyingToken, address _borrowPositionProxyV2, address _userVaultImplementation, address _dolomiteRegistry, address _dolomiteMargin ) IsolationModeVaultFactory( _underlyingToken, _borrowPositionProxyV2, _userVaultImplementation, _dolomiteRegistry, _dolomiteMargin ) { _ownerSetAllowableDebtMarketIds(_initialAllowableDebtMarketIds); _ownerSetAllowableCollateralMarketIds(_initialAllowableCollateralMarketIds); } function ownerSetAllowableDebtMarketIds( uint256[] calldata _newAllowableDebtMarketIds ) external virtual onlyDolomiteMarginOwner(msg.sender) { _ownerSetAllowableDebtMarketIds(_newAllowableDebtMarketIds); } function ownerSetAllowableCollateralMarketIds( uint256[] calldata _newAllowableCollateralMarketIds ) external virtual onlyDolomiteMarginOwner(msg.sender) { _ownerSetAllowableCollateralMarketIds(_newAllowableCollateralMarketIds); } function allowableDebtMarketIds() external view returns (uint256[] memory) { return _allowableDebtMarketIds; } function allowableCollateralMarketIds() external view returns (uint256[] memory) { return _allowableCollateralMarketIds; } // ================================================ // =============== Internal Methods =============== // ================================================ function _ownerSetAllowableDebtMarketIds( uint256[] memory _newAllowableDebtMarketIds ) internal virtual { uint256 len = _newAllowableDebtMarketIds.length; for (uint256 i; i < len; i++) { Require.that( !DOLOMITE_MARGIN().getMarketIsClosing(_newAllowableDebtMarketIds[i]), _FILE, "Market cannot be closing" ); } _allowableDebtMarketIds = _newAllowableDebtMarketIds; emit AllowableDebtMarketIdsSet(_newAllowableDebtMarketIds); } function _ownerSetAllowableCollateralMarketIds( uint256[] memory _newAllowableCollateralMarketIds ) internal virtual { _allowableCollateralMarketIds = _newAllowableCollateralMarketIds; emit AllowableCollateralMarketIdsSet(_newAllowableCollateralMarketIds); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { AccountBalanceLib } from "./AccountBalanceLib.sol"; import { ChainHelperLib } from "./ChainHelperLib.sol"; import { IExpiry } from "../interfaces/IExpiry.sol"; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; import { Require } from "../protocol/lib/Require.sol"; /** * @title AccountActionLib * @author Dolomite * * @notice Library contract that makes specific actions easy to call */ library AccountActionLib { // ============ Constants ============ bytes32 private constant _FILE = "AccountActionLib"; uint256 private constant _ALL = type(uint256).max; // =================================================================== // ========================= Write Functions ========================= // =================================================================== function deposit( IDolomiteMargin _dolomiteMargin, address _accountOwner, address _fromAccount, uint256 _toAccountNumber, uint256 _marketId, IDolomiteMargin.AssetAmount memory _amount ) internal { IDolomiteStructs.AccountInfo[] memory accounts = new IDolomiteStructs.AccountInfo[](1); accounts[0] = IDolomiteStructs.AccountInfo({ owner: _accountOwner, number: _toAccountNumber }); IDolomiteStructs.ActionArgs[] memory actions = new IDolomiteStructs.ActionArgs[](1); actions[0] = encodeDepositAction( /* _accountId = */ 0, _marketId, _amount, _fromAccount ); _dolomiteMargin.operate(accounts, actions); } /** * Withdraws `_marketId` from `_fromAccount` to `_toAccount` */ function withdraw( IDolomiteMargin _dolomiteMargin, address _accountOwner, uint256 _fromAccountNumber, address _toAccount, uint256 _marketId, IDolomiteStructs.AssetAmount memory _amount, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) internal { IDolomiteStructs.AccountInfo[] memory accounts = new IDolomiteStructs.AccountInfo[](1); accounts[0] = IDolomiteStructs.AccountInfo({ owner: _accountOwner, number: _fromAccountNumber }); IDolomiteStructs.ActionArgs[] memory actions = new IDolomiteStructs.ActionArgs[](1); actions[0] = encodeWithdrawalAction( /* _accountId = */ 0, _marketId, _amount, _toAccount ); _dolomiteMargin.operate(accounts, actions); if ( _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.Both || _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.From ) { AccountBalanceLib.verifyBalanceIsNonNegative( _dolomiteMargin, accounts[0].owner, _fromAccountNumber, _marketId ); } } /** * Transfers `_marketId` from `_fromAccount` to `_toAccount` */ function transfer( IDolomiteMargin _dolomiteMargin, address _fromAccountOwner, uint256 _fromAccountNumber, address _toAccountOwner, uint256 _toAccountNumber, uint256 _marketId, IDolomiteStructs.AssetDenomination _amountDenomination, uint256 _amount, AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag ) internal { IDolomiteStructs.AccountInfo[] memory accounts = new IDolomiteStructs.AccountInfo[](2); accounts[0] = IDolomiteStructs.AccountInfo({ owner: _fromAccountOwner, number: _fromAccountNumber }); accounts[1] = IDolomiteStructs.AccountInfo({ owner: _toAccountOwner, number: _toAccountNumber }); IDolomiteStructs.ActionArgs[] memory actions = new IDolomiteStructs.ActionArgs[](1); actions[0] = encodeTransferAction( /* _fromAccountId = */ 0, /* _toAccountId = */ 1, _marketId, _amountDenomination, _amount ); _dolomiteMargin.operate(accounts, actions); if ( _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.Both || _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.From ) { AccountBalanceLib.verifyBalanceIsNonNegative( _dolomiteMargin, _fromAccountOwner, _fromAccountNumber, _marketId ); } if ( _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.Both || _balanceCheckFlag == AccountBalanceLib.BalanceCheckFlag.To ) { AccountBalanceLib.verifyBalanceIsNonNegative( _dolomiteMargin, _toAccountOwner, _toAccountNumber, _marketId ); } } // =============================================================== // ========================= Pure Functions ====================== // =============================================================== function all() internal pure returns (uint256) { return _ALL; } function encodeCallAction( uint256 _accountId, address _callee, bytes memory _callData ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType : IDolomiteStructs.ActionType.Call, accountId : _accountId, amount : IDolomiteStructs.AssetAmount({ sign: false, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: 0 }), primaryMarketId : 0, secondaryMarketId : 0, otherAddress : _callee, otherAccountId : 0, data : _callData }); } function encodeDepositAction( uint256 _accountId, uint256 _marketId, IDolomiteStructs.AssetAmount memory _amount, address _fromAccount ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType: IDolomiteStructs.ActionType.Deposit, accountId: _accountId, amount: _amount, primaryMarketId: _marketId, secondaryMarketId: 0, otherAddress: _fromAccount, otherAccountId: 0, data: bytes("") }); } function encodeExpirationAction( IDolomiteStructs.AccountInfo memory _account, uint256 _accountId, uint256 _owedMarketId, address _expiry, uint256 _expiryTimeDelta ) internal pure returns (IDolomiteStructs.ActionArgs memory) { Require.that( _expiryTimeDelta == uint32(_expiryTimeDelta), _FILE, "Invalid expiry time delta" ); IExpiry.SetExpiryArg[] memory expiryArgs = new IExpiry.SetExpiryArg[](1); expiryArgs[0] = IExpiry.SetExpiryArg({ account : _account, marketId : _owedMarketId, timeDelta : uint32(_expiryTimeDelta), forceUpdate : true }); return encodeCallAction( _accountId, _expiry, abi.encode(IExpiry.CallFunctionType.SetExpiry, expiryArgs) ); } function encodeExpiryLiquidateAction( uint256 _solidAccountId, uint256 _liquidAccountId, uint256 _owedMarketId, uint256 _heldMarketId, address _expiryProxy, uint32 _expiry, bool _flipMarkets ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType: IDolomiteStructs.ActionType.Trade, accountId: _solidAccountId, amount: IDolomiteStructs.AssetAmount({ sign: false, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Target, value: 0 }), primaryMarketId: !_flipMarkets ? _owedMarketId : _heldMarketId, secondaryMarketId: !_flipMarkets ? _heldMarketId : _owedMarketId, otherAddress: _expiryProxy, otherAccountId: _liquidAccountId, data: abi.encode(_owedMarketId, _expiry) }); } function encodeLiquidateAction( uint256 _solidAccountId, uint256 _liquidAccountId, uint256 _owedMarketId, uint256 _heldMarketId, uint256 _owedWeiToLiquidate ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType: IDolomiteStructs.ActionType.Liquidate, accountId: _solidAccountId, amount: IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _owedWeiToLiquidate }), primaryMarketId: _owedMarketId, secondaryMarketId: _heldMarketId, otherAddress: address(0), otherAccountId: _liquidAccountId, data: new bytes(0) }); } function encodeExternalSellActionWithTarget( uint256 _fromAccountId, uint256 _primaryMarketId, uint256 _secondaryMarketId, address _trader, uint256 _targetAmountWei, uint256 _amountOutMinWei, bytes memory _orderData ) internal pure returns (IDolomiteStructs.ActionArgs memory) { IDolomiteStructs.AssetAmount memory assetAmount; assetAmount = IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Target, value: _targetAmountWei }); return IDolomiteStructs.ActionArgs({ actionType : IDolomiteStructs.ActionType.Sell, accountId : _fromAccountId, amount : assetAmount, primaryMarketId : _primaryMarketId, secondaryMarketId : _secondaryMarketId, otherAddress : _trader, otherAccountId : 0, data : abi.encode(_amountOutMinWei, _orderData) }); } function encodeExternalSellAction( uint256 _fromAccountId, uint256 _primaryMarketId, uint256 _secondaryMarketId, address _trader, uint256 _amountInWei, uint256 _amountOutMinWei, bytes memory _orderData ) internal pure returns (IDolomiteStructs.ActionArgs memory) { IDolomiteStructs.AssetAmount memory assetAmount; if (_amountInWei == _ALL) { assetAmount = IDolomiteStructs.AssetAmount({ sign: false, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Target, value: 0 }); } else { assetAmount = IDolomiteStructs.AssetAmount({ sign: false, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountInWei }); } return IDolomiteStructs.ActionArgs({ actionType : IDolomiteStructs.ActionType.Sell, accountId : _fromAccountId, amount : assetAmount, primaryMarketId : _primaryMarketId, secondaryMarketId : _secondaryMarketId, otherAddress : _trader, otherAccountId : 0, data : abi.encode(_amountOutMinWei, _orderData) }); } function encodeInternalTradeAction( uint256 _fromAccountId, uint256 _toAccountId, uint256 _primaryMarketId, uint256 _secondaryMarketId, address _traderAddress, uint256 _amountInWei, uint256 _chainId, bool _calculateAmountWithMakerAccount, bytes memory _orderData ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType: IDolomiteStructs.ActionType.Trade, accountId: _fromAccountId, amount: IDolomiteStructs.AssetAmount({ sign: true, denomination: IDolomiteStructs.AssetDenomination.Wei, ref: IDolomiteStructs.AssetReference.Delta, value: _amountInWei }), primaryMarketId: _primaryMarketId, secondaryMarketId: _secondaryMarketId, otherAddress: _traderAddress, otherAccountId: _toAccountId, data: ChainHelperLib.isArbitrum(_chainId) ? _orderData : abi.encode(_calculateAmountWithMakerAccount, _orderData) }); } function encodeTransferAction( uint256 _fromAccountId, uint256 _toAccountId, uint256 _marketId, IDolomiteStructs.AssetDenomination _amountDenomination, uint256 _amount ) internal pure returns (IDolomiteStructs.ActionArgs memory) { IDolomiteStructs.AssetAmount memory assetAmount; if (_amount == _ALL) { assetAmount = IDolomiteStructs.AssetAmount({ sign: false, denomination: _amountDenomination, ref: IDolomiteStructs.AssetReference.Target, value: 0 }); } else { assetAmount = IDolomiteStructs.AssetAmount({ sign: false, denomination: _amountDenomination, ref: IDolomiteStructs.AssetReference.Delta, value: _amount }); } return IDolomiteStructs.ActionArgs({ actionType : IDolomiteStructs.ActionType.Transfer, accountId : _fromAccountId, amount : assetAmount, primaryMarketId : _marketId, secondaryMarketId : 0, otherAddress : address(0), otherAccountId : _toAccountId, data : bytes("") }); } function encodeWithdrawalAction( uint256 _accountId, uint256 _marketId, IDolomiteStructs.AssetAmount memory _amount, address _toAccount ) internal pure returns (IDolomiteStructs.ActionArgs memory) { return IDolomiteStructs.ActionArgs({ actionType: IDolomiteStructs.ActionType.Withdraw, accountId: _accountId, amount: _amount, primaryMarketId: _marketId, secondaryMarketId: 0, otherAddress: _toAccount, otherAccountId: 0, data: bytes("") }); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; import { Require } from "../protocol/lib/Require.sol"; import { TypesLib } from "../protocol/lib/TypesLib.sol"; /** * @title AccountBalanceLib * @author Dolomite * * @notice Library contract that checks a user's balance after transaction to be non-negative */ library AccountBalanceLib { using TypesLib for IDolomiteStructs.Par; // ============ Types ============ /// Checks that either BOTH, FROM, or TO accounts all have non-negative balances enum BalanceCheckFlag { Both, From, To, None } // ============ Constants ============ bytes32 private constant _FILE = "AccountBalanceLib"; // ============ Functions ============ /** * Checks that the account's balance is non-negative. Reverts if the check fails */ function verifyBalanceIsNonNegative( IDolomiteMargin dolomiteMargin, address _accountOwner, uint256 _accountNumber, uint256 _marketId ) internal view { IDolomiteStructs.AccountInfo memory account = IDolomiteStructs.AccountInfo({ owner: _accountOwner, number: _accountNumber }); IDolomiteStructs.Par memory par = dolomiteMargin.getAccountPar(account, _marketId); Require.that( par.isPositive() || par.isZero(), _FILE, "account cannot go negative", _accountOwner, _accountNumber, _marketId ); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title ChainHelperLib * @author Dolomite * * @notice Library contract that discovers which chain we're on */ library ChainHelperLib { // ============ Constants ============ bytes32 private constant _FILE = "ChainHelperLib"; uint256 private constant _ARBITRUM_ONE = 42161; uint256 private constant _ARBITRUM_SEPOLIA = 421614; // ============ Functions ============ function isArbitrum(uint256 chainId) internal pure returns (bool) { return chainId == _ARBITRUM_ONE || chainId == _ARBITRUM_SEPOLIA; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { ChainHelperLib } from "./ChainHelperLib.sol"; import { IExpiry } from "../interfaces/IExpiry.sol"; import { IExpiryV2 } from "../interfaces/IExpiryV2.sol"; import { IDolomiteMargin } from "../protocol/interfaces/IDolomiteMargin.sol"; import { IDolomiteMarginV2 } from "../protocol/interfaces/IDolomiteMarginV2.sol"; import { IDolomiteStructs } from "../protocol/interfaces/IDolomiteStructs.sol"; /** * @title DolomiteMarginVersionWrapperLib * @author Dolomite * * @notice Library contract that discovers which chain we're on */ library DolomiteMarginVersionWrapperLib { using DolomiteMarginVersionWrapperLib for *; // ============ Constants ============ bytes32 private constant _FILE = "DolomiteMarginVersionWrapperLib"; // =========================================== // ============= Public Functions ============ // =========================================== function getVersionedLiquidationSpreadForPair( IDolomiteMargin _dolomiteMargin, uint256 _chainId, IDolomiteStructs.AccountInfo memory _liquidAccount, uint256 _heldMarketId, uint256 _owedMarketId ) internal view returns (IDolomiteStructs.Decimal memory) { if (ChainHelperLib.isArbitrum(_chainId)) { return _dolomiteMargin.getLiquidationSpreadForPair(_heldMarketId, _owedMarketId); } else { return dv2(_dolomiteMargin).getLiquidationSpreadForAccountAndPair( _liquidAccount, _heldMarketId, _owedMarketId ); } } function getVersionedSpreadAdjustedPrices( IExpiry _expiry, uint256 _chainId, IDolomiteStructs.AccountInfo memory _liquidAccount, uint256 _heldMarketId, uint256 _owedMarketId, uint32 _expiration ) internal view returns ( IDolomiteStructs.MonetaryPrice memory heldPrice, IDolomiteStructs.MonetaryPrice memory owedPriceAdj ) { if (ChainHelperLib.isArbitrum(_chainId)) { (heldPrice, owedPriceAdj) = _expiry.getSpreadAdjustedPrices(_heldMarketId, _owedMarketId, _expiration); } else { (heldPrice, owedPriceAdj) = ev2(_expiry).getLiquidationSpreadAdjustedPrices( _liquidAccount, _heldMarketId, _owedMarketId, _expiration ); } } // =========================================== // ============ Private Functions ============ // =========================================== function dv2(IDolomiteMargin _dolomiteMargin) private pure returns (IDolomiteMarginV2) { return IDolomiteMarginV2(address(_dolomiteMargin)); } function ev2(IExpiry _expiry) private pure returns (IExpiryV2) { return IExpiryV2(address(_expiry)); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; import { IDolomiteStructs } from "./IDolomiteStructs.sol"; /** * @title IDolomiteAccountRiskOverrideSetter * @author Dolomite * * @notice Interface that can be implemented by any contract that needs to implement risk overrides for an account. */ interface IDolomiteAccountRiskOverrideSetter { /** * @notice Gets the risk overrides for a given account owner. * * @param _accountOwner The owner of the account whose risk override should be retrieved. * @return marginRatioOverride The margin ratio override for this account. * @return liquidationSpreadOverride The liquidation spread override for this account. */ function getAccountRiskOverride( address _accountOwner ) external view returns ( IDolomiteStructs.Decimal memory marginRatioOverride, IDolomiteStructs.Decimal memory liquidationSpreadOverride ); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title IDolomiteInterestSetter * @author Dolomite * * @notice This interface defines the functions that for an interest setter that can be used to determine the interest * rate of a market. */ interface IDolomiteInterestSetter { // ============ Enum ============ enum InterestSetterType { None, Linear, DoubleExponential, Other } // ============ Structs ============ struct InterestRate { uint256 value; } // ============ Functions ============ /** * Get the interest rate of a token given some borrowed and supplied amounts * * @param token The address of the ERC20 token for the market * @param borrowWei The total borrowed token amount for the market * @param supplyWei The total supplied token amount for the market * @return The interest rate per second */ function getInterestRate( address token, uint256 borrowWei, uint256 supplyWei ) external view returns (InterestRate memory); function interestSetterType() external pure returns (InterestSetterType); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.sol"; import { IDolomiteMarginAdmin } from "./IDolomiteMarginAdmin.sol"; import { IDolomitePriceOracle } from "./IDolomitePriceOracle.sol"; /** * @title IDolomiteMargin * @author Dolomite * * @notice The interface for interacting with the main entry-point to DolomiteMargin */ interface IDolomiteMargin is IDolomiteMarginAdmin { // ================================================== // ================= Write Functions ================ // ================================================== /** * The main entry-point to DolomiteMargin that allows users and contracts to manage accounts. * Take one or more actions on one or more accounts. The msg.sender must be the owner or * operator of all accounts except for those being liquidated, vaporized, or traded with. * One call to operate() is considered a singular "operation". Account collateralization is * ensured only after the completion of the entire operation. * * @param accounts A list of all accounts that will be used in this operation. Cannot contain * duplicates. In each action, the relevant account will be referred-to by its * index in the list. * @param actions An ordered list of all actions that will be taken in this operation. The * actions will be processed in order. */ function operate( AccountInfo[] calldata accounts, ActionArgs[] calldata actions ) external; /** * Approves/disapproves any number of operators. An operator is an external address that has the * same permissions to manipulate an account as the owner of the account. Operators are simply * addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. * * Operators are also able to act as AutoTrader contracts on behalf of the account owner if the * operator is a smart contract and implements the IAutoTrader interface. * * @param args A list of OperatorArgs which have an address and a boolean. The boolean value * denotes whether to approve (true) or revoke approval (false) for that address. */ function setOperators( OperatorArg[] calldata args ) external; // ================================================== // ================= Read Functions ================ // ================================================== // ============ Getters for Markets ============ /** * Get the ERC20 token address for a market. * * @param token The token to query * @return The token's marketId if the token is valid */ function getMarketIdByTokenAddress( address token ) external view returns (uint256); /** * Get the ERC20 token address for a market. * * @param marketId The market to query * @return The token address */ function getMarketTokenAddress( uint256 marketId ) external view returns (address); /** * Return the maximum amount of the market that can be supplied on Dolomite. Always 0 or positive. * * @param marketId The market to query * @return The max amount of the market that can be supplied */ function getMarketMaxWei( uint256 marketId ) external view returns (Wei memory); /** * Return true if a particular market is in closing mode. Additional borrows cannot be taken * from a market that is closing. * * @param marketId The market to query * @return True if the market is closing */ function getMarketIsClosing( uint256 marketId ) external view returns (bool); /** * Get the price of the token for a market. * * @param marketId The market to query * @return The price of each atomic unit of the token */ function getMarketPrice( uint256 marketId ) external view returns (MonetaryPrice memory); /** * Get the total number of markets. * * @return The number of markets */ function getNumMarkets() external view returns (uint256); /** * Get the total principal amounts (borrowed and supplied) for a market. * * @param marketId The market to query * @return The total principal amounts */ function getMarketTotalPar( uint256 marketId ) external view returns (TotalPar memory); /** * Get the most recently cached interest index for a market. * * @param marketId The market to query * @return The most recent index */ function getMarketCachedIndex( uint256 marketId ) external view returns (InterestIndex memory); /** * Get the interest index for a market if it were to be updated right now. * * @param marketId The market to query * @return The estimated current index */ function getMarketCurrentIndex( uint256 marketId ) external view returns (InterestIndex memory); /** * Get the price oracle address for a market. * * @param marketId The market to query * @return The price oracle address */ function getMarketPriceOracle( uint256 marketId ) external view returns (IDolomitePriceOracle); /** * Get the interest-setter address for a market. * * @param marketId The market to query * @return The interest-setter address */ function getMarketInterestSetter( uint256 marketId ) external view returns (IDolomiteInterestSetter); /** * Get the margin premium for a market. A margin premium makes it so that any positions that * include the market require a higher collateralization to avoid being liquidated. * * @param marketId The market to query * @return The market's margin premium */ function getMarketMarginPremium( uint256 marketId ) external view returns (Decimal memory); /** * Get the spread premium for a market. A spread premium makes it so that any liquidations * that include the market have a higher spread than the global default. * * @param marketId The market to query * @return The market's spread premium */ function getMarketSpreadPremium( uint256 marketId ) external view returns (Decimal memory); /** * Return true if this market can be removed and its ID can be recycled and reused * * @param marketId The market to query * @return True if the market is recyclable */ function getMarketIsRecyclable( uint256 marketId ) external view returns (bool); /** * Gets the recyclable markets, up to `n` length. If `n` is greater than the length of the list, 0's are returned * for the empty slots. * * @param n The number of markets to get, bounded by the linked list being smaller than `n` * @return The list of recyclable markets, in the same order held by the linked list */ function getRecyclableMarkets( uint256 n ) external view returns (uint[] memory); /** * Get the current borrower interest rate for a market. * * @param marketId The market to query * @return The current interest rate */ function getMarketInterestRate( uint256 marketId ) external view returns (IDolomiteInterestSetter.InterestRate memory); /** * Get basic information about a particular market. * * @param marketId The market to query * @return A Market struct with the current state of the market */ function getMarket( uint256 marketId ) external view returns (Market memory); /** * Get comprehensive information about a particular market. * * @param marketId The market to query * @return A tuple containing the values: * - A Market struct with the current state of the market * - The current estimated interest index * - The current token price * - The current market interest rate */ function getMarketWithInfo( uint256 marketId ) external view returns ( Market memory, InterestIndex memory, MonetaryPrice memory, IDolomiteInterestSetter.InterestRate memory ); /** * Get the number of excess tokens for a market. The number of excess tokens is calculated by taking the current * number of tokens held in DolomiteMargin, adding the number of tokens owed to DolomiteMargin by borrowers, and * subtracting the number of tokens owed to suppliers by DolomiteMargin. * * @param marketId The market to query * @return The number of excess tokens */ function getNumExcessTokens( uint256 marketId ) external view returns (Wei memory); // ============ Getters for Accounts ============ /** * Get the principal value for a particular account and market. * * @param account The account to query * @param marketId The market to query * @return The principal value */ function getAccountPar( AccountInfo calldata account, uint256 marketId ) external view returns (Par memory); /** * Get the principal value for a particular account and market, with no check the market is valid. Meaning, markets * that don't exist return 0. * * @param account The account to query * @param marketId The market to query * @return The principal value */ function getAccountParNoMarketCheck( AccountInfo calldata account, uint256 marketId ) external view returns (Par memory); /** * Get the token balance for a particular account and market. * * @param account The account to query * @param marketId The market to query * @return The token amount */ function getAccountWei( AccountInfo calldata account, uint256 marketId ) external view returns (Wei memory); /** * Get the status of an account (Normal, Liquidating, or Vaporizing). * * @param account The account to query * @return The account's status */ function getAccountStatus( AccountInfo calldata account ) external view returns (AccountStatus); /** * Get a list of markets that have a non-zero balance for an account * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountMarketsWithBalances( AccountInfo calldata account ) external view returns (uint256[] memory); /** * Get the number of markets that have a non-zero balance for an account * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountNumberOfMarketsWithBalances( AccountInfo calldata account ) external view returns (uint256); /** * Get the marketId for an account's market with a non-zero balance at the given index * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountMarketWithBalanceAtIndex( AccountInfo calldata account, uint256 index ) external view returns (uint256); /** * Get the number of markets with which an account has a negative balance. * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountNumberOfMarketsWithDebt( AccountInfo calldata account ) external view returns (uint256); /** * Get the total supplied and total borrowed value of an account. * * @param account The account to query * @return The following values: * - The supplied value of the account * - The borrowed value of the account */ function getAccountValues( AccountInfo calldata account ) external view returns (MonetaryValue memory, MonetaryValue memory); /** * Get the total supplied and total borrowed values of an account adjusted by the marginPremium * of each market. Supplied values are divided by (1 + marginPremium) for each market and * borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these * adjusted values gives the margin-ratio of the account which will be compared to the global * margin-ratio when determining if the account can be liquidated. * * @param account The account to query * @return The following values: * - The supplied value of the account (adjusted for marginPremium) * - The borrowed value of the account (adjusted for marginPremium) */ function getAdjustedAccountValues( AccountInfo calldata account ) external view returns (MonetaryValue memory, MonetaryValue memory); /** * Get an account's summary for each market. * * @param account The account to query * @return The following values: * - The market IDs for each market * - The ERC20 token address for each market * - The account's principal value for each market * - The account's (supplied or borrowed) number of tokens for each market */ function getAccountBalances( AccountInfo calldata account ) external view returns (uint[] memory, address[] memory, Par[] memory, Wei[] memory); // ============ Getters for Account Permissions ============ /** * Return true if a particular address is approved as an operator for an owner's accounts. * Approved operators can act on the accounts of the owner as if it were the operator's own. * * @param owner The owner of the accounts * @param operator The possible operator * @return True if operator is approved for owner's accounts */ function getIsLocalOperator( address owner, address operator ) external view returns (bool); /** * Return true if a particular address is approved as a global operator. Such an address can * act on any account as if it were the operator's own. * * @param operator The address to query * @return True if operator is a global operator */ function getIsGlobalOperator( address operator ) external view returns (bool); /** * Checks if the autoTrader can only be called invoked by a global operator * * @param autoTrader The trader that should be checked for special call privileges. */ function getIsAutoTraderSpecial(address autoTrader) external view returns (bool); /** * @return The address that owns the DolomiteMargin protocol */ function owner() external view returns (address); // ============ Getters for Risk Params ============ /** * Get the global minimum margin-ratio that every position must maintain to prevent being * liquidated. * * @return The global margin-ratio */ function getMarginRatio() external view returns (Decimal memory); /** * Get the global liquidation spread. This is the spread between oracle prices that incentivizes * the liquidation of risky positions. * * @return The global liquidation spread */ function getLiquidationSpread() external view returns (Decimal memory); /** * Get the adjusted liquidation spread for some market pair. This is equal to the global * liquidation spread multiplied by (1 + spreadPremium) for each of the two markets. * * @param heldMarketId The market for which the account has collateral * @param owedMarketId The market for which the account has borrowed tokens * @return The adjusted liquidation spread */ function getLiquidationSpreadForPair( uint256 heldMarketId, uint256 owedMarketId ) external view returns (Decimal memory); /** * Get the global earnings-rate variable that determines what percentage of the interest paid * by borrowers gets passed-on to suppliers. * * @return The global earnings rate */ function getEarningsRate() external view returns (Decimal memory); /** * Get the global minimum-borrow value which is the minimum value of any new borrow on DolomiteMargin. * * @return The global minimum borrow value */ function getMinBorrowedValue() external view returns (MonetaryValue memory); /** * Get all risk parameters in a single struct. * * @return All global risk parameters */ function getRiskParams() external view returns (RiskParams memory); /** * Get all risk parameter limits in a single struct. These are the maximum limits at which the * risk parameters can be set by the admin of DolomiteMargin. * * @return All global risk parameter limits */ function getRiskLimits() external view returns (RiskLimits memory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.sol"; import { IDolomitePriceOracle } from "./IDolomitePriceOracle.sol"; import { IDolomiteStructs } from "./IDolomiteStructs.sol"; /** * @title IDolomiteMarginAdmin * @author Dolomite * * @notice This interface defines the functions that can be called by the owner of DolomiteMargin. */ interface IDolomiteMarginAdmin is IDolomiteStructs { // ============ Token Functions ============ /** * Withdraw an ERC20 token for which there is an associated market. Only excess tokens can be withdrawn. The number * of excess tokens is calculated by taking the current number of tokens held in DolomiteMargin, adding the number * of tokens owed to DolomiteMargin by borrowers, and subtracting the number of tokens owed to suppliers by * DolomiteMargin. */ function ownerWithdrawExcessTokens( uint256 marketId, address recipient ) external returns (uint256); /** * Withdraw an ERC20 token for which there is no associated market. */ function ownerWithdrawUnsupportedTokens( address token, address recipient ) external returns (uint256); // ============ Market Functions ============ /** * Sets the number of non-zero balances an account may have within the same `accountIndex`. This ensures a user * cannot DOS the system by filling their account with non-zero balances (which linearly increases gas costs when * checking collateralization) and disallowing themselves to close the position, because the number of gas units * needed to process their transaction exceed the block's gas limit. In turn, this would prevent the user from also * being liquidated, causing the all of the capital to be "stuck" in the position. * * Lowering this number does not "freeze" user accounts that have more than the new limit of balances, because this * variable is enforced by checking the users number of non-zero balances against the max or if it sizes down before * each transaction finishes. */ function ownerSetAccountMaxNumberOfMarketsWithBalances( uint256 accountMaxNumberOfMarketsWithBalances ) external; /** * Add a new market to DolomiteMargin. Must be for a previously-unsupported ERC20 token. */ function ownerAddMarket( address token, IDolomitePriceOracle priceOracle, IDolomiteInterestSetter interestSetter, Decimal calldata marginPremium, Decimal calldata spreadPremium, uint256 maxWei, bool isClosing, bool isRecyclable ) external; /** * Removes a market from DolomiteMargin, sends any remaining tokens in this contract to `salvager` and invokes the * recyclable callback */ function ownerRemoveMarkets( uint[] calldata marketIds, address salvager ) external; /** * Set (or unset) the status of a market to "closing". The borrowedValue of a market cannot increase while its * status is "closing". */ function ownerSetIsClosing( uint256 marketId, bool isClosing ) external; /** * Set the price oracle for a market. */ function ownerSetPriceOracle( uint256 marketId, IDolomitePriceOracle priceOracle ) external; /** * Set the interest-setter for a market. */ function ownerSetInterestSetter( uint256 marketId, IDolomiteInterestSetter interestSetter ) external; /** * Set a premium on the minimum margin-ratio for a market. This makes it so that any positions that include this * market require a higher collateralization to avoid being liquidated. */ function ownerSetMarginPremium( uint256 marketId, Decimal calldata marginPremium ) external; function ownerSetMaxWei( uint256 marketId, uint256 maxWei ) external; /** * Set a premium on the liquidation spread for a market. This makes it so that any liquidations that include this * market have a higher spread than the global default. */ function ownerSetSpreadPremium( uint256 marketId, Decimal calldata spreadPremium ) external; // ============ Risk Functions ============ /** * Set the global minimum margin-ratio that every position must maintain to prevent being liquidated. */ function ownerSetMarginRatio( Decimal calldata ratio ) external; /** * Set the global liquidation spread. This is the spread between oracle prices that incentivizes the liquidation of * risky positions. */ function ownerSetLiquidationSpread( Decimal calldata spread ) external; /** * Set the global earnings-rate variable that determines what percentage of the interest paid by borrowers gets * passed-on to suppliers. */ function ownerSetEarningsRate( Decimal calldata earningsRate ) external; /** * Set the global minimum-borrow value which is the minimum value of any new borrow on DolomiteMargin. */ function ownerSetMinBorrowedValue( MonetaryValue calldata minBorrowedValue ) external; // ============ Global Operator Functions ============ /** * Approve (or disapprove) an address that is permissioned to be an operator for all accounts in DolomiteMargin. * Intended only to approve smart-contracts. */ function ownerSetGlobalOperator( address operator, bool approved ) external; /** * Approve (or disapprove) an auto trader that can only be called by a global operator. IE for expirations */ function ownerSetAutoTraderSpecial( address autoTrader, bool special ) external; }
// SPDX-License-Identifier: Apache-2.0 /* Copyright 2019 dYdX Trading Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; /** * @title IDolomiteMarginExchangeWrapper * @author dYdX * * @notice Interface that Exchange Wrappers for DolomiteMargin must implement in order to trade ERC20 tokens with * external protocols. */ interface IDolomiteMarginExchangeWrapper { // ============ Public Functions ============ /** * Exchange some amount of inputToken for outputToken. * * @param _tradeOriginator Address of the initiator of the trade (however, this value cannot always be trusted as * it is set at the discretion of the msg.sender) * @param _receiver Address to set allowance on once the trade has completed * @param _outputToken The token to receive (target asset; IE path[path.length - 1]) * @param _inputToken The token to pay (originator asset; IE path[0]) * @param _inputAmount Amount of `inputToken` being paid to this wrapper * @param _orderData Arbitrary bytes data for any information to pass to the exchange * @return The amount of outputToken to be received by DolomiteMargin */ function exchange( address _tradeOriginator, address _receiver, address _outputToken, address _inputToken, uint256 _inputAmount, bytes calldata _orderData ) external returns (uint256); /** * Get amount of `inputToken` required to buy a certain amount of `outputToken` for a given trade. * Should match the `inputToken` amount used in exchangeForAmount. If the order cannot provide * exactly `_desiredOutputToken`, then it must return the price to buy the minimum amount greater * than `_desiredOutputToken` * * @param _inputToken The token to pay to this contract (originator asset; IE path[0]) * @param _outputToken The token to receive by DolomiteMargin (target asset; IE path[path.length - 1]) * @param _desiredInputAmount Amount of `_inputToken` requested * @param _orderData Arbitrary bytes data for any information to pass to the exchange * @return Amount of `_inputToken` the needed to complete the exchange */ function getExchangeCost( address _inputToken, address _outputToken, uint256 _desiredInputAmount, bytes calldata _orderData ) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteAccountRiskOverrideSetter } from "./IDolomiteAccountRiskOverrideSetter.sol"; import { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.sol"; import { IDolomiteMarginV2Admin } from "./IDolomiteMarginV2Admin.sol"; import { IDolomiteOracleSentinel } from "./IDolomiteOracleSentinel.sol"; import { IDolomitePriceOracle } from "./IDolomitePriceOracle.sol"; /** * @title IDolomiteMarginV2 * @author Dolomite * * @notice The interface for interacting with the main entry-point to DolomiteMargin */ interface IDolomiteMarginV2 is IDolomiteMarginV2Admin { // ================================================== // ================= Write Functions ================ // ================================================== /** * The main entry-point to DolomiteMargin that allows users and contracts to manage accounts. * Take one or more actions on one or more accounts. The msg.sender must be the owner or * operator of all accounts except for those being liquidated, vaporized, or traded with. * One call to operate() is considered a singular "operation". Account collateralization is * ensured only after the completion of the entire operation. * * @param accounts A list of all accounts that will be used in this operation. Cannot contain * duplicates. In each action, the relevant account will be referred-to by its * index in the list. * @param actions An ordered list of all actions that will be taken in this operation. The * actions will be processed in order. */ function operate( AccountInfo[] calldata accounts, ActionArgs[] calldata actions ) external; /** * Approves/disapproves any number of operators. An operator is an external address that has the * same permissions to manipulate an account as the owner of the account. Operators are simply * addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts. * * Operators are also able to act as AutoTrader contracts on behalf of the account owner if the * operator is a smart contract and implements the IAutoTrader interface. * * @param args A list of OperatorArgs which have an address and a boolean. The boolean value * denotes whether to approve (true) or revoke approval (false) for that address. */ function setOperators( OperatorArg[] calldata args ) external; // ================================================== // ================= Read Functions ================ // ================================================== // ============ Getters for Markets ============ /** * Get the ERC20 token address for a market. * * @param token The token to query * @return The token's marketId if the token is valid */ function getMarketIdByTokenAddress( address token ) external view returns (uint256); /** * Get the ERC20 token address for a market. * * @param marketId The market to query * @return The token address */ function getMarketTokenAddress( uint256 marketId ) external view returns (address); /** * Return the maximum amount of the market that can be supplied on Dolomite. Always 0 or positive. * * @param marketId The market to query * @return The max amount of the market that can be supplied */ function getMarketMaxWei( uint256 marketId ) external view returns (Wei memory); /** * Get the max supply amount for a a market. * * @param marketId The market to query * @return The market's max supply amount. Always 0 or positive. */ function getMarketMaxSupplyWei( uint256 marketId ) external view returns (Wei memory); /** * Get the max borrow amount for a a market. * * @param marketId The market to query * @return The market's max borrow amount. Always negative or 0. */ function getMarketMaxBorrowWei( uint256 marketId ) external view returns (Wei memory); /** * Get the market-specific earnings that determines what percentage of the interest paid by borrowers gets passed-on * to suppliers. If the value is set to 0, the override is not set. * * @return The market-specific earnings rate */ function getMarketEarningsRateOverride( uint256 marketId ) external view returns (Decimal memory); /** * Get the current borrow interest rate for a market. The value is denominated as interest paid per second, and the * number is scaled to have 18 decimals. To get APR, multiply the number returned by 31536000 (seconds in a year). * * @param marketId The market to query * @return The current borrow interest rate */ function getMarketBorrowInterestRatePerSecond( uint256 marketId ) external view returns (IDolomiteInterestSetter.InterestRate memory); /** * Return true if a particular market is in closing mode. Additional borrows cannot be taken * from a market that is closing. * * @param marketId The market to query * @return True if the market is closing */ function getMarketIsClosing( uint256 marketId ) external view returns (bool); /** * Get the price of the token for a market. * * @param marketId The market to query * @return The price of each atomic unit of the token */ function getMarketPrice( uint256 marketId ) external view returns (MonetaryPrice memory); /** * Get the total number of markets. * * @return The number of markets */ function getNumMarkets() external view returns (uint256); /** * Get the total principal amounts (borrowed and supplied) for a market. * * @param marketId The market to query * @return The total principal amounts */ function getMarketTotalPar( uint256 marketId ) external view returns (TotalPar memory); /** * Get the total principal amounts (borrowed and supplied) for a market. * * @param marketId The market to query * @return The total principal amounts */ function getMarketTotalWei( uint256 marketId ) external view returns (TotalWei memory); /** * Get the most recently cached interest index for a market. * * @param marketId The market to query * @return The most recent index */ function getMarketCachedIndex( uint256 marketId ) external view returns (InterestIndex memory); /** * Get the interest index for a market if it were to be updated right now. * * @param marketId The market to query * @return The estimated current index */ function getMarketCurrentIndex( uint256 marketId ) external view returns (InterestIndex memory); /** * Get the price oracle address for a market. * * @param marketId The market to query * @return The price oracle address */ function getMarketPriceOracle( uint256 marketId ) external view returns (IDolomitePriceOracle); /** * Get the interest-setter address for a market. * * @param marketId The market to query * @return The interest-setter address */ function getMarketInterestSetter( uint256 marketId ) external view returns (IDolomiteInterestSetter); /** * Get the margin premium for a market. A margin premium makes it so that any positions that * include the market require a higher collateralization to avoid being liquidated. * * @param marketId The market to query * @return The market's margin premium */ function getMarketMarginPremium( uint256 marketId ) external view returns (Decimal memory); /** * Get the spread premium for a market. A spread premium makes it so that any liquidations * that include the market have a higher spread than the global default. * * @param marketId The market to query * @return The market's spread premium */ function getMarketLiquidationSpreadPremium( uint256 marketId ) external view returns (Decimal memory); /** * Get the spread premium for a market. A spread premium makes it so that any liquidations * that include the market have a higher spread than the global default. * * @param marketId The market to query * @return The market's spread premium */ function getMarketSpreadPremium( uint256 marketId ) external view returns (Decimal memory); /** * Get the current borrower interest rate for a market. * * @param marketId The market to query * @return The current interest rate */ function getMarketInterestRate( uint256 marketId ) external view returns (IDolomiteInterestSetter.InterestRate memory); /** * Get the current borrow interest rate for a market. The value is denominated as interest paid per year, and the * number is scaled to have 18 decimals. * * @param marketId The market to query * @return The current supply interest rate */ function getMarketBorrowInterestRateApr( uint256 marketId ) external view returns (IDolomiteInterestSetter.InterestRate memory); /** * Get the current supply interest rate for a market. * * @param marketId The market to query * @return The current supply interest rate */ function getMarketSupplyInterestRateApr( uint256 marketId ) external view returns (IDolomiteInterestSetter.InterestRate memory); /** * Get basic information about a particular market. * * @param marketId The market to query * @return A Market struct with the current state of the market */ function getMarket( uint256 marketId ) external view returns (MarketV2 memory); /** * Get comprehensive information about a particular market. * * @param marketId The market to query * @return A tuple containing the values: * - A Market struct with the current state of the market * - The current estimated interest index * - The current token price * - The current market interest rate */ function getMarketWithInfo( uint256 marketId ) external view returns ( MarketV2 memory, InterestIndex memory, MonetaryPrice memory, IDolomiteInterestSetter.InterestRate memory ); /** * Get the number of excess tokens for a market. The number of excess tokens is calculated by taking the current * number of tokens held in DolomiteMargin, adding the number of tokens owed to DolomiteMargin by borrowers, and * subtracting the number of tokens owed to suppliers by DolomiteMargin. * * @param marketId The market to query * @return The number of excess tokens */ function getNumExcessTokens( uint256 marketId ) external view returns (Wei memory); // ============ Getters for Accounts ============ /** * Get the principal value for a particular account and market. * * @param account The account to query * @param marketId The market to query * @return The principal value */ function getAccountPar( AccountInfo calldata account, uint256 marketId ) external view returns (Par memory); /** * Get the principal value for a particular account and market, with no check the market is valid. Meaning, markets * that don't exist return 0. * * @param account The account to query * @param marketId The market to query * @return The principal value */ function getAccountParNoMarketCheck( AccountInfo calldata account, uint256 marketId ) external view returns (Par memory); /** * Get the token balance for a particular account and market. * * @param account The account to query * @param marketId The market to query * @return The token amount */ function getAccountWei( AccountInfo calldata account, uint256 marketId ) external view returns (Wei memory); /** * Get the status of an account (Normal, Liquidating, or Vaporizing). * * @param account The account to query * @return The account's status */ function getAccountStatus( AccountInfo calldata account ) external view returns (AccountStatus); /** * Get a list of markets that have a non-zero balance for an account * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountMarketsWithBalances( AccountInfo calldata account ) external view returns (uint256[] memory); /** * Get the number of markets that have a non-zero balance for an account * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountNumberOfMarketsWithBalances( AccountInfo calldata account ) external view returns (uint256); /** * Get the marketId for an account's market with a non-zero balance at the given index * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountMarketWithBalanceAtIndex( AccountInfo calldata account, uint256 index ) external view returns (uint256); /** * Get the number of markets with which an account has a negative balance. * * @param account The account to query * @return The non-sorted marketIds with non-zero balance for the account. */ function getAccountNumberOfMarketsWithDebt( AccountInfo calldata account ) external view returns (uint256); /** * Get the total supplied and total borrowed value of an account. * * @param account The account to query * @return The following values: * - The supplied value of the account * - The borrowed value of the account */ function getAccountValues( AccountInfo calldata account ) external view returns (MonetaryValue memory, MonetaryValue memory); /** * Get the total supplied and total borrowed values of an account adjusted by the marginPremium * of each market. Supplied values are divided by (1 + marginPremium) for each market and * borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these * adjusted values gives the margin-ratio of the account which will be compared to the global * margin-ratio when determining if the account can be liquidated. * * @param account The account to query * @return The following values: * - The supplied value of the account (adjusted for marginPremium) * - The borrowed value of the account (adjusted for marginPremium) */ function getAdjustedAccountValues( AccountInfo calldata account ) external view returns (MonetaryValue memory, MonetaryValue memory); /** * Get an account's summary for each market. * * @param account The account to query * @return The following values: * - The market IDs for each market * - The ERC20 token address for each market * - The account's principal value for each market * - The account's (supplied or borrowed) number of tokens for each market */ function getAccountBalances( AccountInfo calldata account ) external view returns (uint[] memory, address[] memory, Par[] memory, Wei[] memory); // ============ Getters for Account Permissions ============ /** * Return true if a particular address is approved as an operator for an owner's accounts. * Approved operators can act on the accounts of the owner as if it were the operator's own. * * @param owner The owner of the accounts * @param operator The possible operator * @return True if operator is approved for owner's accounts */ function getIsLocalOperator( address owner, address operator ) external view returns (bool); /** * Return true if a particular address is approved as a global operator. Such an address can * act on any account as if it were the operator's own. * * @param operator The address to query * @return True if operator is a global operator */ function getIsGlobalOperator( address operator ) external view returns (bool); /** * Checks if the autoTrader can only be called invoked by a global operator * * @param autoTrader The trader that should be checked for special call privileges. */ function getIsAutoTraderSpecial(address autoTrader) external view returns (bool); /** * @return The address that owns the DolomiteMargin protocol */ function owner() external view returns (address); // ============ Getters for Risk Params ============ /** * Get the global minimum margin-ratio that every position must maintain to prevent being * liquidated. * * @return The global margin-ratio */ function getMarginRatio() external view returns (Decimal memory); /** * Get the global minimum margin-ratio that every position must maintain to prevent being * liquidated. * * @param account The account whose margin ratio is being queried. This is used to determine if there is an * override that supersedes the global minimum. * @return The margin ratio for this account */ function getMarginRatioForAccount(AccountInfo calldata account) external view returns (Decimal memory); /** * Get the global liquidation spread. This is the spread between oracle prices that incentivizes * the liquidation of risky positions. * * @return The global liquidation spread */ function getLiquidationSpread() external view returns (Decimal memory); /** * Get the adjusted liquidation spread for some market pair. This is equal to the global * liquidation spread multiplied by (1 + spreadPremium) for each of the two markets. * * @param heldMarketId The market for which the account has collateral * @param owedMarketId The market for which the account has borrowed tokens * @return The adjusted liquidation spread */ function getLiquidationSpreadForPair( uint256 heldMarketId, uint256 owedMarketId ) external view returns (Decimal memory); /** * Get the adjusted liquidation spread for some market pair. This is equal to the global liquidation spread * multiplied by (1 + spreadPremium) for each of the two markets. * * If the pair is in e-mode and has a liquidation spread override, then the override is used instead. * * @param account The account whose liquidation spread is being queried. This is used to determine if there is * an override in place. * @param heldMarketId The market for which the account has collateral * @param owedMarketId The market for which the account has borrowed tokens * @return The adjusted liquidation spread */ function getLiquidationSpreadForAccountAndPair( AccountInfo calldata account, uint256 heldMarketId, uint256 owedMarketId ) external view returns (Decimal memory); /** * Get the global earnings-rate variable that determines what percentage of the interest paid * by borrowers gets passed-on to suppliers. * * @return The global earnings rate */ function getEarningsRate() external view returns (Decimal memory); /** * Get the global minimum-borrow value which is the minimum value of any new borrow on DolomiteMargin. * * @return The global minimum borrow value */ function getMinBorrowedValue() external view returns (MonetaryValue memory); /** * Get the maximum number of assets an account owner can hold in an account number. * * @return The maximum number of assets an account owner can hold in an account number. */ function getAccountMaxNumberOfMarketsWithBalances() external view returns (uint256); /** * Gets the oracle sentinel, which is responsible for checking if the Blockchain or L2 is alive, if liquidations * should be processed, and if markets should are in size-down only mode. * * @return The oracle sentinel for DolomiteMargin */ function getOracleSentinel() external view returns (IDolomiteOracleSentinel); /** * @return True if borrowing is globally allowed according to the Oracle Sentinel or false if it is not */ function getIsBorrowAllowed() external view returns (bool); /** * @return True if liquidations are globally allowed according to the Oracle Sentinel or false if they are not */ function getIsLiquidationAllowed() external view returns (bool); /** * @return The gas limit used for making callbacks via `IExternalCallback::onInternalBalanceChange` to smart * contract wallets. */ function getCallbackGasLimit() external view returns (uint256); /** * Get the account risk override getter for global use. This contract enables e-mode based on the assets held in a * position. * * @return The contract that contains risk override information for any account that does NOT have an account- * specific override. */ function getDefaultAccountRiskOverrideSetter() external view returns (IDolomiteAccountRiskOverrideSetter); /** * Get the account risk override getter for an account owner. This contract enables e-mode for certain isolation * mode vaults. * * @param accountOwner The address of the account to check if there is a margin ratio override. * @return The contract that contains risk override information for this account. */ function getAccountRiskOverrideSetterByAccountOwner( address accountOwner ) external view returns (IDolomiteAccountRiskOverrideSetter); /** * Get the margin ratio override for an account owner. Used to enable e-mode for certain isolation mode vaults. * * @param account The account to check if there is a risk override. * @return marginRatioOverride The margin ratio override for an account owner. Defaults to 0 if there's no * override in place. * @return liquidationSpreadOverride The margin ratio override for an account owner. Defaults to 0 if there's no * override in place. */ function getAccountRiskOverrideByAccount( AccountInfo calldata account ) external view returns (Decimal memory marginRatioOverride, Decimal memory liquidationSpreadOverride); /** * Get the margin ratio override for an account. Used to enable e-mode for certain accounts/positions. * * @param account The account to check if there is a margin ratio override. * @return The margin ratio override for an account owner. Defaults to 0 if there's no override in place. */ function getMarginRatioOverrideByAccount(AccountInfo calldata account) external view returns (Decimal memory); /** * Get the liquidation reward override for an account owner. Used to enable e-mode for certain isolation mode * vaults. * * @param account The account to check if there is a liquidation spread override. * @return The liquidation spread override for an account owner. Defaults to 0 if there's no override in place. */ function getLiquidationSpreadOverrideByAccount( AccountInfo calldata account ) external view returns (Decimal memory); /** * Get all risk parameter limits in a single struct. These are the maximum limits at which the * risk parameters can be set by the admin of DolomiteMargin. * * @return All global risk parameter limits */ function getRiskLimits() external view returns (RiskLimitsV2 memory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteAccountRiskOverrideSetter } from "./IDolomiteAccountRiskOverrideSetter.sol"; import { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.sol"; import { IDolomiteOracleSentinel } from "./IDolomiteOracleSentinel.sol"; import { IDolomitePriceOracle } from "./IDolomitePriceOracle.sol"; import { IDolomiteStructs } from "./IDolomiteStructs.sol"; /** * @title IDolomiteMarginV2Admin * @author Dolomite * * @notice This interface defines the functions that can be called by the owner of DolomiteMargin. */ interface IDolomiteMarginV2Admin is IDolomiteStructs { // ============ Token Functions ============ /** * Withdraw an ERC20 token for which there is an associated market. Only excess tokens can be withdrawn. The number * of excess tokens is calculated by taking the current number of tokens held in DolomiteMargin, adding the number * of tokens owed to DolomiteMargin by borrowers, and subtracting the number of tokens owed to suppliers by * DolomiteMargin. */ function ownerWithdrawExcessTokens( uint256 marketId, address recipient ) external returns (uint256); /** * Withdraw an ERC20 token for which there is no associated market. */ function ownerWithdrawUnsupportedTokens( address token, address recipient ) external returns (uint256); // ============ Market Functions ============ /** * Add a new market to DolomiteMargin. Must be for a previously-unsupported ERC20 token. */ function ownerAddMarket( address token, IDolomitePriceOracle priceOracle, IDolomiteInterestSetter interestSetter, Decimal calldata marginPremium, Decimal calldata spreadPremium, uint256 maxSupplyWei, uint256 maxBorrowWei, Decimal calldata earningsRateOverride, bool isClosing ) external; /** * Set (or unset) the status of a market to "closing". The borrowedValue of a market cannot increase while its * status is "closing". */ function ownerSetIsClosing( uint256 marketId, bool isClosing ) external; /** * Set the price oracle for a market. */ function ownerSetPriceOracle( uint256 marketId, IDolomitePriceOracle priceOracle ) external; /** * Set the interest-setter for a market. */ function ownerSetInterestSetter( uint256 marketId, IDolomiteInterestSetter interestSetter ) external; /** * Set a premium on the minimum margin-ratio for a market. This makes it so that any positions that include this * market require a higher collateralization to avoid being liquidated. */ function ownerSetMarginPremium( uint256 marketId, Decimal calldata marginPremium ) external; /** * Set a premium on the liquidation spread for a market. This makes it so that any liquidations that include this * market have a higher spread than the global default. */ function ownerSetLiquidationSpreadPremium( uint256 marketId, Decimal calldata liquidationSpreadPremium ) external; /** * Sets the maximum supply wei for a given `marketId`. */ function ownerSetMaxSupplyWei( uint256 marketId, uint256 maxSupplyWei ) external; /** * Sets the maximum borrow wei for a given `marketId`. */ function ownerSetMaxBorrowWei( uint256 marketId, uint256 maxBorrowWei ) external; /** * Sets the earnings rate override for a given `marketId`. Set it to 0 unset the override. */ function ownerSetEarningsRateOverride( uint256 marketId, Decimal calldata earningsRateOverride ) external; // ============ Risk Functions ============ /** * Set the global minimum margin-ratio that every position must maintain to prevent being liquidated. */ function ownerSetMarginRatio( Decimal calldata ratio ) external; /** * Set the global liquidation spread. This is the spread between oracle prices that incentivizes the liquidation of * risky positions. */ function ownerSetLiquidationSpread( Decimal calldata spread ) external; /** * Set the global earnings-rate variable that determines what percentage of the interest paid by borrowers gets * passed-on to suppliers. */ function ownerSetEarningsRate( Decimal calldata earningsRate ) external; /** * Set the global minimum-borrow value which is the minimum value of any new borrow on DolomiteMargin. */ function ownerSetMinBorrowedValue( MonetaryValue calldata minBorrowedValue ) external; /** * Sets the number of non-zero balances an account may have within the same `accountIndex`. This ensures a user * cannot DOS the system by filling their account with non-zero balances (which linearly increases gas costs when * checking collateralization) and disallowing themselves to close the position, because the number of gas units * needed to process their transaction exceed the block's gas limit. In turn, this would prevent the user from also * being liquidated, causing the all of the capital to be "stuck" in the position. * * Lowering this number does not "freeze" user accounts that have more than the new limit of balances, because this * variable is enforced by checking the users number of non-zero balances against the max or if it sizes down before * each transaction finishes. */ function ownerSetAccountMaxNumberOfMarketsWithBalances( uint256 accountMaxNumberOfMarketsWithBalances ) external; /** * Sets the current oracle sentinel used to report if borrowing and liquidations are enabled. */ function ownerSetOracleSentinel( IDolomiteOracleSentinel oracleSentinel ) external; /** * Sets the gas limit that's passed to any of the callback functions */ function ownerSetCallbackGasLimit( uint256 callbackGasLimit ) external; /** * Sets the account risk override setter by default for any account */ function ownerSetDefaultAccountRiskOverride( IDolomiteAccountRiskOverrideSetter accountRiskOverrideSetter ) external; /** * Sets the account risk override setter for a given wallet */ function ownerSetAccountRiskOverride( address accountOwner, IDolomiteAccountRiskOverrideSetter accountRiskOverrideSetter ) external; // ============ Global Operator Functions ============ /** * Approve (or disapprove) an address that is permissioned to be an operator for all accounts in DolomiteMargin. * Intended only to approve smart-contracts. */ function ownerSetGlobalOperator( address operator, bool approved ) external; /** * Approve (or disapprove) an auto trader that can only be called by a global operator. IE for expirations */ function ownerSetAutoTraderSpecial( address autoTrader, bool special ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; /** * @title IDolomiteOracleSentinel * @author Dolomite * * Interface that Dolomite pings to check if the Blockchain or L2 is alive, if liquidations should be processed, and if * markets should are in size-down only mode. */ interface IDolomiteOracleSentinel { // ============ Events ============ event GracePeriodSet( uint256 gracePeriod ); // ============ Functions ============ /** * @dev Allows the owner to set the grace period duration, which specifies how long the system will disallow * liquidations after sequencer is back online. Only callable by the owner. * * @param _gracePeriod The new duration of the grace period */ function ownerSetGracePeriod( uint256 _gracePeriod ) external; /** * @return True if new borrows should be allowed, false otherwise */ function isBorrowAllowed() external view returns (bool); /** * @return True if liquidations should be allowed, false otherwise */ function isLiquidationAllowed() external view returns (bool); /** * @return The duration between when the feed comes back online and when the system will allow liquidations to be * processed normally */ function gracePeriod() external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteStructs } from "./IDolomiteStructs.sol"; /** * @title IDolomitePriceOracle * @author Dolomite * * @notice Interface that Price Oracles for DolomiteMargin must implement in order to report prices. */ interface IDolomitePriceOracle { // ============ Public Functions ============ /** * Get the price of a token * * @param token The ERC20 token address of the market * @return The USD price of a base unit of the token, then multiplied by 10^(36 - decimals). * So a USD-stable coin with 6 decimal places would return `price * 10^30`. * This is the price of the base unit rather than the price of a "human-readable" * token amount. Every ERC20 may have a different number of decimals. */ function getPrice( address token ) external view returns (IDolomiteStructs.MonetaryPrice memory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IDolomiteAccountRiskOverrideSetter } from "./IDolomiteAccountRiskOverrideSetter.sol"; import { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.sol"; import { IDolomiteOracleSentinel } from "./IDolomiteOracleSentinel.sol"; import { IDolomitePriceOracle } from "./IDolomitePriceOracle.sol"; /** * @title IDolomiteStructs * @author Dolomite * * @notice This interface defines the structs used by DolomiteMargin */ interface IDolomiteStructs { // ========================= Enums ========================= enum ActionType { Deposit, // supply tokens Withdraw, // borrow tokens Transfer, // transfer balance between accounts Buy, // buy an amount of some token (externally) Sell, // sell an amount of some token (externally) Trade, // trade tokens against another account Liquidate, // liquidate an undercollateralized or expiring account Vaporize, // use excess tokens to zero-out a completely negative account Call // send arbitrary data to an address } enum AssetDenomination { Wei, // the amount is denominated in wei Par // the amount is denominated in par } enum AssetReference { Delta, // the amount is given as a delta from the current value Target // the amount is given as an exact number to end up at } // ========================= Structs ========================= struct AccountInfo { address owner; // The address that owns the account uint256 number; // A nonce that allows a single address to control many accounts } /** * Most-recently-cached account status. * * Normal: Can only be liquidated if the account values are violating the global margin-ratio. * Liquid: Can be liquidated no matter the account values. * Can be vaporized if there are no more positive account values. * Vapor: Has only negative (or zeroed) account values. Can be vaporized. * */ enum AccountStatus { Normal, Liquid, Vapor } /* * Arguments that are passed to DolomiteMargin in an ordered list as part of a single operation. * Each ActionArgs has an actionType which specifies which action struct that this data will be * parsed into before being processed. */ struct ActionArgs { ActionType actionType; uint256 accountId; AssetAmount amount; uint256 primaryMarketId; uint256 secondaryMarketId; address otherAddress; uint256 otherAccountId; bytes data; } struct AssetAmount { bool sign; // true if positive AssetDenomination denomination; AssetReference ref; uint256 value; } struct Decimal { uint256 value; } struct InterestIndex { uint96 borrow; uint96 supply; uint32 lastUpdate; } struct Market { address token; // Whether additional borrows are allowed for this market bool isClosing; // Whether this market can be removed and its ID can be recycled and reused bool isRecyclable; // Total aggregated supply and borrow amount of the entire market TotalPar totalPar; // Interest index of the market InterestIndex index; // Contract address of the price oracle for this market IDolomitePriceOracle priceOracle; // Contract address of the interest setter for this market IDolomiteInterestSetter interestSetter; // Multiplier on the marginRatio for this market, IE 5% (0.05 * 1e18). This number increases the market's // required collateralization by: reducing the user's supplied value (in terms of dollars) for this market and // increasing its borrowed value. This is done through the following operation: // `suppliedWei = suppliedWei + (assetValueForThisMarket / (1 + marginPremium))` // This number increases the user's borrowed wei by multiplying it by: // `borrowedWei = borrowedWei + (assetValueForThisMarket * (1 + marginPremium))` Decimal marginPremium; // Multiplier on the liquidationSpread for this market, IE 20% (0.2 * 1e18). This number increases the // `liquidationSpread` using the following formula: // `liquidationSpread = liquidationSpread * (1 + spreadPremium)` // NOTE: This formula is applied up to two times - one for each market whose spreadPremium is greater than 0 // (when performing a liquidation between two markets) Decimal spreadPremium; // The maximum amount that can be held by the external. This allows the external to cap any additional risk // that is inferred by allowing borrowing against low-cap or assets with increased volatility. Setting this // value to 0 is analogous to having no limit. This value can never be below 0. Wei maxWei; } struct MarketV2 { // Contract address of the associated ERC20 token address token; // Whether additional borrows are allowed for this market bool isClosing; // Total aggregated supply and borrow amount of the entire market TotalPar totalPar; // Interest index of the market InterestIndex index; // Contract address of the price oracle for this market IDolomitePriceOracle priceOracle; // Contract address of the interest setter for this market IDolomiteInterestSetter interestSetter; // Multiplier on the marginRatio for this market, IE 5% (0.05 * 1e18). This number increases the market's // required collateralization by: reducing the user's supplied value (in terms of dollars) for this market and // increasing its borrowed value. This is done through the following operation: // `suppliedWei = suppliedWei + (assetValueForThisMarket / (1 + marginPremium))` // This number increases the user's borrowed wei by multiplying it by: // `borrowedWei = borrowedWei + (assetValueForThisMarket * (1 + marginPremium))` Decimal marginPremium; // Multiplier on the liquidationSpread for this market, IE 20% (0.2 * 1e18). This number increases the // `liquidationSpread` using the following formula: // `liquidationSpread = liquidationSpread * (1 + spreadPremium)` // NOTE: This formula is applied up to two times - one for each market whose spreadPremium is greater than 0 // (when performing a liquidation between two markets) Decimal liquidationSpreadPremium; // The maximum amount that can be held by the protocol. This allows the protocol to cap any additional risk // that is inferred by allowing borrowing against low-cap or assets with increased volatility. Setting this // value to 0 is analogous to having no limit. This value can never be below 0. Wei maxSupplyWei; // The maximum amount that can be borrowed by the protocol. This allows the protocol to cap any additional risk // that is inferred by allowing borrowing against low-cap or assets with increased volatility. Setting this // value to 0 is analogous to having no limit. This value can never be greater than 0. Wei maxBorrowWei; // The percentage of interest paid that is passed along from borrowers to suppliers. Setting this to 0 will // default to RiskParams.earningsRate. Decimal earningsRateOverride; } /* * The price of a base-unit of an asset. Has `36 - token.decimals` decimals */ struct MonetaryPrice { uint256 value; } struct MonetaryValue { uint256 value; } struct OperatorArg { address operator; bool trusted; } struct Par { bool sign; uint128 value; } struct RiskLimits { // The highest that the ratio can be for liquidating under-water accounts uint64 marginRatioMax; // The highest that the liquidation rewards can be when a liquidator liquidates an account uint64 liquidationSpreadMax; // The highest that the supply APR can be for a market, as a proportion of the borrow rate. Meaning, a rate of // 100% (1e18) would give suppliers all of the interest that borrowers are paying. A rate of 90% would give // suppliers 90% of the interest that borrowers pay. uint64 earningsRateMax; // The highest min margin ratio premium that can be applied to a particular market. Meaning, a value of 100% // (1e18) would require borrowers to maintain an extra 100% collateral to maintain a healthy margin ratio. This // value works by increasing the debt owed and decreasing the supply held for the particular market by this // amount, plus 1e18 (since a value of 10% needs to be applied as `decimal.plusOne`) uint64 marginPremiumMax; // The highest liquidation reward that can be applied to a particular market. This percentage is applied // in addition to the liquidation spread in `RiskParams`. Meaning a value of 1e18 is 100%. It is calculated as: // `liquidationSpread * Decimal.onePlus(spreadPremium)` uint64 spreadPremiumMax; uint128 minBorrowedValueMax; } struct RiskLimitsV2 { // The highest that the ratio can be for liquidating under-water accounts uint64 marginRatioMax; // The highest that the liquidation rewards can be when a liquidator liquidates an account uint64 liquidationSpreadMax; // The highest that the supply APR can be for a market, as a proportion of the borrow rate. Meaning, a rate of // 100% (1e18) would give suppliers all of the interest that borrowers are paying. A rate of 90% would give // suppliers 90% of the interest that borrowers pay. uint64 earningsRateMax; // The highest min margin ratio premium that can be applied to a particular market. Meaning, a value of 100% // (1e18) would require borrowers to maintain an extra 100% collateral to maintain a healthy margin ratio. This // value works by increasing the debt owed and decreasing the supply held for the particular market by this // amount, plus 1e18 (since a value of 10% needs to be applied as `decimal.plusOne`) uint64 marginPremiumMax; // The highest liquidation reward that can be applied to a particular market. This percentage is applied // in addition to the liquidation spread in `RiskParams`. Meaning a value of 1e18 is 100%. It is calculated as: // `liquidationSpread * Decimal.onePlus(spreadPremium)` uint64 liquidationSpreadPremiumMax; // The highest that the borrow interest rate can ever be. If the rate returned is ever higher, the rate is // capped at this value instead of reverting. The goal is to keep Dolomite operational under all circumstances // instead of inadvertently DOS'ing the protocol. uint96 interestRateMax; // The highest that the minBorrowedValue can be. This is the minimum amount of value that must be borrowed. // Typically a value of $100 (100 * 1e18) is more than sufficient. uint128 minBorrowedValueMax; } struct RiskParams { // Required ratio of over-collateralization Decimal marginRatio; // Percentage penalty incurred by liquidated accounts Decimal liquidationSpread; // Percentage of the borrower's interest fee that gets passed to the suppliers Decimal earningsRate; // The minimum absolute borrow value of an account // There must be sufficient incentivize to liquidate undercollateralized accounts MonetaryValue minBorrowedValue; // The maximum number of markets a user can have a non-zero balance for a given account. uint256 accountMaxNumberOfMarketsWithBalances; } // The global risk parameters that govern the health and security of the system struct RiskParamsV2 { // Required ratio of over-collateralization Decimal marginRatio; // Percentage penalty incurred by liquidated accounts Decimal liquidationSpread; // Percentage of the borrower's interest fee that gets passed to the suppliers Decimal earningsRate; // The minimum absolute borrow value of an account // There must be sufficient incentivize to liquidate undercollateralized accounts MonetaryValue minBorrowedValue; // The maximum number of markets a user can have a non-zero balance for a given account. uint256 accountMaxNumberOfMarketsWithBalances; // The oracle sentinel used to disable borrowing/liquidations if the sequencer goes down IDolomiteOracleSentinel oracleSentinel; // The gas limit used for making callbacks via `IExternalCallback::onInternalBalanceChange` to smart contract // wallets. Setting to 0 will effectively disable callbacks; setting it super large is not desired since it // could lead to DOS attacks on the protocol; however, hard coding a max value isn't preferred since some chains // can calculate gas usage differently (like ArbGas before Arbitrum rolled out nitro) uint256 callbackGasLimit; // Certain addresses are allowed to borrow with different LTV requirements. When an account's risk is overrode, // the global risk parameters are ignored and the account's risk parameters are used instead. mapping(address => IDolomiteAccountRiskOverrideSetter) accountRiskOverrideSetterMap; } struct TotalPar { uint128 borrow; uint128 supply; } struct TotalWei { uint128 borrow; uint128 supply; } struct Wei { bool sign; uint256 value; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title IWETH * @author Dolomite * * @notice An interface for the WETH contract for wrapping and tokenizing ETH. */ interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 _amount) external; }
// SPDX-License-Identifier: Apache-2.0 /* Copyright 2019 dYdX Trading Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; import { DolomiteMarginMath } from "./DolomiteMarginMath.sol"; import { IDolomiteStructs } from "../interfaces/IDolomiteStructs.sol"; /** * @title DecimalLib * @author dYdX * * Library that defines a fixed-point number with 18 decimal places. */ library DecimalLib { // ============ Constants ============ uint256 private constant _BASE = 10 ** 18; // ============ Functions ============ function one() internal pure returns (IDolomiteStructs.Decimal memory) { return IDolomiteStructs.Decimal({ value: _BASE}); } function onePlus( IDolomiteStructs.Decimal memory d ) internal pure returns (IDolomiteStructs.Decimal memory) { return IDolomiteStructs.Decimal({ value: d.value + _BASE}); } function oneSub( IDolomiteStructs.Decimal memory d ) internal pure returns (IDolomiteStructs.Decimal memory) { return IDolomiteStructs.Decimal({ value: _BASE - d.value}); } function mul( uint256 target, IDolomiteStructs.Decimal memory d ) internal pure returns (uint256) { return DolomiteMarginMath.getPartial(target, d.value, _BASE); } function div( uint256 target, IDolomiteStructs.Decimal memory d ) internal pure returns (uint256) { return DolomiteMarginMath.getPartial(target, _BASE, d.value); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { Require } from "./Require.sol"; /** * @title DolomiteMarginMath * @author dYdX * * @notice Library for non-standard Math functions */ library DolomiteMarginMath { // ============ Constants ============ bytes32 internal constant _FILE = "DolomiteMarginMath"; // ============ Library Functions ============ /* * Return target * (numerator / denominator). */ function getPartial( uint256 target, uint256 numerator, uint256 denominator ) internal pure returns (uint256) { return target * numerator / denominator; } /* * Return target * (numerator / denominator), but rounded half-up. Meaning, a result of 101.1 rounds to 102 * instead of 101. */ function getPartialRoundUp( uint256 target, uint256 numerator, uint256 denominator ) internal pure returns (uint256) { if (target == 0 || numerator == 0) { return 0; } return (((target * numerator) - 1) / denominator) + 1; } /* * Return target * (numerator / denominator), but rounded half-up. Meaning, a result of 101.5 rounds to 102 * instead of 101. */ function getPartialRoundHalfUp( uint256 target, uint256 numerator, uint256 denominator ) internal pure returns (uint256) { if (target == 0 || numerator == 0) { return 0; } return (((target * numerator) + (denominator / 2)) / denominator); } function to128( uint256 number ) internal pure returns (uint128) { uint128 result = uint128(number); Require.that( result == number, _FILE, "Unsafe cast to uint128", number ); return result; } function to96( uint256 number ) internal pure returns (uint96) { uint96 result = uint96(number); Require.that( result == number, _FILE, "Unsafe cast to uint96", number ); return result; } function to32( uint256 number ) internal pure returns (uint32) { uint32 result = uint32(number); Require.that( result == number, _FILE, "Unsafe cast to uint32", number ); return result; } }
// SPDX-License-Identifier: Apache-2.0 /* Copyright 2019 dYdX Trading Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; /** * @title Require * @author dYdX * * @notice Stringifies parameters to pretty-print revert messages. Costs more gas than regular require() */ library Require { // ============ Constants ============ uint256 private constant _ASCII_ZERO = 48; // '0' uint256 private constant _ASCII_RELATIVE_ZERO = 87; // 'a' - 10 uint256 private constant _ASCII_LOWER_EX = 120; // 'x' bytes2 private constant _COLON = 0x3a20; // ': ' bytes2 private constant _COMMA = 0x2c20; // ', ' bytes2 private constant _LPAREN = 0x203c; // ' <' bytes1 private constant _RPAREN = 0x3e; // '>' uint256 private constant _FOUR_BIT_MASK = 0xf; // ============ Library Functions ============ function that( bool must, bytes32 file, bytes32 reason ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason) ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, uint256 payloadA ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, uint256 payloadA, uint256 payloadB ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _COMMA, _stringify(payloadB), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, address payloadA ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, address payloadA, uint256 payloadB ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _COMMA, _stringify(payloadB), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, address payloadA, uint256 payloadB, uint256 payloadC ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _COMMA, _stringify(payloadB), _COMMA, _stringify(payloadC), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, bytes32 payloadA ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _RPAREN ) ) ); } } function that( bool must, bytes32 file, bytes32 reason, bytes32 payloadA, uint256 payloadB, uint256 payloadC ) internal pure { if (!must) { revert( string( abi.encodePacked( stringifyTruncated(file), _COLON, stringifyTruncated(reason), _LPAREN, _stringify(payloadA), _COMMA, _stringify(payloadB), _COMMA, _stringify(payloadC), _RPAREN ) ) ); } } // ============ Private Functions ============ function stringifyTruncated( bytes32 input ) internal pure returns (bytes memory) { // put the input bytes into the result bytes memory result = abi.encodePacked(input); // determine the length of the input by finding the location of the last non-zero byte for (uint256 i = 32; i > 0; ) { // reverse-for-loops with unsigned integer i--; // find the last non-zero byte in order to determine the length if (result[i] != 0) { uint256 length = i + 1; /* solhint-disable-next-line no-inline-assembly */ assembly { mstore(result, length) // r.length = length; } return result; } } // all bytes are zero return new bytes(0); } function stringifyFunctionSelector( bytes4 input ) internal pure returns (bytes memory) { uint256 z = uint256(bytes32(input) >> 224); // bytes4 are "0x" followed by 4 bytes of data which take up 2 characters each bytes memory result = new bytes(10); // populate the result with "0x" result[0] = bytes1(uint8(_ASCII_ZERO)); result[1] = bytes1(uint8(_ASCII_LOWER_EX)); // for each byte (starting from the lowest byte), populate the result with two characters for (uint256 i = 0; i < 4; i++) { // each byte takes two characters uint256 shift = i * 2; // populate the least-significant character result[9 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; // populate the most-significant character result[8 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; } return result; } function _stringify( uint256 input ) private pure returns (bytes memory) { if (input == 0) { return "0"; } // get the final string length uint256 j = input; uint256 length; while (j != 0) { length++; j /= 10; } // allocate the string bytes memory bstr = new bytes(length); // populate the string starting with the least-significant character j = input; for (uint256 i = length; i > 0; ) { // reverse-for-loops with unsigned integer i--; // take last decimal digit bstr[i] = bytes1(uint8(_ASCII_ZERO + (j % 10))); // remove the last decimal digit j /= 10; } return bstr; } function _stringify( address input ) private pure returns (bytes memory) { uint256 z = uint256(uint160(input)); // addresses are "0x" followed by 20 bytes of data which take up 2 characters each bytes memory result = new bytes(42); // populate the result with "0x" result[0] = bytes1(uint8(_ASCII_ZERO)); result[1] = bytes1(uint8(_ASCII_LOWER_EX)); // for each byte (starting from the lowest byte), populate the result with two characters for (uint256 i = 0; i < 20; i++) { // each byte takes two characters uint256 shift = i * 2; // populate the least-significant character result[41 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; // populate the most-significant character result[40 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; } return result; } function _stringify( bytes32 input ) private pure returns (bytes memory) { uint256 z = uint256(input); // bytes32 are "0x" followed by 32 bytes of data which take up 2 characters each bytes memory result = new bytes(66); // populate the result with "0x" result[0] = bytes1(uint8(_ASCII_ZERO)); result[1] = bytes1(uint8(_ASCII_LOWER_EX)); // for each byte (starting from the lowest byte), populate the result with two characters for (uint256 i = 0; i < 32; i++) { // each byte takes two characters uint256 shift = i * 2; // populate the least-significant character result[65 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; // populate the most-significant character result[64 - shift] = _char(z & _FOUR_BIT_MASK); z = z >> 4; } return result; } function _char( uint256 input ) private pure returns (bytes1) { // return ASCII digit (0-9) if (input < 10) { return bytes1(uint8(input + _ASCII_ZERO)); } // return ASCII letter (a-f) return bytes1(uint8(input + _ASCII_RELATIVE_ZERO)); } }
// SPDX-License-Identifier: Apache-2.0 /* Copyright 2019 dYdX Trading Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ pragma solidity ^0.8.9; import { DolomiteMarginMath } from "./DolomiteMarginMath.sol"; import { IDolomiteStructs } from "../interfaces/IDolomiteStructs.sol"; /** * @title TypesLib * @author dYdX * * @notice Library for interacting with the basic structs used in DolomiteMargin */ library TypesLib { using DolomiteMarginMath for uint256; // ============ Par (Principal Amount) ============ function zeroPar() internal pure returns (IDolomiteStructs.Par memory) { return IDolomiteStructs.Par({ sign: false, value: 0 }); } function sub( IDolomiteStructs.Par memory a, IDolomiteStructs.Par memory b ) internal pure returns (IDolomiteStructs.Par memory) { return add(a, negative(b)); } function add( IDolomiteStructs.Par memory a, IDolomiteStructs.Par memory b ) internal pure returns (IDolomiteStructs.Par memory) { IDolomiteStructs.Par memory result; if (a.sign == b.sign) { result.sign = a.sign; result.value = a.value + b.value; } else { if (a.value >= b.value) { result.sign = a.sign; result.value = a.value - b.value; } else { result.sign = b.sign; result.value = b.value - a.value; } } return result; } function equals( IDolomiteStructs.Par memory a, IDolomiteStructs.Par memory b ) internal pure returns (bool) { if (a.value == b.value) { if (a.value == 0) { return true; } return a.sign == b.sign; } return false; } function negative( IDolomiteStructs.Par memory a ) internal pure returns (IDolomiteStructs.Par memory) { return IDolomiteStructs.Par({ sign: !a.sign, value: a.value }); } function isNegative( IDolomiteStructs.Par memory a ) internal pure returns (bool) { return !a.sign && a.value > 0; } function isPositive( IDolomiteStructs.Par memory a ) internal pure returns (bool) { return a.sign && a.value > 0; } function isZero( IDolomiteStructs.Par memory a ) internal pure returns (bool) { return a.value == 0; } function isLessThanZero( IDolomiteStructs.Par memory a ) internal pure returns (bool) { return a.value > 0 && !a.sign; } function isGreaterThanOrEqualToZero( IDolomiteStructs.Par memory a ) internal pure returns (bool) { return isZero(a) || a.sign; } // ============ Wei (Token Amount) ============ function zeroWei() internal pure returns (IDolomiteStructs.Wei memory) { return IDolomiteStructs.Wei({ sign: false, value: 0 }); } function sub( IDolomiteStructs.Wei memory a, IDolomiteStructs.Wei memory b ) internal pure returns (IDolomiteStructs.Wei memory) { return add(a, negative(b)); } function add( IDolomiteStructs.Wei memory a, IDolomiteStructs.Wei memory b ) internal pure returns (IDolomiteStructs.Wei memory) { IDolomiteStructs.Wei memory result; if (a.sign == b.sign) { result.sign = a.sign; result.value = a.value + b.value; } else { if (a.value >= b.value) { result.sign = a.sign; result.value = a.value - b.value; } else { result.sign = b.sign; result.value = b.value - a.value; } } return result; } function equals( IDolomiteStructs.Wei memory a, IDolomiteStructs.Wei memory b ) internal pure returns (bool) { if (a.value == b.value) { if (a.value == 0) { return true; } return a.sign == b.sign; } return false; } function negative( IDolomiteStructs.Wei memory a ) internal pure returns (IDolomiteStructs.Wei memory) { return IDolomiteStructs.Wei({ sign: !a.sign, value: a.value }); } function isNegative( IDolomiteStructs.Wei memory a ) internal pure returns (bool) { return !a.sign && a.value > 0; } function isPositive( IDolomiteStructs.Wei memory a ) internal pure returns (bool) { return a.sign && a.value > 0; } function isZero( IDolomiteStructs.Wei memory a ) internal pure returns (bool) { return a.value == 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol) pragma solidity ^0.8.0; /** * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. * `CREATE2` can be used to compute in advance the address where a smart * contract will be deployed, which allows for interesting new mechanisms known * as 'counterfactual interactions'. * * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more * information. */ library Create2 { /** * @dev Deploys a contract using `CREATE2`. The address where the contract * will be deployed can be known in advance via {computeAddress}. * * The bytecode for a contract can be obtained from Solidity with * `type(contractName).creationCode`. * * Requirements: * * - `bytecode` must not be empty. * - `salt` must have not been used for `bytecode` already. * - the factory must have a balance of at least `amount`. * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. */ function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { require(address(this).balance >= amount, "Create2: insufficient balance"); require(bytecode.length != 0, "Create2: bytecode length is zero"); /// @solidity memory-safe-assembly assembly { addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) } require(addr != address(0), "Create2: Failed on deploy"); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the * `bytecodeHash` or `salt` will result in a new destination address. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { return computeAddress(salt, bytecodeHash, address(this)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. */ function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // Get free memory pointer // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | // |-------------------|---------------------------------------------------------------------------| // | bytecodeHash | CCCCCCCCCCCCC...CC | // | salt | BBBBBBBBBBBBB...BB | // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | // | 0xFF | FF | // |-------------------|---------------------------------------------------------------------------| // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | mstore(add(ptr, 0x40), bytecodeHash) mstore(add(ptr, 0x20), salt) mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff mstore8(start, 0xff) addr := keccak256(start, 85) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; // solhint-disable max-line-length import { IGenericTraderBase } from "@dolomite-exchange/modules-base/contracts/interfaces/IGenericTraderBase.sol"; import { IAsyncFreezableIsolationModeVaultFactory } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IAsyncFreezableIsolationModeVaultFactory.sol"; import { IAsyncIsolationModeTraderBase } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IAsyncIsolationModeTraderBase.sol"; import { IIsolationModeUpgradeableProxy } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IIsolationModeUpgradeableProxy.sol"; import { IIsolationModeVaultFactory } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IIsolationModeVaultFactory.sol"; import { IUpgradeableAsyncIsolationModeUnwrapperTrader } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IUpgradeableAsyncIsolationModeUnwrapperTrader.sol"; // solhint-disable-line max-line-length import { IUpgradeableAsyncIsolationModeWrapperTrader } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IUpgradeableAsyncIsolationModeWrapperTrader.sol"; // solhint-disable-line max-line-length import { DolomiteMarginVersionWrapperLib } from "@dolomite-exchange/modules-base/contracts/lib/DolomiteMarginVersionWrapperLib.sol"; import { IDolomiteMargin } from "@dolomite-exchange/modules-base/contracts/protocol/interfaces/IDolomiteMargin.sol"; import { IDolomitePriceOracle } from "@dolomite-exchange/modules-base/contracts/protocol/interfaces/IDolomitePriceOracle.sol"; import { IDolomiteStructs } from "@dolomite-exchange/modules-base/contracts/protocol/interfaces/IDolomiteStructs.sol"; import { IWETH } from "@dolomite-exchange/modules-base/contracts/protocol/interfaces/IWETH.sol"; import { DecimalLib } from "@dolomite-exchange/modules-base/contracts/protocol/lib/DecimalLib.sol"; import { Require } from "@dolomite-exchange/modules-base/contracts/protocol/lib/Require.sol"; import { TypesLib } from "@dolomite-exchange/modules-base/contracts/protocol/lib/TypesLib.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { IGmxDataStore } from "./interfaces/IGmxDataStore.sol"; import { IGmxExchangeRouter } from "./interfaces/IGmxExchangeRouter.sol"; import { IGmxV2IsolationModeTokenVaultV1 } from "./interfaces/IGmxV2IsolationModeTokenVaultV1.sol"; import { IGmxV2IsolationModeUnwrapperTraderV2 } from "./interfaces/IGmxV2IsolationModeUnwrapperTraderV2.sol"; import { IGmxV2IsolationModeVaultFactory } from "./interfaces/IGmxV2IsolationModeVaultFactory.sol"; import { IGmxV2IsolationModeWrapperTraderV2 } from "./interfaces/IGmxV2IsolationModeWrapperTraderV2.sol"; import { IGmxV2Registry } from "./interfaces/IGmxV2Registry.sol"; import { GmxEventUtils } from "./lib/GmxEventUtils.sol"; import { GmxMarket } from "./lib/GmxMarket.sol"; import { GmxPrice } from "./lib/GmxPrice.sol"; // solhint-enable max-line-length /** * @title GmxV2Library * @author Dolomite * * @notice Library contract for the GmxV2IsolationModeTokenVaultV1 contract to reduce code size */ library GmxV2Library { using DecimalLib for *; using DolomiteMarginVersionWrapperLib for *; using SafeERC20 for IERC20; using SafeERC20 for IWETH; using TypesLib for IDolomiteStructs.Par; // ================================================================== // ============================ Constants =========================== // ================================================================== bytes32 private constant _FILE = "GmxV2Library"; bytes32 private constant _MAX_PNL_FACTOR_KEY = keccak256(abi.encode("MAX_PNL_FACTOR")); bytes32 private constant _MAX_PNL_FACTOR_FOR_ADL_KEY = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_ADL")); bytes32 private constant _MAX_PNL_FACTOR_FOR_WITHDRAWALS_KEY = keccak256(abi.encode("MAX_PNL_FACTOR_FOR_WITHDRAWALS")); // solhint-disable-line max-line-length bytes32 private constant _MAX_CALLBACK_GAS_LIMIT_KEY = keccak256(abi.encode("MAX_CALLBACK_GAS_LIMIT")); bytes32 private constant _CREATE_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("CREATE_WITHDRAWAL_FEATURE_DISABLED")); // solhint-disable-line max-line-length bytes32 private constant _EXECUTE_WITHDRAWAL_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_WITHDRAWAL_FEATURE_DISABLED")); // solhint-disable-line max-line-length bytes32 private constant _EXECUTE_DEPOSIT_FEATURE_DISABLED = keccak256(abi.encode("EXECUTE_DEPOSIT_FEATURE_DISABLED")); // solhint-disable-line max-line-length bytes32 private constant _IS_MARKET_DISABLED = keccak256(abi.encode("IS_MARKET_DISABLED")); uint256 private constant _GMX_PRICE_DECIMAL_ADJUSTMENT = 6; uint256 private constant _GMX_PRICE_SCALE_ADJUSTMENT = 10 ** _GMX_PRICE_DECIMAL_ADJUSTMENT; // ========================================================= // ======================== Structs ======================== // ========================================================= struct MiniCache { IDolomiteMargin dolomiteMargin; uint256 inputMarketId; uint256 outputMarketId; uint256 longMarketId; uint256 shortMarketId; } // ================================================================== // ======================== Public Functions ======================== // ================================================================== function wrapperCreateDeposit( IGmxV2IsolationModeVaultFactory _factory, IGmxV2Registry _registry, IWETH _weth, address _vault, uint256 _ethExecutionFee, address _outputTokenUnderlying, uint256 _minOutputAmount, address _inputToken, uint256 _inputAmount ) public returns (bytes32) { IGmxExchangeRouter exchangeRouter = _registry.gmxExchangeRouter(); bytes32 executeDepositKey = keccak256(abi.encode( _EXECUTE_DEPOSIT_FEATURE_DISABLED, exchangeRouter.depositHandler() )); Require.that( !_registry.gmxDataStore().getBool(executeDepositKey), _FILE, "Execute deposit feature disabled" ); address depositVault = _registry.gmxDepositVault(); if (_inputToken == address(_weth)) { _weth.safeTransferFrom(_vault, address(this), _ethExecutionFee); _weth.safeApprove(address(_registry.gmxRouter()), _ethExecutionFee + _inputAmount); exchangeRouter.sendTokens(address(_weth), depositVault, _ethExecutionFee + _inputAmount); } else { _weth.safeTransferFrom(_vault, address(this), _ethExecutionFee); _weth.safeApprove(address(_registry.gmxRouter()), _ethExecutionFee); exchangeRouter.sendTokens(address(_weth), depositVault, _ethExecutionFee); IERC20(_inputToken).safeApprove(address(_registry.gmxRouter()), _inputAmount); exchangeRouter.sendTokens(_inputToken, depositVault, _inputAmount); } IGmxExchangeRouter.CreateDepositParams memory depositParams = IGmxExchangeRouter.CreateDepositParams( /* receiver = */ address(this), /* callbackContract = */ address(this), /* uiFeeReceiver = */ address(0), /* market = */ _outputTokenUnderlying, /* initialLongToken = */ _factory.LONG_TOKEN(), /* initialShortToken = */ _factory.SHORT_TOKEN(), /* longTokenSwapPath = */ new address[](0), /* shortTokenSwapPath = */ new address[](0), /* minMarketTokens = */ _minOutputAmount, /* shouldUnwrapNativeToken = */ false, /* executionFee = */ _ethExecutionFee, /* callbackGasLimit = */ _registry.callbackGasLimit() ); return exchangeRouter.createDeposit(depositParams); } function initiateCancelDeposit(IGmxV2IsolationModeWrapperTraderV2 _wrapper, bytes32 _key) public { IUpgradeableAsyncIsolationModeWrapperTrader.DepositInfo memory depositInfo = _wrapper.getDepositInfo(_key); Require.that( msg.sender == depositInfo.vault || IAsyncIsolationModeTraderBase(address(_wrapper)).isHandler(msg.sender), _FILE, "Only vault or handler can cancel" ); _wrapper.GMX_REGISTRY_V2().gmxExchangeRouter().cancelDeposit(_key); } function unwrapperInitiateCancelWithdrawal(IGmxV2IsolationModeUnwrapperTraderV2 _unwrapper, bytes32 _key) public { IUpgradeableAsyncIsolationModeUnwrapperTrader.WithdrawalInfo memory withdrawalInfo = _unwrapper.getWithdrawalInfo(_key); Require.that( msg.sender == withdrawalInfo.vault || IAsyncIsolationModeTraderBase(address(_unwrapper)).isHandler(msg.sender), _FILE, "Only vault or handler can cancel" ); _unwrapper.GMX_REGISTRY_V2().gmxExchangeRouter().cancelWithdrawal(_key); } function unwrapperExecuteInitiateUnwrapping( IGmxV2IsolationModeVaultFactory _factory, address _vault, uint256 _inputAmount, address _outputToken, uint256 _minOutputAmount, uint256 _ethExecutionFee, bytes calldata _extraData ) public returns (bytes32) { IERC20(_factory.UNDERLYING_TOKEN()).safeTransferFrom(_vault, address(this), _inputAmount); IGmxV2Registry registry = _factory.gmxV2Registry(); IGmxExchangeRouter exchangeRouter = registry.gmxExchangeRouter(); address[] memory swapPath = new address[](1); swapPath[0] = _factory.UNDERLYING_TOKEN(); // Change scope for stack too deep { address withdrawalVault = registry.gmxWithdrawalVault(); exchangeRouter.sendWnt{value: _ethExecutionFee}(withdrawalVault, _ethExecutionFee); IERC20(swapPath[0]).safeApprove(address(registry.gmxRouter()), _inputAmount); exchangeRouter.sendTokens(swapPath[0], withdrawalVault, _inputAmount); } Require.that( _extraData.length == 64, _FILE, "Invalid extra data" ); // Fix stack too deep address outputToken = _outputToken; IGmxV2IsolationModeVaultFactory factory = _factory; address longToken = factory.LONG_TOKEN(); (, uint256 minOtherTokenAmount) = abi.decode(_extraData, (IDolomiteStructs.Decimal, uint256)); _minOutputAmount -= minOtherTokenAmount; // subtract from the total figure to get its value from the Zap SDK Require.that( _minOutputAmount > 0 && minOtherTokenAmount > 0, _FILE, "minOutputAmount too small" ); IUpgradeableAsyncIsolationModeUnwrapperTrader unwrapper = registry.getUnwrapperByToken(factory); IGmxExchangeRouter.CreateWithdrawalParams memory withdrawalParams = IGmxExchangeRouter.CreateWithdrawalParams( /* receiver = */ address(unwrapper), /* callbackContract = */ address(unwrapper), /* uiFeeReceiver = */ address(0), /* market = */ swapPath[0], /* longTokenSwapPath = */ outputToken == longToken ? new address[](0) : swapPath, /* shortTokenSwapPath = */ outputToken != longToken ? new address[](0) : swapPath, /* minLongTokenAmount = */ longToken == outputToken ? _minOutputAmount : minOtherTokenAmount, /* minShortTokenAmount = */ longToken != outputToken ? _minOutputAmount : minOtherTokenAmount, /* shouldUnwrapNativeToken = */ false, /* executionFee = */ _ethExecutionFee, /* callbackGasLimit = */ registry.callbackGasLimit() ); if (longToken == factory.SHORT_TOKEN()) { withdrawalParams.longTokenSwapPath = new address[](0); withdrawalParams.shortTokenSwapPath = new address[](0); } return exchangeRouter.createWithdrawal(withdrawalParams); } function vaultValidateExecutionFeeIfWrapToUnderlying( IGmxV2IsolationModeTokenVaultV1 _vault, uint256 _tradeAccountNumber, IGenericTraderBase.TraderParam[] memory _tradersPath ) public { uint256 len = _tradersPath.length; if (_tradersPath[len - 1].traderType == IGenericTraderBase.TraderType.IsolationModeWrapper) { _depositAndApproveWethForWrapping(_vault); Require.that( msg.value <= IAsyncFreezableIsolationModeVaultFactory(_vault.VAULT_FACTORY()).maxExecutionFee(), _FILE, "Invalid execution fee" ); _tradersPath[len - 1].tradeData = abi.encode(_tradeAccountNumber, abi.encode(msg.value)); } else { Require.that( msg.value == 0, _FILE, "Cannot send ETH for non-wrapper" ); } } function vaultCancelDeposit(IGmxV2IsolationModeTokenVaultV1 _vault, bytes32 _key) public { IUpgradeableAsyncIsolationModeWrapperTrader wrapper = _vault.registry().getWrapperByToken( IGmxV2IsolationModeVaultFactory(_vault.VAULT_FACTORY()) ); _validateVaultOwnerForStruct(wrapper.getDepositInfo(_key).vault); wrapper.initiateCancelDeposit(_key); } function vaultCancelWithdrawal(IGmxV2IsolationModeTokenVaultV1 _vault, bytes32 _key) public { IUpgradeableAsyncIsolationModeUnwrapperTrader unwrapper = _vault.registry().getUnwrapperByToken( IGmxV2IsolationModeVaultFactory(_vault.VAULT_FACTORY()) ); IUpgradeableAsyncIsolationModeUnwrapperTrader.WithdrawalInfo memory withdrawalInfo = unwrapper.getWithdrawalInfo(_key); _validateVaultOwnerForStruct(withdrawalInfo.vault); Require.that( !withdrawalInfo.isLiquidation, _FILE, "Withdrawal from liquidation" ); unwrapper.initiateCancelWithdrawal(_key); } function isValidInputOrOutputToken( IGmxV2IsolationModeVaultFactory _factory, address _token, bool _skipLongToken ) public view returns (bool) { if (_skipLongToken) { return _token == _factory.SHORT_TOKEN(); } return _token == _factory.LONG_TOKEN() || _token == _factory.SHORT_TOKEN(); } function validateExecutionFee( IGmxV2IsolationModeTokenVaultV1 _vault, uint256 _toAccountNumber ) public view { address factory = IIsolationModeUpgradeableProxy(address(_vault)).vaultFactory(); Require.that( msg.value == IGmxV2IsolationModeVaultFactory(factory).executionFee(), _FILE, "Invalid execution fee" ); Require.that( _vault.getExecutionFeeForAccountNumber(_toAccountNumber) == 0, _FILE, "Execution fee already paid" ); } function isExternalRedemptionPaused( IGmxV2Registry _registry, IGmxV2IsolationModeVaultFactory _factory ) public view returns (bool) { address underlyingToken = _factory.UNDERLYING_TOKEN(); IGmxDataStore dataStore = _registry.gmxDataStore(); { bool isMarketDisabled = dataStore.getBool(_isMarketDisableKey(underlyingToken)); if (isMarketDisabled) { return true; } } { bytes32 createWithdrawalKey = keccak256(abi.encode( _CREATE_WITHDRAWAL_FEATURE_DISABLED, _registry.gmxWithdrawalHandler() )); bool isCreateWithdrawalFeatureDisabled = dataStore.getBool(createWithdrawalKey); if (isCreateWithdrawalFeatureDisabled) { return true; } } { bytes32 executeWithdrawalKey = keccak256(abi.encode( _EXECUTE_WITHDRAWAL_FEATURE_DISABLED, _registry.gmxWithdrawalHandler() )); bool isExecuteWithdrawalFeatureDisabled = dataStore.getBool(executeWithdrawalKey); if (isExecuteWithdrawalFeatureDisabled) { return true; } } uint256 maxPnlForWithdrawalsShort = dataStore.getUint( _maxPnlFactorKey(_MAX_PNL_FACTOR_FOR_WITHDRAWALS_KEY, underlyingToken, /* _isLong = */ false) ); uint256 maxPnlForWithdrawalsLong = dataStore.getUint( _maxPnlFactorKey(_MAX_PNL_FACTOR_FOR_WITHDRAWALS_KEY, underlyingToken, /* _isLong = */ true) ); IDolomitePriceOracle aggregator = _registry.dolomiteRegistry().oracleAggregator(); GmxMarket.MarketPrices memory marketPrices = _getGmxMarketPrices( aggregator.getPrice( _registry.gmxMarketToIndexToken(underlyingToken) ).value, aggregator.getPrice(_factory.LONG_TOKEN()).value, aggregator.getPrice(_factory.SHORT_TOKEN()).value ); int256 shortPnlToPoolFactor = _registry.gmxReader().getPnlToPoolFactor( dataStore, underlyingToken, marketPrices, /* _isLong = */ false, /* _maximize = */ true ); int256 longPnlToPoolFactor = _registry.gmxReader().getPnlToPoolFactor( dataStore, underlyingToken, marketPrices, /* _isLong = */ true, /* _maximize = */ true ); bool isShortPnlTooLarge = shortPnlToPoolFactor > int256(maxPnlForWithdrawalsShort); bool isLongPnlTooLarge = longPnlToPoolFactor > int256(maxPnlForWithdrawalsLong); uint256 maxCallbackGasLimit = dataStore.getUint(_MAX_CALLBACK_GAS_LIMIT_KEY); return isShortPnlTooLarge || isLongPnlTooLarge || _registry.callbackGasLimit() > maxCallbackGasLimit; } function validateInitialMarketIds( uint256[] memory _marketIds, uint256 _longMarketId, uint256 _shortMarketId ) public pure { if (_longMarketId == type(uint256).max) { Require.that( _marketIds.length >= 1, _FILE, "Invalid market IDs length" ); Require.that( _marketIds[0] == _shortMarketId, _FILE, "Invalid market IDs" ); } else { Require.that( _marketIds.length >= 2, _FILE, "Invalid market IDs length" ); Require.that( (_marketIds[0] == _longMarketId && _marketIds[1] == _shortMarketId) || (_marketIds[0] == _shortMarketId && _marketIds[1] == _longMarketId), _FILE, "Invalid market IDs" ); } } function validateEventDataForWithdrawal( IGmxV2IsolationModeVaultFactory _factory, uint256 _marketTokenAmount, GmxEventUtils.AddressKeyValue memory _outputTokenAddress, GmxEventUtils.UintKeyValue memory _outputTokenAmount, GmxEventUtils.AddressKeyValue memory _secondaryOutputTokenAddress, GmxEventUtils.UintKeyValue memory _secondaryOutputTokenAmount, IGmxV2IsolationModeUnwrapperTraderV2.WithdrawalInfo memory _withdrawalInfo ) public view { Require.that( _marketTokenAmount >= _withdrawalInfo.inputAmount, _FILE, "Invalid market token amount" ); Require.that( keccak256(abi.encodePacked(_outputTokenAddress.key)) == keccak256(abi.encodePacked("outputToken")), _FILE, "Unexpected outputToken" ); Require.that( keccak256(abi.encodePacked(_outputTokenAmount.key)) == keccak256(abi.encodePacked("outputAmount")), _FILE, "Unexpected outputAmount" ); Require.that( keccak256(abi.encodePacked(_secondaryOutputTokenAddress.key)) == keccak256(abi.encodePacked("secondaryOutputToken")), _FILE, "Unexpected secondaryOutputToken" ); Require.that( keccak256(abi.encodePacked(_secondaryOutputTokenAmount.key)) == keccak256(abi.encodePacked("secondaryOutputAmount")), _FILE, "Unexpected secondaryOutputAmount" ); if (_withdrawalInfo.outputToken == _factory.LONG_TOKEN()) { Require.that( _withdrawalInfo.outputToken == _outputTokenAddress.value, _FILE, "Output token is incorrect" ); if (_secondaryOutputTokenAmount.value > 0) { Require.that( _outputTokenAddress.value == _secondaryOutputTokenAddress.value, _FILE, "Can only receive one token" ); } } else { Require.that( _withdrawalInfo.outputToken == _secondaryOutputTokenAddress.value, _FILE, "Output token is incorrect" ); if (_outputTokenAmount.value > 0) { Require.that( _outputTokenAddress.value == _secondaryOutputTokenAddress.value, _FILE, "Can only receive one token" ); } } } function validateMinAmountIsNotTooLargeForLiquidation( IGmxV2IsolationModeVaultFactory _factory, IDolomiteStructs.AccountInfo memory _liquidAccount, uint256 _inputAmount, address _outputToken, uint256 _minOutputAmount, bytes calldata _extraData, uint256 _chainId ) public view { // For managing "stack too deep" MiniCache memory cache = MiniCache({ dolomiteMargin: _factory.DOLOMITE_MARGIN(), inputMarketId: _factory.marketId(), outputMarketId: _factory.DOLOMITE_MARGIN().getMarketIdByTokenAddress(_outputToken), longMarketId: _factory.LONG_TOKEN_MARKET_ID(), shortMarketId: _factory.SHORT_TOKEN_MARKET_ID() }); (IDolomiteStructs.Decimal memory weight, uint256 otherMinOutputAmount) = abi.decode( _extraData, (IDolomiteStructs.Decimal, uint256) ); _minOutputAmount -= otherMinOutputAmount; _requireMinAmountIsNotTooLargeForLiquidation( cache.dolomiteMargin, _liquidAccount, cache.inputMarketId, cache.outputMarketId, _inputAmount.mul(DecimalLib.oneSub(weight)), _minOutputAmount, _chainId ); // Check the min output amount of the other token too since GM is unwound via 2 tokens. The // `otherMinOutputAmount` is the min amount out we'll accept when swapping to `outputToken` _requireMinAmountIsNotTooLargeForLiquidation( cache.dolomiteMargin, _liquidAccount, cache.inputMarketId, cache.outputMarketId, _inputAmount.mul(weight), otherMinOutputAmount, _chainId ); } // ================================================================== // ======================== Private Functions ====================== // ================================================================== function _depositAndApproveWethForWrapping(IGmxV2IsolationModeTokenVaultV1 _vault) private { Require.that( msg.value > 0, _FILE, "Invalid execution fee" ); _vault.WETH().deposit{value: msg.value}(); IERC20(address(_vault.WETH())).safeApprove( address(_vault.registry().getWrapperByToken(IIsolationModeVaultFactory(_vault.VAULT_FACTORY()))), msg.value ); } function _getGmxMarketPrices( uint256 _indexTokenPrice, uint256 _longTokenPrice, uint256 _shortTokenPrice ) private pure returns (GmxMarket.MarketPrices memory) { // Dolomite returns price as 36 decimals - token decimals // GMX expects 30 decimals - token decimals so we divide by 10 ** 6 GmxPrice.PriceProps memory indexTokenPriceProps = GmxPrice.PriceProps({ min: _indexTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT, max: _indexTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT }); GmxPrice.PriceProps memory longTokenPriceProps = GmxPrice.PriceProps({ min: _longTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT, max: _longTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT }); GmxPrice.PriceProps memory shortTokenPriceProps = GmxPrice.PriceProps({ min: _shortTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT, max: _shortTokenPrice / _GMX_PRICE_SCALE_ADJUSTMENT }); return GmxMarket.MarketPrices({ indexTokenPrice: indexTokenPriceProps, longTokenPrice: longTokenPriceProps, shortTokenPrice: shortTokenPriceProps }); } function _requireMinAmountIsNotTooLargeForLiquidation( IDolomiteMargin _dolomiteMargin, IDolomiteStructs.AccountInfo memory _liquidAccount, uint256 _inputMarketId, uint256 _outputMarketId, uint256 _inputTokenAmount, uint256 _minOutputAmount, uint256 _chainId ) private view { uint256 inputValue = _dolomiteMargin.getMarketPrice(_inputMarketId).value * _inputTokenAmount; uint256 outputValue = _dolomiteMargin.getMarketPrice(_outputMarketId).value * _minOutputAmount; IDolomiteMargin.Decimal memory spread = _dolomiteMargin.getVersionedLiquidationSpreadForPair( _chainId, _liquidAccount, /* heldMarketId = */ _inputMarketId, /* ownedMarketId = */ _outputMarketId ); spread.value /= 2; uint256 inputValueAdj = inputValue - inputValue.mul(spread); Require.that( outputValue <= inputValueAdj, _FILE, "minOutputAmount too large" ); } function _validateVaultOwnerForStruct(address _vault) private view { Require.that( _vault == address(this), _FILE, "Invalid vault owner", _vault ); } function _maxPnlFactorKey( bytes32 _pnlFactorType, address _market, bool _isLong ) private pure returns (bytes32) { return keccak256(abi.encode(_MAX_PNL_FACTOR_KEY, _pnlFactorType, _market, _isLong)); } function _isMarketDisableKey(address _market) private pure returns (bytes32) { return keccak256(abi.encode(_IS_MARKET_DISABLED, _market)); } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IGmxRoleStore } from "./IGmxRoleStore.sol"; /** * @title IGmxDataStore * @author Dolomite * * @notice GMX DataStore interface */ interface IGmxDataStore { function setUint(bytes32 _key, uint256 _value) external returns (uint256); function setBool(bytes32 _key, bool _bool) external returns (bool); function getBool(bytes32 _key) external view returns (bool); function getUint(bytes32 _key) external view returns (uint256); function roleStore() external view returns (IGmxRoleStore); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxDeposit } from "../lib/GmxDeposit.sol"; import { GmxEventUtils } from "../lib/GmxEventUtils.sol"; /** * @title IGmxDepositCallbackReceiver * @author Dolomite * */ interface IGmxDepositCallbackReceiver { // @dev called after a deposit execution // @param key the key of the deposit // @param deposit the deposit that was executed function afterDepositExecution( bytes32 _key, GmxDeposit.DepositProps memory _deposit, GmxEventUtils.EventLogData memory _eventData ) external; // @dev called after a deposit cancellation // @param key the key of the deposit // @param deposit the deposit that was cancelled function afterDepositCancellation( bytes32 _key, GmxDeposit.DepositProps memory _deposit, GmxEventUtils.EventLogData memory _eventData ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxDeposit } from "../lib/GmxDeposit.sol"; import { GmxOracleUtils } from "../lib/GmxOracleUtils.sol"; /** * @title IGmxDepositHandler * @author Dolomite * */ interface IGmxDepositHandler { // ======== Structs ========= // @dev CreateDepositParams struct used in createDeposit to avoid stack // too deep errors // // @param receiver the address to send the market tokens to // @param callbackContract the callback contract // @param uiFeeReceiver the ui fee receiver // @param market the market to deposit into // @param minMarketTokens the minimum acceptable number of liquidity tokens // @param shouldUnwrapNativeToken whether to unwrap the native token when // sending funds back to the user in case the deposit gets cancelled // @param executionFee the execution fee for keepers // @param callbackGasLimit the gas limit for the callbackContract struct CreateDepositParams { address receiver; address callbackContract; address uiFeeReceiver; address market; address initialLongToken; address initialShortToken; address[] longTokenSwapPath; address[] shortTokenSwapPath; uint256 minMarketTokens; bool shouldUnwrapNativeToken; uint256 executionFee; uint256 callbackGasLimit; } struct Props { uint256 min; uint256 max; } // ======== Events ========= event AfterDepositExecutionError(bytes32 key, GmxDeposit.DepositProps deposit); // ======== Functions ========= function createDeposit(address _account, CreateDepositParams calldata _params) external returns (bytes32); function cancelDeposit(bytes32 _key) external; function simulateExecuteDeposit(bytes32 _key, GmxOracleUtils.SimulatePricesParams memory _params) external; function executeDeposit(bytes32 _key, GmxOracleUtils.SetPricesParams calldata _oracleParams) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IGmxDepositHandler } from "./IGmxDepositHandler.sol"; import { IGmxWithdrawalHandler } from "./IGmxWithdrawalHandler.sol"; /** * @title IGmxExchangeRouter * @author Dolomite * * @notice Interface of the GMX Exchange Router contract */ interface IGmxExchangeRouter { struct CreateDepositParams { address receiver; address callbackContract; address uiFeeReceiver; address market; address initialLongToken; address initialShortToken; address[] longTokenSwapPath; address[] shortTokenSwapPath; uint256 minMarketTokens; bool shouldUnwrapNativeToken; uint256 executionFee; uint256 callbackGasLimit; } struct CreateWithdrawalParams { address receiver; address callbackContract; address uiFeeReceiver; address market; address[] longTokenSwapPath; address[] shortTokenSwapPath; uint256 minLongTokenAmount; uint256 minShortTokenAmount; bool shouldUnwrapNativeToken; uint256 executionFee; uint256 callbackGasLimit; } function createDeposit(CreateDepositParams calldata _params) external returns (bytes32); function createWithdrawal(CreateWithdrawalParams calldata _params) external returns (bytes32); function sendWnt(address _receiver, uint256 _amount) external payable; function sendTokens(address _token, address _receiver, uint256 _amount) external payable; function cancelDeposit(bytes32 _key) external payable; function cancelWithdrawal(bytes32 _key) external payable; function depositHandler() external view returns (IGmxDepositHandler); function withdrawalHandler() external view returns (IGmxWithdrawalHandler); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IGmxDataStore } from "./IGmxDataStore.sol"; import { GmxDeposit } from "../lib/GmxDeposit.sol"; import { GmxMarket } from "../lib/GmxMarket.sol"; import { GmxMarketPoolValueInfo } from "../lib/GmxMarketPoolValueInfo.sol"; import { GmxPrice } from "../lib/GmxPrice.sol"; import { GmxWithdrawal } from "../lib/GmxWithdrawal.sol"; /** * @title IGmxReader * @author Dolomite * * @notice GMX Reader Interface */ interface IGmxReader { enum SwapPricingType { TwoStep, Shift, Atomic } // ================ Errors ================ // AdlHandler errors error AdlNotRequired(int256 pnlToPoolFactor, uint256 maxPnlFactorForAdl); error InvalidAdl(int256 nextPnlToPoolFactor, int256 pnlToPoolFactor); error PnlOvercorrected(int256 nextPnlToPoolFactor, uint256 minPnlFactorForAdl); // AdlUtils errors error InvalidSizeDeltaForAdl(uint256 sizeDeltaUsd, uint256 positionSizeInUsd); error AdlNotEnabled(); // Bank errors error SelfTransferNotSupported(address receiver); error InvalidNativeTokenSender(address msgSender); // BaseRouter error CouldNotSendNativeToken(address receiver, uint256 amount); // CallbackUtils errors error MaxCallbackGasLimitExceeded(uint256 callbackGasLimit, uint256 maxCallbackGasLimit); // Config errors error InvalidBaseKey(bytes32 baseKey); error InvalidFeeFactor(bytes32 baseKey, uint256 value); // Timelock errors error ActionAlreadySignalled(); error ActionNotSignalled(); error SignalTimeNotYetPassed(uint256 signalTime); error InvalidTimelockDelay(uint256 timelockDelay); error MaxTimelockDelayExceeded(uint256 timelockDelay); error InvalidFeeReceiver(address receiver); error InvalidOracleSigner(address receiver); // DepositStoreUtils errors error DepositNotFound(bytes32 key); // DepositUtils errors error EmptyDeposit(); error EmptyDepositAmounts(); // ExecuteDepositUtils errors error MinMarketTokens(uint256 received, uint256 expected); error EmptyDepositAmountsAfterSwap(); error InvalidPoolValueForDeposit(int256 poolValue); error InvalidSwapOutputToken(address outputToken, address expectedOutputToken); error InvalidReceiverForFirstDeposit(address receiver, address expectedReceiver); error InvalidMinMarketTokensForFirstDeposit(uint256 minMarketTokens, uint256 expectedMinMarketTokens); // ExchangeUtils errors error RequestNotYetCancellable(uint256 requestAge, uint256 requestExpirationAge, string requestType); // GlpMigrator errors error InvalidGlpAmount(uint256 totalGlpAmountToRedeem, uint256 totalGlpAmount); error InvalidLongTokenForMigration(address market, address migrationLongToken, address marketLongToken); error InvalidShortTokenForMigration(address market, address migrationShortToken, address marketShortToken); // OrderHandler errors error OrderNotUpdatable(uint256 orderType); error InvalidKeeperForFrozenOrder(address keeper); // FeatureUtils errors error DisabledFeature(bytes32 key); // FeeHandler errors error InvalidClaimFeesInput(uint256 marketsLength, uint256 tokensLength); // GasUtils errors error InsufficientExecutionFee(uint256 minExecutionFee, uint256 executionFee); error InsufficientWntAmountForExecutionFee(uint256 wntAmount, uint256 executionFee); error InsufficientExecutionGasForErrorHandling(uint256 startingGas, uint256 minHandleErrorGas); error InsufficientExecutionGas( uint256 startingGas, uint256 estimatedGasLimit, uint256 minAdditionalGasForExecution ); error InsufficientHandleExecutionErrorGas(uint256 gas, uint256 minHandleExecutionErrorGas); // MarketFactory errors error MarketAlreadyExists(bytes32 salt, address existingMarketAddress); // MarketStoreUtils errors error MarketNotFound(address key); // MarketUtils errors error EmptyMarket(); error DisabledMarket(address market); error MaxSwapPathLengthExceeded(uint256 swapPathLengh, uint256 maxSwapPathLength); error InsufficientPoolAmount(uint256 poolAmount, uint256 amount); error InsufficientReserve(uint256 reservedUsd, uint256 maxReservedUsd); error InsufficientReserveForOpenInterest(uint256 reservedUsd, uint256 maxReservedUsd); error UnableToGetOppositeToken(address inputToken, address market); error UnexpectedTokenForVirtualInventory(address token, address market); error EmptyMarketTokenSupply(); error InvalidSwapMarket(address market); error UnableToGetCachedTokenPrice(address token, address market); error CollateralAlreadyClaimed(uint256 adjustedClaimableAmount, uint256 claimedAmount); error OpenInterestCannotBeUpdatedForSwapOnlyMarket(address market); error MaxOpenInterestExceeded(uint256 openInterest, uint256 maxOpenInterest); error MaxPoolAmountExceeded(uint256 poolAmount, uint256 maxPoolAmount); error MaxPoolAmountForDepositExceeded(uint256 poolAmount, uint256 maxPoolAmountForDeposit); error UnexpectedBorrowingFactor(uint256 positionBorrowingFactor, uint256 cumulativeBorrowingFactor); error UnableToGetBorrowingFactorEmptyPoolUsd(); error UnableToGetFundingFactorEmptyOpenInterest(); error InvalidPositionMarket(address market); error InvalidCollateralTokenForMarket(address market, address token); error PnlFactorExceededForLongs(int256 pnlToPoolFactor, uint256 maxPnlFactor); error PnlFactorExceededForShorts(int256 pnlToPoolFactor, uint256 maxPnlFactor); error InvalidUiFeeFactor(uint256 uiFeeFactor, uint256 maxUiFeeFactor); error EmptyAddressInMarketTokenBalanceValidation(address market, address token); error InvalidMarketTokenBalance(address market, address token, uint256 balance, uint256 expectedMinBalance); error InvalidMarketTokenBalanceForCollateralAmount( address market, address token, uint256 balance, uint256 collateralAmount ); error InvalidMarketTokenBalanceForClaimableFunding( address market, address token, uint256 balance, uint256 claimableFundingFeeAmount ); error UnexpectedPoolValue(int256 poolValue); // Oracle errors error EmptySigner(uint256 signerIndex); error InvalidBlockNumber(uint256 minOracleBlockNumber, uint256 currentBlockNumber); error InvalidMinMaxBlockNumber(uint256 minOracleBlockNumber, uint256 maxOracleBlockNumber); error HasRealtimeFeedId(address token, bytes32 feedId); error InvalidRealtimeFeedLengths(uint256 tokensLength, uint256 dataLength); error EmptyRealtimeFeedId(address token); error InvalidRealtimeFeedId(address token, bytes32 feedId, bytes32 expectedFeedId); error InvalidRealtimeBidAsk(address token, int192 bid, int192 ask); error InvalidRealtimeBlockHash(address token, bytes32 blockHash, bytes32 expectedBlockHash); error InvalidRealtimePrices(address token, int192 bid, int192 ask); error RealtimeMaxPriceAgeExceeded(address token, uint256 oracleTimestamp, uint256 currentTimestamp); error MaxPriceAgeExceeded(uint256 oracleTimestamp, uint256 currentTimestamp); error MinOracleSigners(uint256 oracleSigners, uint256 minOracleSigners); error MaxOracleSigners(uint256 oracleSigners, uint256 maxOracleSigners); error BlockNumbersNotSorted(uint256 minOracleBlockNumber, uint256 prevMinOracleBlockNumber); error MinPricesNotSorted(address token, uint256 price, uint256 prevPrice); error MaxPricesNotSorted(address token, uint256 price, uint256 prevPrice); error EmptyPriceFeedMultiplier(address token); error EmptyRealtimeFeedMultiplier(address token); error InvalidFeedPrice(address token, int256 price); error PriceFeedNotUpdated(address token, uint256 timestamp, uint256 heartbeatDuration); error MaxSignerIndex(uint256 signerIndex, uint256 maxSignerIndex); error InvalidOraclePrice(address token); error InvalidSignerMinMaxPrice(uint256 minPrice, uint256 maxPrice); error InvalidMedianMinMaxPrice(uint256 minPrice, uint256 maxPrice); error NonEmptyTokensWithPrices(uint256 tokensWithPricesLength); error InvalidMinMaxForPrice(address token, uint256 min, uint256 max); error EmptyPriceFeed(address token); error PriceAlreadySet(address token, uint256 minPrice, uint256 maxPrice); error MaxRefPriceDeviationExceeded( address token, uint256 price, uint256 refPrice, uint256 maxRefPriceDeviationFactor ); error InvalidBlockRangeSet(uint256 largestMinBlockNumber, uint256 smallestMaxBlockNumber); // OracleModule errors error InvalidPrimaryPricesForSimulation(uint256 primaryTokensLength, uint256 primaryPricesLength); error EndOfOracleSimulation(); // OracleUtils errors error EmptyCompactedPrice(uint256 index); error EmptyCompactedBlockNumber(uint256 index); error EmptyCompactedTimestamp(uint256 index); error UnsupportedOracleBlockNumberType(uint256 oracleBlockNumberType); error InvalidSignature(address recoveredSigner, address expectedSigner); error EmptyPrimaryPrice(address token); error OracleBlockNumbersAreSmallerThanRequired(uint256[] oracleBlockNumbers, uint256 expectedBlockNumber); error OracleBlockNumberNotWithinRange( uint256[] minOracleBlockNumbers, uint256[] maxOracleBlockNumbers, uint256 blockNumber ); // BaseOrderUtils errors error EmptyOrder(); error UnsupportedOrderType(); error InvalidOrderPrices( uint256 primaryPriceMin, uint256 primaryPriceMax, uint256 triggerPrice, uint256 orderType ); error EmptySizeDeltaInTokens(); error PriceImpactLargerThanOrderSize(int256 priceImpactUsd, uint256 sizeDeltaUsd); error NegativeExecutionPrice( int256 executionPrice, uint256 price, uint256 positionSizeInUsd, int256 priceImpactUsd, uint256 sizeDeltaUsd ); error OrderNotFulfillableAtAcceptablePrice(uint256 price, uint256 acceptablePrice); // IncreaseOrderUtils errors error UnexpectedPositionState(); // OrderUtils errors error OrderTypeCannotBeCreated(uint256 orderType); error OrderAlreadyFrozen(); // OrderStoreUtils errors error OrderNotFound(bytes32 key); // SwapOrderUtils errors error UnexpectedMarket(); // DecreasePositionCollateralUtils errors error InsufficientFundsToPayForCosts(uint256 remainingCostUsd, string step); error InvalidOutputToken(address tokenOut, address expectedTokenOut); // DecreasePositionUtils errors error InvalidDecreaseOrderSize(uint256 sizeDeltaUsd, uint256 positionSizeInUsd); error UnableToWithdrawCollateral(int256 estimatedRemainingCollateralUsd); error InvalidDecreasePositionSwapType(uint256 decreasePositionSwapType); error PositionShouldNotBeLiquidated( string reason, int256 remainingCollateralUsd, int256 minCollateralUsd, int256 minCollateralUsdForLeverage ); // IncreasePositionUtils errors error InsufficientCollateralAmount(uint256 collateralAmount, int256 collateralDeltaAmount); error InsufficientCollateralUsd(int256 remainingCollateralUsd); // PositionStoreUtils errors error PositionNotFound(bytes32 key); // PositionUtils errors error LiquidatablePosition( string reason, int256 remainingCollateralUsd, int256 minCollateralUsd, int256 minCollateralUsdForLeverage ); error EmptyPosition(); error InvalidPositionSizeValues(uint256 sizeInUsd, uint256 sizeInTokens); error MinPositionSize(uint256 positionSizeInUsd, uint256 minPositionSizeUsd); // PositionPricingUtils errors error UsdDeltaExceedsLongOpenInterest(int256 usdDelta, uint256 longOpenInterest); error UsdDeltaExceedsShortOpenInterest(int256 usdDelta, uint256 shortOpenInterest); // SwapPricingUtils errors error UsdDeltaExceedsPoolValue(int256 usdDelta, uint256 poolUsd); // RoleModule errors error Unauthorized(address msgSender, string role); // RoleStore errors error ThereMustBeAtLeastOneRoleAdmin(); error ThereMustBeAtLeastOneTimelockMultiSig(); // ExchangeRouter errors error InvalidClaimFundingFeesInput(uint256 marketsLength, uint256 tokensLength); error InvalidClaimCollateralInput(uint256 marketsLength, uint256 tokensLength, uint256 timeKeysLength); error InvalidClaimAffiliateRewardsInput(uint256 marketsLength, uint256 tokensLength); error InvalidClaimUiFeesInput(uint256 marketsLength, uint256 tokensLength); // SwapUtils errors error InvalidTokenIn(address tokenIn, address market); error InsufficientOutputAmount(uint256 outputAmount, uint256 minOutputAmount); error InsufficientSwapOutputAmount(uint256 outputAmount, uint256 minOutputAmount); error DuplicatedMarketInSwapPath(address market); error SwapPriceImpactExceedsAmountIn(uint256 amountAfterFees, int256 negativeImpactAmount); // SubaccountRouter errors error InvalidReceiverForSubaccountOrder(address receiver, address expectedReceiver); // SubaccountUtils errors error SubaccountNotAuthorized(address account, address subaccount); error MaxSubaccountActionCountExceeded(address account, address subaccount, uint256 count, uint256 maxCount); // TokenUtils errors error EmptyTokenTranferGasLimit(address token); error TokenTransferError(address token, address receiver, uint256 amount); error EmptyHoldingAddress(); // AccountUtils errors error EmptyAccount(); error EmptyReceiver(); // Array errors error CompactedArrayOutOfBounds( uint256[] compactedValues, uint256 index, uint256 slotIndex, string label ); error ArrayOutOfBoundsUint256( uint256[] values, uint256 index, string label ); error ArrayOutOfBoundsBytes( bytes[] values, uint256 index, string label ); // WithdrawalStoreUtils errors error WithdrawalNotFound(bytes32 key); // WithdrawalUtils errors error EmptyWithdrawal(); error EmptyWithdrawalAmount(); error MinLongTokens(uint256 received, uint256 expected); error MinShortTokens(uint256 received, uint256 expected); error InsufficientMarketTokens(uint256 balance, uint256 expected); error InsufficientWntAmount(uint256 wntAmount, uint256 executionFee); error InvalidPoolValueForWithdrawal(int256 poolValue); // Uint256Mask errors error MaskIndexOutOfBounds(uint256 index, string label); error DuplicatedIndex(uint256 index, string label); // =============== Structs ============== // @dev SwapFees struct to contain swap fee values // @param feeReceiverAmount The fee amount for the fee receiver // @param feeAmountForPool The fee amount for the pool // @param amountAfterFees The output amount after fees struct SwapFees { uint256 feeReceiverAmount; uint256 feeAmountForPool; uint256 amountAfterFees; address uiFeeReceiver; uint256 uiFeeReceiverFactor; uint256 uiFeeAmount; } // =============== Functions ============== function getMarketTokenPrice( IGmxDataStore _dataStore, GmxMarket.MarketProps memory _market, GmxPrice.PriceProps memory _indexTokenPrice, GmxPrice.PriceProps memory _longTokenPrice, GmxPrice.PriceProps memory _shortTokenPrice, bytes32 _pnlFactorType, bool _maximize ) external view returns (int256, GmxMarketPoolValueInfo.PoolValueInfoProps memory); function getDeposit( IGmxDataStore _dataStore, bytes32 _key ) external view returns (GmxDeposit.DepositProps memory); function getWithdrawal( IGmxDataStore _dataStore, bytes32 _key ) external view returns (GmxWithdrawal.WithdrawalProps memory); function getPnlToPoolFactor( IGmxDataStore _dataStore, address _marketAddress, GmxMarket.MarketPrices memory _prices, bool _isLong, bool _maximize ) external view returns (int256); function getSwapPriceImpact( IGmxDataStore _dataStore, address _marketKey, address _tokenIn, address _tokenOut, uint256 _amountIn, GmxPrice.PriceProps memory _tokenInPrice, GmxPrice.PriceProps memory _tokenOutPrice ) external view returns (int256, int256); function getSwapAmountOut( IGmxDataStore _dataStore, GmxMarket.MarketProps memory _market, GmxMarket.MarketPrices memory _prices, address _tokenIn, uint256 _amountIn, address _uiFeeReceiver ) external view returns (uint256, int256, SwapFees memory fees); function getDepositAmountOut( IGmxDataStore _dataStore, GmxMarket.MarketProps memory _market, GmxMarket.MarketPrices memory _prices, uint256 _longTokenAmount, uint256 _shortTokenAmount, address _uiFeeReceiver, SwapPricingType _swapPricingType, bool includeVirtualInventoryImpact ) external view returns (uint256); function getWithdrawalAmountOut( IGmxDataStore _dataStore, GmxMarket.MarketProps memory _market, GmxMarket.MarketPrices memory _prices, uint256 _marketTokenAmount, address _uiFeeReceiver, SwapPricingType _swapPricingType ) external view returns (uint256, uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title IGmxRoleStore * @author Dolomite * * @notice GMX RoleStore interface */ interface IGmxRoleStore { /** * @dev Returns the members of the specified role. * * @param _roleKey The key of the role. * @param _start The start index, the value for this index will be included. * @param _end The end index, the value for this index will not be included. * @return The members of the role. */ function getRoleMembers(bytes32 _roleKey, uint256 _start, uint256 _end) external view returns (address[] memory); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title IGmxRouter * @author Dolomite * */ interface IGmxRouter { function pluginTransfer(address _token, address _account, address _receiver, uint256 _amount) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IIsolationModeTokenVaultV1WithAsyncFreezableAndPausable } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IIsolationModeTokenVaultV1WithAsyncFreezableAndPausable.sol"; // solhint-disable-line max-line-length import { IGmxV2Registry } from "./IGmxV2Registry.sol"; /** * @title IGmxV2IsolationModeTokenVaultV1 * @author Dolomite * */ interface IGmxV2IsolationModeTokenVaultV1 is IIsolationModeTokenVaultV1WithAsyncFreezableAndPausable { function cancelDeposit(bytes32 _key) external; function cancelWithdrawal(bytes32 _key) external; function registry() external view returns (IGmxV2Registry); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IUpgradeableAsyncIsolationModeUnwrapperTrader } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IUpgradeableAsyncIsolationModeUnwrapperTrader.sol"; // solhint-disable-line max-line-length import { IGmxV2Registry } from "./IGmxV2Registry.sol"; import { IGmxWithdrawalCallbackReceiver } from "./IGmxWithdrawalCallbackReceiver.sol"; /** * @title IGmxV2IsolationModeUnwrapperTraderV2 * @author Dolomite * */ interface IGmxV2IsolationModeUnwrapperTraderV2 is IUpgradeableAsyncIsolationModeUnwrapperTrader, IGmxWithdrawalCallbackReceiver { function GMX_REGISTRY_V2() external view returns (IGmxV2Registry); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IAsyncFreezableIsolationModeVaultFactory } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IAsyncFreezableIsolationModeVaultFactory.sol"; // solhint-disable-line max-line-length import { IGmxV2Registry } from "./IGmxV2Registry.sol"; /** * @title IGmxV2IsolationModeVaultFactory * @author Dolomite * * @notice Interface for a subclass of IsolationModeVaultFactory that creates vaults for GM tokens. */ interface IGmxV2IsolationModeVaultFactory is IAsyncFreezableIsolationModeVaultFactory { // ================================================ // ==================== Structs =================== // ================================================ struct MarketInfoConstructorParams { address marketToken; address indexToken; address shortToken; address longToken; } // =================================================== // ==================== Functions ==================== // =================================================== function INDEX_TOKEN() external view returns (address); function SHORT_TOKEN() external view returns (address); function LONG_TOKEN() external view returns (address); // function INDEX_TOKEN_MARKET_ID() external view returns (uint256); function SHORT_TOKEN_MARKET_ID() external view returns (uint256); function LONG_TOKEN_MARKET_ID() external view returns (uint256); function gmxV2Registry() external view returns (IGmxV2Registry); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IUpgradeableAsyncIsolationModeWrapperTrader } from "@dolomite-exchange/modules-base/contracts/isolation-mode/interfaces/IUpgradeableAsyncIsolationModeWrapperTrader.sol"; // solhint-disable-line max-line-length import { IGmxDepositCallbackReceiver } from "./IGmxDepositCallbackReceiver.sol"; import { IGmxV2Registry } from "./IGmxV2Registry.sol"; /** * @title IGmxV2IsolationModeWrapperTraderV2 * @author Dolomite * */ interface IGmxV2IsolationModeWrapperTraderV2 is IUpgradeableAsyncIsolationModeWrapperTrader, IGmxDepositCallbackReceiver { function GMX_REGISTRY_V2() external view returns (IGmxV2Registry); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { IBaseRegistry } from "@dolomite-exchange/modules-base/contracts/interfaces/IBaseRegistry.sol"; import { IHandlerRegistry } from "@dolomite-exchange/modules-base/contracts/interfaces/IHandlerRegistry.sol"; import { IGmxDataStore } from "./IGmxDataStore.sol"; import { IGmxDepositHandler } from "./IGmxDepositHandler.sol"; import { IGmxExchangeRouter } from "./IGmxExchangeRouter.sol"; import { IGmxReader } from "./IGmxReader.sol"; import { IGmxRouter } from "./IGmxRouter.sol"; import { IGmxWithdrawalHandler } from "./IGmxWithdrawalHandler.sol"; /** * @title IGmxV2Registry * @author Dolomite * * @notice A registry contract for storing all of the different addresses that can interact with the GMX V2 ecosystem */ interface IGmxV2Registry is IBaseRegistry, IHandlerRegistry { // ================================================ // ==================== Events ==================== // ================================================ event GmxExchangeRouterSet(address _gmxExchangeRouter); event GmxDataStoreSet(address _gmxDataStore); event GmxReaderSet(address _gmxReader); event GmxRouterSet(address _gmxRouter); event GmxDepositVaultSet(address _gmxDepositVault); event GmxWithdrawalVaultSet(address _gmxDepositVault); event GmxV2UnwrapperTraderSet(address _gmxV2UnwrapperTrader); event GmxV2WrapperTraderSet(address _gmxV2WrapperTrader); event GmxMarketToIndexTokenSet(address _marketToken, address _indexToken); // =================================================== // ==================== Functions ==================== // =================================================== function ownerSetGmxExchangeRouter(address _gmxExchangeRouter) external; function ownerSetGmxDataStore(address _gmxDataStore) external; function ownerSetGmxReader(address _gmxReader) external; function ownerSetGmxRouter(address _gmxRouter) external; function ownerSetGmxDepositVault(address _gmxDepositVault) external; function ownerSetGmxWithdrawalVault(address _gmxWithdrawalVault) external; function ownerSetGmxMarketToIndexToken(address _marketToken, address _indexToken) external; function gmxExchangeRouter() external view returns (IGmxExchangeRouter); function gmxDataStore() external view returns (IGmxDataStore); function gmxReader() external view returns (IGmxReader); function gmxRouter() external view returns (IGmxRouter); function gmxDepositHandler() external view returns (IGmxDepositHandler); function gmxDepositVault() external view returns (address); function gmxWithdrawalHandler() external view returns (IGmxWithdrawalHandler); function gmxWithdrawalVault() external view returns (address); function gmxMarketToIndexToken(address _marketToken) external view returns (address); }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxEventUtils } from "../lib/GmxEventUtils.sol"; import { GmxWithdrawal } from "../lib/GmxWithdrawal.sol"; /** * @title IGmxWithdrawalCallbackReceiver * @author Dolomite * */ interface IGmxWithdrawalCallbackReceiver { // @dev called after a withdrawal execution // @param key the key of the withdrawal // @param withdrawal the withdrawal that was executed function afterWithdrawalExecution( bytes32 _key, GmxWithdrawal.WithdrawalProps memory _withdrawal, GmxEventUtils.EventLogData memory _eventData ) external; // @dev called after a withdrawal cancellation // @param key the key of the withdrawal // @param withdrawal the withdrawal that was cancelled function afterWithdrawalCancellation( bytes32 _key, GmxWithdrawal.WithdrawalProps memory _withdrawal, GmxEventUtils.EventLogData memory _eventData ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxOracleUtils } from "../lib/GmxOracleUtils.sol"; /** * @title IGmxWithdrawalHandler * @author Dolomite * */ interface IGmxWithdrawalHandler { /** * * @param receiver The address that will receive the withdrawal tokens. * @param callbackContract The contract that will be called back. * @param market The market on which the withdrawal will be executed. * @param minLongTokenAmount The minimum amount of long tokens that must be withdrawn. * @param minShortTokenAmount The minimum amount of short tokens that must be withdrawn. * @param shouldUnwrapNativeToken Whether the native token should be unwrapped when executing the withdrawal. * @param executionFee The execution fee for the withdrawal. * @param callbackGasLimit The gas limit for calling the callback contract. */ struct CreateWithdrawalParams { address receiver; address callbackContract; address uiFeeReceiver; address market; address[] longTokenSwapPath; address[] shortTokenSwapPath; uint256 minLongTokenAmount; uint256 minShortTokenAmount; bool shouldUnwrapNativeToken; uint256 executionFee; uint256 callbackGasLimit; } struct Props { uint256 min; uint256 max; } struct SimulatePricesParams { address[] primaryTokens; Props[] primaryPrices; } error InsufficientWntAmount(uint256 wntAmount, uint256 executionFee); function createWithdrawal(address _account, CreateWithdrawalParams calldata _params) external returns (bytes32); function cancelWithdrawal(bytes32 _key) external; function simulateExecuteWithdrawal(bytes32 _key, SimulatePricesParams memory _params) external; function executeWithdrawal( bytes32 key, GmxOracleUtils.SetPricesParams calldata oracleParams ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title GmxDeposit * @author Dolomite * */ library GmxDeposit { // @dev there is a limit on the number of fields a struct can have when being passed // or returned as a memory variable which can cause "Stack too deep" errors // use sub-structs to avoid this issue // @param addresses address values // @param numbers number values // @param flags boolean values struct DepositProps { Addresses addresses; Numbers numbers; Flags flags; } // @param account the account depositing liquidity // @param receiver the address to send the liquidity tokens to // @param callbackContract the callback contract // @param uiFeeReceiver the ui fee receiver // @param market the market to deposit to struct Addresses { address account; address receiver; address callbackContract; address uiFeeReceiver; address market; address initialLongToken; address initialShortToken; address[] longTokenSwapPath; address[] shortTokenSwapPath; } // @param initialLongTokenAmount the amount of long tokens to deposit // @param initialShortTokenAmount the amount of short tokens to deposit // @param minMarketTokens the minimum acceptable number of liquidity tokens // @param updatedAtBlock the block that the deposit was last updated at // sending funds back to the user in case the deposit gets cancelled // @param executionFee the execution fee for keepers // @param callbackGasLimit the gas limit for the callbackContract struct Numbers { uint256 initialLongTokenAmount; uint256 initialShortTokenAmount; uint256 minMarketTokens; uint256 updatedAtBlock; uint256 updatedAtTime; uint256 executionFee; uint256 callbackGasLimit; } // @param shouldUnwrapNativeToken whether to unwrap the native token when struct Flags { bool shouldUnwrapNativeToken; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title GmxEventUtils * @author Dolomite * */ library GmxEventUtils { struct EmitPositionDecreaseParams { bytes32 key; address account; address market; address collateralToken; bool isLong; } struct EventLogData { AddressItems addressItems; UintItems uintItems; IntItems intItems; BoolItems boolItems; Bytes32Items bytes32Items; BytesItems bytesItems; StringItems stringItems; } struct AddressItems { AddressKeyValue[] items; AddressArrayKeyValue[] arrayItems; } struct UintItems { UintKeyValue[] items; UintArrayKeyValue[] arrayItems; } struct IntItems { IntKeyValue[] items; IntArrayKeyValue[] arrayItems; } struct BoolItems { BoolKeyValue[] items; BoolArrayKeyValue[] arrayItems; } struct Bytes32Items { Bytes32KeyValue[] items; Bytes32ArrayKeyValue[] arrayItems; } struct BytesItems { BytesKeyValue[] items; BytesArrayKeyValue[] arrayItems; } struct StringItems { StringKeyValue[] items; StringArrayKeyValue[] arrayItems; } struct AddressKeyValue { string key; address value; } struct AddressArrayKeyValue { string key; address[] value; } struct UintKeyValue { string key; uint256 value; } struct UintArrayKeyValue { string key; uint256[] value; } struct IntKeyValue { string key; int256 value; } struct IntArrayKeyValue { string key; int256[] value; } struct BoolKeyValue { string key; bool value; } struct BoolArrayKeyValue { string key; bool[] value; } struct Bytes32KeyValue { string key; bytes32 value; } struct Bytes32ArrayKeyValue { string key; bytes32[] value; } struct BytesKeyValue { string key; bytes value; } struct BytesArrayKeyValue { string key; bytes[] value; } struct StringKeyValue { string key; string value; } struct StringArrayKeyValue { string key; string[] value; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxPrice } from "./GmxPrice.sol"; /** * @title GmxMarket * @author Dolomite * * @notice GMX Market Library */ library GmxMarket { struct MarketProps { address marketToken; address indexToken; address longToken; address shortToken; } struct MarketPrices { GmxPrice.PriceProps indexTokenPrice; GmxPrice.PriceProps longTokenPrice; GmxPrice.PriceProps shortTokenPrice; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title GmxMarketPoolValueInfo * @author Dolomite * * @notice GMX MarketPoolVaultInfo Library */ library GmxMarketPoolValueInfo { // @dev struct to avoid stack too deep errors for the getPoolValue call // @param value the pool value // @param longTokenAmount the amount of long token in the pool // @param shortTokenAmount the amount of short token in the pool // @param longTokenUsd the USD value of the long tokens in the pool // @param shortTokenUsd the USD value of the short tokens in the pool // @param totalBorrowingFees the total pending borrowing fees for the market // @param borrowingFeePoolFactor the pool factor for borrowing fees // @param impactPoolAmount the amount of tokens in the impact pool // @param longPnl the pending pnl of long positions // @param shortPnl the pending pnl of short positions // @param netPnl the net pnl of long and short positions struct PoolValueInfoProps { int256 poolValue; int256 longPnl; int256 shortPnl; int256 netPnl; uint256 longTokenAmount; uint256 shortTokenAmount; uint256 longTokenUsd; uint256 shortTokenUsd; uint256 totalBorrowingFees; uint256 borrowingFeePoolFactor; uint256 impactPoolAmount; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; import { GmxPrice } from "./GmxPrice.sol"; /** * @title GmxOracleUtils * @author Dolomite * */ library GmxOracleUtils { /** * @dev SetPricesParams struct for values required in Oracle.setPrices * * * @param signerInfo The compacted indexes of signers, the index is used to retrieve the signer * address from the OracleStore * @param tokens The list of tokens to set prices for * @param compactedOracleBlockNumbers The compacted oracle block numbers * @param compactedOracleTimestamps The compacted oracle timestamps * @param compactedDecimals The compacted decimals for prices * @param compactedMinPrices The compacted min prices * @param compactedMinPricesIndexes The compacted min price indexes * @param compactedMaxPrices The compacted max prices * @param compactedMaxPricesIndexes The compacted max price indexes * @param signatures The signatures of the oracle signers * @param priceFeedTokens The tokens to set prices for based on an external price feed value */ struct SetPricesParams { uint256 signerInfo; address[] tokens; uint256[] compactedMinOracleBlockNumbers; uint256[] compactedMaxOracleBlockNumbers; uint256[] compactedOracleTimestamps; uint256[] compactedDecimals; uint256[] compactedMinPrices; uint256[] compactedMinPricesIndexes; uint256[] compactedMaxPrices; uint256[] compactedMaxPricesIndexes; bytes[] signatures; address[] priceFeedTokens; address[] realtimeFeedTokens; bytes[] realtimeFeedData; } struct SimulatePricesParams { address[] primaryTokens; GmxPrice.PriceProps[] primaryPrices; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title GmxPrice * @author Dolomite * * @notice GMX Price Library */ library GmxPrice { struct PriceProps { uint256 min; uint256 max; } }
// SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2023 Dolomite This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ pragma solidity ^0.8.9; /** * @title GmxWithdrawal * @author Dolomite * */ library GmxWithdrawal { // @dev there is a limit on the number of fields a struct can have when being passed // or returned as a memory variable which can cause "Stack too deep" errors // use sub-structs to avoid this issue // @param addresses address values // @param numbers number values // @param flags boolean values struct WithdrawalProps { Addresses addresses; Numbers numbers; Flags flags; } // @param account The account to withdraw for. // @param receiver The address that will receive the withdrawn tokens. // @param callbackContract The contract that will be called back. // @param uiFeeReceiver The ui fee receiver. // @param market The market on which the withdrawal will be executed. struct Addresses { address account; address receiver; address callbackContract; address uiFeeReceiver; address market; address[] longTokenSwapPath; address[] shortTokenSwapPath; } // @param marketTokenAmount The amount of market tokens that will be withdrawn. // @param minLongTokenAmount The minimum amount of long tokens that must be withdrawn. // @param minShortTokenAmount The minimum amount of short tokens that must be withdrawn. // @param updatedAtBlock The block at which the withdrawal was last updated. // @param executionFee The execution fee for the withdrawal. // @param callbackGasLimit The gas limit for calling the callback contract. struct Numbers { uint256 marketTokenAmount; uint256 minLongTokenAmount; uint256 minShortTokenAmount; uint256 updatedAtBlock; uint256 updatedAtTime; uint256 executionFee; uint256 callbackGasLimit; } // @param shouldUnwrapNativeToken whether to unwrap the native token when struct Flags { bool shouldUnwrapNativeToken; } }
{ "optimizer": { "enabled": true, "runs": 200, "details": { "yul": false } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/GmxV2Library.sol": { "GmxV2Library": "0x6b8964b454e514D97Ee50Cd5E87A2338360229D9" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"components":[{"internalType":"address","name":"gmxV2Registry","type":"address"},{"internalType":"uint256","name":"executionFee","type":"uint256"},{"components":[{"internalType":"address","name":"marketToken","type":"address"},{"internalType":"address","name":"indexToken","type":"address"},{"internalType":"address","name":"shortToken","type":"address"},{"internalType":"address","name":"longToken","type":"address"}],"internalType":"struct IGmxV2IsolationModeVaultFactory.MarketInfoConstructorParams","name":"tokenAndMarketAddresses","type":"tuple"},{"internalType":"bool","name":"skipLongToken","type":"bool"},{"internalType":"uint256[]","name":"initialAllowableDebtMarketIds","type":"uint256[]"},{"internalType":"uint256[]","name":"initialAllowableCollateralMarketIds","type":"uint256[]"},{"internalType":"address","name":"borrowPositionProxyV2","type":"address"},{"internalType":"address","name":"userVaultImplementation","type":"address"},{"internalType":"address","name":"dolomiteRegistry","type":"address"},{"internalType":"address","name":"dolomiteMargin","type":"address"}],"internalType":"struct GmxV2IsolationModeVaultFactory.ConstructorParams","name":"_params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"allowableCollateralMarketIds","type":"uint256[]"}],"name":"AllowableCollateralMarketIdsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"allowableDebtMarketIds","type":"uint256[]"}],"name":"AllowableDebtMarketIdsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_executionFee","type":"uint256"}],"name":"ExecutionFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_handlerRegistry","type":"address"}],"name":"HandlerRegistrySet","type":"event"},{"anonymous":false,"inputs":[],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_maxExecutionFee","type":"uint256"}],"name":"MaxExecutionFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenConverter","type":"address"},{"indexed":false,"internalType":"bool","name":"isTrusted","type":"bool"}],"name":"TokenConverterSet","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":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"transferCursor","type":"uint256"},{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountWei","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"TransferQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousUserVaultImplementation","type":"address"},{"indexed":true,"internalType":"address","name":"newUserVaultImplementation","type":"address"}],"name":"UserVaultImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"uint256","name":"accountNumber","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isFrozen","type":"bool"}],"name":"VaultAccountFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"VaultCreated","type":"event"},{"inputs":[],"name":"BORROW_POSITION_PROXY","outputs":[{"internalType":"contract IBorrowPositionProxyV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOLOMITE_MARGIN","outputs":[{"internalType":"contract IDolomiteMargin","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOLOMITE_MARGIN_OWNER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOLOMITE_REGISTRY","outputs":[{"internalType":"contract IDolomiteRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INDEX_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LONG_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LONG_TOKEN_MARKET_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHORT_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHORT_TOKEN_MARKET_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNDERLYING_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowableCollateralMarketIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowableDebtMarketIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","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":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"calculateVaultByAccount","outputs":[{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"createVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_toAccountNumber","type":"uint256"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"createVaultAndDepositIntoDolomiteMargin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_toAccountNumber","type":"uint256"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"depositIntoDolomiteMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_vaultAccountNumber","type":"uint256"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"depositIntoDolomiteMarginFromTokenConverter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_toAccountNumber","type":"uint256"},{"internalType":"uint256","name":"_otherMarketId","type":"uint256"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"depositOtherTokenIntoDolomiteMarginForVaultOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"enqueueTransferFromDolomiteMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"enqueueTransferIntoDolomiteMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"getAccountByVault","outputs":[{"internalType":"address","name":"_account","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_accountNumber","type":"uint256"}],"name":"getOutputTokenByAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_accountNumber","type":"uint256"},{"internalType":"enum IAsyncFreezableIsolationModeVaultFactory.FreezeType","name":"_freezeType","type":"uint8"}],"name":"getPendingAmountByAccount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"enum IAsyncFreezableIsolationModeVaultFactory.FreezeType","name":"_freezeType","type":"uint8"}],"name":"getPendingAmountByVault","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProxyVaultInitCodeHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_transferCursor","type":"uint256"}],"name":"getQueuedTransferByCursor","outputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"isExecuted","type":"bool"}],"internalType":"struct IIsolationModeVaultFactory.QueuedTransfer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getVaultByAccount","outputs":[{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gmxV2Registry","outputs":[{"internalType":"contract IGmxV2Registry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"handlerRegistry","outputs":[{"internalType":"contract IHandlerRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isIsolationAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenConverter","type":"address"}],"name":"isTokenConverterTrusted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_accountNumber","type":"uint256"}],"name":"isVaultAccountFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"isVaultFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"marketId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxExecutionFee","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":"_tokenConverters","type":"address[]"}],"name":"ownerInitialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_newAllowableCollateralMarketIds","type":"uint256[]"}],"name":"ownerSetAllowableCollateralMarketIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_newAllowableDebtMarketIds","type":"uint256[]"}],"name":"ownerSetAllowableDebtMarketIds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_executionFee","type":"uint256"}],"name":"ownerSetExecutionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_handlerRegistry","type":"address"}],"name":"ownerSetHandlerRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenConverter","type":"address"},{"internalType":"bool","name":"_isTrusted","type":"bool"}],"name":"ownerSetIsTokenConverterTrusted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxExecutionFee","type":"uint256"}],"name":"ownerSetMaxExecutionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userVaultImplementation","type":"address"}],"name":"ownerSetUserVaultImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"bool","name":"_isDepositSourceWrapper","type":"bool"}],"name":"setIsVaultDepositSourceWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"bool","name":"_shouldSkipTransfer","type":"bool"}],"name":"setShouldVaultSkipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint256","name":"_accountNumber","type":"uint256"},{"internalType":"enum IAsyncFreezableIsolationModeVaultFactory.FreezeType","name":"_freezeType","type":"uint8"},{"components":[{"internalType":"bool","name":"sign","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IDolomiteStructs.Wei","name":"_amountDeltaWei","type":"tuple"},{"internalType":"address","name":"_conversionToken","type":"address"}],"name":"setVaultAccountPendingAmountForFrozenStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":[],"name":"transferCursor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":[],"name":"userVaultImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromAccountNumber","type":"uint256"},{"internalType":"uint256","name":"_amountWei","type":"uint256"}],"name":"withdrawFromDolomiteMargin","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101a0604052670de0b6b3a7640000600f553480156200001e57600080fd5b506040516200814d3803806200814d8339810160408190526200004191620011de565b80608001518160a001518260400151600001518360c001518460e00151856101000151866101200151876020015188600001518686868686846001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015620000b357600080fd5b505afa158015620000c8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000f29190810190620012e1565b60405160200162000104919062001346565b604051602081830303815290604052856001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156200014d57600080fd5b505afa15801562000162573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200018c9190810190620012e1565b6040516020016200019e91906200138f565b604051602081830303815290604052866001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b158015620001e757600080fd5b505afa158015620001fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002229190620013b3565b6001600160a01b0384166080526200023c8383836200052c565b5050506001600160a01b0380831660e05285811660a05284811660c0526005805491851661010002610100600160a81b03199092169190911790556200028461dead62000570565b5050505050506200029b826200077360201b60201c565b620002a68162000812565b50620002b49050876200085f565b620002bf86620009d5565b50505060408086018051602001516001600160a01b0390811661014052905190910151166101005250620002f792505062000a1c9050565b6001600160a01b0316638fae3be1610100516040518263ffffffff1660e01b8152600401620003279190620013e9565b60206040518083038186803b1580156200034057600080fd5b505afa15801562000355573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200037b9190620013f9565b6101605260408101516060908101516001600160a01b0316610120528101516200042d5760805161012051604051638fae3be160e01b81526001600160a01b0390921691638fae3be191620003d391600401620013e9565b60206040518083038186803b158015620003ec57600080fd5b505afa15801562000401573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004279190620013f9565b62000431565b6000195b61018081905260808201516101605160405163016e3bdf60e31b8152736b8964b454e514d97ee50cd5e87a2338360229d993630b71def8936200047993909260040162001489565b60006040518083038186803b1580156200049257600080fd5b505af4158015620004a7573d6000803e3d6000fd5b50505060a0820151610180516101605160405163016e3bdf60e31b8152736b8964b454e514d97ee50cd5e87a2338360229d99450630b71def893620004f3939092909160040162001489565b60006040518083038186803b1580156200050c57600080fd5b505af415801562000521573d6000803e3d6000fd5b50505050506200186f565b82516200054190600390602086019062000da5565b5081516200055790600490602085019062000da5565b506005805460ff191660ff929092169190911790555050565b6000620005d260006001600160a01b0316836001600160a01b031614157f49736f6c6174696f6e4d6f64655661756c74466163746f7279000000000000006e125b9d985b1a59081858d8dbdd5b9d608a1b62000a2260201b620021cb1760201c565b6001600160a01b038281166000908152600a60209081526040909120546200064a921615907f49736f6c6174696f6e4d6f64655661756c74466163746f727900000000000000907f5661756c7420616c72656164792065786973747300000000000000000000000090620021cb62000a22821b17901c565b6000620006b2600084604051602001620006659190620014eb565b60405160208183030381529060405280519060200120604051806020016200068d9062000e34565b6020820181038252601f19601f8201166040525062000a8e60201b620022321760201c565b90506001600160a01b038116620006cd57620006cd62001502565b826001600160a01b03167f5d9c31ffa0fecffd7cf379989a3c7af252f0335e0d2a1320b55245912c781f5382604051620007089190620013e9565b60405180910390a26001600160a01b03808216600081815260096020908152604080832080549589166001600160a01b03199687168117909155808452600a909252909120805490931690911790915561dead146200076d576200076d838262000b0f565b92915050565b620007d0600f548211157f467265657a61626c655661756c74466163746f727900000000000000000000007f496e76616c696420657865637574696f6e20666565000000000000000000000062000a2260201b620021cb1760201c565b60108190556040517f34243bbc545b7abbfc8001dc34d1ae65eef90e6bbccd634ddf433247734c9d7a906200080790839062001518565b60405180910390a150565b601180546001600160a01b0319166001600160a01b0383161790556040517fd61d47c7844ec2c99fa7e2b21baaacf489203aa183ed706df8a3f169acd7b38e9062000807908390620013e9565b805160005b8181101562000981576200096c6200087b60805190565b6001600160a01b0316635ac7d17c8584815181106200089e576200089e62001528565b60200260200101516040518263ffffffff1660e01b8152600401620008c4919062001518565b60206040518083038186803b158015620008dd57600080fd5b505afa158015620008f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200091891906200153e565b157f53696d706c6549736f6c6174696f6e4d6f64655661756c74466163746f7279007f4d61726b65742063616e6e6f7420626520636c6f73696e67000000000000000062000a2260201b620021cb1760201c565b80620009788162001579565b91505062000864565b5081516200099790601290602085019062000e42565b507fe394f8a439e499167cfe98e403f35fc54387abe3f9db4e5c0632c8ec8e9b193482604051620009c99190620015d3565b60405180910390a15050565b8051620009ea90601390602084019062000e42565b507f3ef7cb7777c10315913a05aed0c0c3f1b40e11bbe9df01be0a5d1f71db93faff81604051620008079190620015d3565b60805190565b8262000a895762000a338262000ce6565b6101d160f51b62000a448362000ce6565b60405160200162000a5893929190620015f7565b60408051601f198184030181529082905262461bcd60e51b825262000a809160040162001663565b60405180910390fd5b505050565b60008347101562000ab35760405162461bcd60e51b815260040162000a8090620016ad565b815162000ad45760405162461bcd60e51b815260040162000a8090620016f2565b8282516020840186f590506001600160a01b03811662000b085760405162461bcd60e51b815260040162000a809062001739565b9392505050565b6001600160a01b0382161580159062000b3057506001600160a01b03811615155b62000b3f5762000b3f62001502565b60405163189acdbd60e31b81526001600160a01b0382169063c4d66de89062000b6d908590600401620013e9565b600060405180830381600087803b15801562000b8857600080fd5b505af115801562000b9d573d6000803e3d6000fd5b5050505060c0516001600160a01b031663f697ae998260016040518363ffffffff1660e01b815260040162000bd492919062001754565b600060405180830381600087803b15801562000bef57600080fd5b505af115801562000c04573d6000803e3d6000fd5b5050505060e0516001600160a01b031663f68ebbbd6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000c4457600080fd5b505afa15801562000c59573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c7f919062001798565b6001600160a01b03166305c4fdf983836040518363ffffffff1660e01b815260040162000cae929190620017bd565b600060405180830381600087803b15801562000cc957600080fd5b505af115801562000cde573d6000803e3d6000fd5b505050505050565b606060008260405160200162000cfd9190620017dc565b60408051601f19818403018152919052905060205b801562000d8a578062000d2581620017f3565b91505081818151811062000d3d5762000d3d62001528565b01602001517fff00000000000000000000000000000000000000000000000000000000000000161562000d8457600062000d798260016200180d565b835250909392505050565b62000d12565b5060408051600080825260208201909252905b509392505050565b82805462000db3906200183e565b90600052602060002090601f01602090048101928262000dd7576000855562000e22565b82601f1062000df257805160ff191683800117855562000e22565b8280016001018555821562000e22579182015b8281111562000e2257825182559160200191906001019062000e05565b5062000e3092915062000e7f565b5090565b610b37806200761683390190565b82805482825590600052602060002090810192821562000e22579160200282018281111562000e2257825182559160200191906001019062000e05565b5b8082111562000e30576000815560010162000e80565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b038211171562000ed45762000ed462000e96565b6040525050565b600062000ee760405190565b905062000ef5828262000eac565b919050565b60006001600160a01b0382166200076d565b62000f178162000efa565b811462000f2357600080fd5b50565b80516200076d8162000f0c565b8062000f17565b80516200076d8162000f33565b60006080828403121562000f5e5762000f5e600080fd5b62000f6a608062000edb565b9050600062000f7a848462000f26565b825250602062000f8d8484830162000f26565b602083015250604062000fa38482850162000f26565b604083015250606062000fb98482850162000f26565b60608301525092915050565b80151562000f17565b80516200076d8162000fc5565b60006001600160401b0382111562000ff75762000ff762000e96565b5060209081020190565b600062001018620010128462000fdb565b62000edb565b83815290506020808201908402830185811115620010395762001039600080fd5b835b8181101562001061578062001051888262000f3a565b845250602092830192016200103b565b5050509392505050565b600082601f830112620010815762001081600080fd5b81516200109384826020860162001001565b949350505050565b60006101a08284031215620010b357620010b3600080fd5b620010c061014062000edb565b90506000620010d0848462000f26565b8252506020620010e38484830162000f3a565b6020830152506040620010f98482850162000f47565b60408301525060c06200110f8482850162000fce565b60608301525060e08201516001600160401b03811115620011335762001133600080fd5b62001141848285016200106b565b6080830152506101008201516001600160401b03811115620011665762001166600080fd5b62001174848285016200106b565b60a0830152506101206200118b8482850162000f26565b60c083015250610140620011a28482850162000f26565b60e083015250610160620011b98482850162000f26565b61010083015250610180620011d18482850162000f26565b6101208301525092915050565b600060208284031215620011f557620011f5600080fd5b81516001600160401b03811115620012105762001210600080fd5b62001093848285016200109b565b60006001600160401b038211156200123a576200123a62000e96565b601f19601f83011660200192915050565b60005b83811015620012685781810151838201526020016200124e565b8381111562001278576000848401525b50505050565b60006200128f62001012846200121e565b905082815260208101848484011115620012ac57620012ac600080fd5b62000d9d8482856200124b565b600082601f830112620012cf57620012cf600080fd5b8151620010938482602086016200127e565b600060208284031215620012f857620012f8600080fd5b81516001600160401b03811115620013135762001313600080fd5b6200109384828501620012b9565b60006200132c825190565b6200133c8185602086016200124b565b9290920192915050565b7f446f6c6f6d6974652049736f6c6174696f6e3a2000000000000000000000000081526000601482015b915062000b08828462001321565b601960fa1b815260005b5060010190565b600062001370826200137e565b60ff811662000f17565b80516200076d816200139c565b600060208284031215620013ca57620013ca600080fd5b6000620010938484620013a6565b620013e38162000efa565b82525050565b602081016200076d8284620013d8565b600060208284031215620014105762001410600080fd5b600062001093848462000f3a565b80620013e3565b60006200143383836200141e565b505060200190565b600062001446825190565b80845260209384019383018060005b838110156200147e5781516200146c888262001425565b97506020830192505060010162001455565b509495945050505050565b606080825281016200149c81866200143b565b9050620014ad60208301856200141e565b6200109360408301846200141e565b60006200076d8260601b90565b60006200076d82620014bc565b620013e3620014e58262000efa565b620014c9565b6000620014f98284620014d6565b50601401919050565b634e487b7160e01b600052600160045260246000fd5b602081016200076d82846200141e565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620015555762001555600080fd5b600062001093848462000fce565b634e487b7160e01b600052601160045260246000fd5b600060001982141562001388576200138862001563565b60006200159b825190565b80845260209384019383018060005b838110156200147e578151620015c1888262001425565b975060208301925050600101620015aa565b6020808252810162000b08818462001590565b6001600160f01b03198116620013e3565b600062001605828662001321565b9150620016138285620015e6565b60028201915062001625828462001321565b95945050505050565b600062001639825190565b808452602084019350620016528185602086016200124b565b601f01601f19169290920192915050565b6020808252810162000b0881846200162e565b601d81526000602082017f437265617465323a20696e73756666696369656e742062616c616e6365000000815291505b5060200190565b602080825281016200076d8162001676565b60208082527f437265617465323a2062797465636f6465206c656e677468206973207a65726f91019081526000620016a6565b602080825281016200076d81620016bf565b601981526000602082017f437265617465323a204661696c6564206f6e206465706c6f790000000000000081529150620016a6565b602080825281016200076d8162001704565b801515620013e3565b60408101620017648285620013d8565b62000b0860208301846200174b565b60006200076d8262000efa565b62000f178162001773565b80516200076d8162001780565b600060208284031215620017af57620017af600080fd5b60006200109384846200178b565b60408101620017cd8285620013d8565b62000b086020830184620013d8565b6000620017ea82846200141e565b50602001919050565b60008162001805576200180562001563565b506000190190565b6000821982111562001823576200182362001563565b500190565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200185357607f821691505b6020821081141562001869576200186962001828565b50919050565b60805160a05160c05160e0516101005161012051610140516101605161018051615d28620018ee6000396000610691015260006107cb01526000610955015260006103fb0152600061065201526000818161097d01526124df0152600081816105b1015261246d0152600061058901526000610feb0152615d286000f3fe60806040523480156200001157600080fd5b5060043610620003f05760003560e01c806376d258f81162000211578063b1a1e3bf1162000125578063cbffd92111620000bb578063de87cac61162000086578063de87cac614620009f9578063ed4e3a351462000a10578063f8a41f4f1462000a18578063fb82f8ee1462000a2f57600080fd5b8063cbffd921146200099f578063d143d59114620009a9578063d3f5f06214620009b3578063dd62ed3e14620009bd57600080fd5b8063bc08373211620000fc578063bc0837321462000909578063c1090d5a1462000938578063c11201f7146200094f578063c6d20c85146200097757600080fd5b8063b1a1e3bf14620008c9578063b4bd6f4614620008db578063bc01089914620008f257600080fd5b8063956f5c7811620001a7578063a269bfb71162000172578063a269bfb71462000853578063a6e7d83f146200086a578063a9059cbb1462000883578063b01f61e1146200089a57600080fd5b8063956f5c78146200080457806395b5b196146200081b57806395d89b411462000832578063a00c8438146200083c57600080fd5b806381a1219111620001e857806381a1219114620007a457806389c32efb14620007bb5780638b4d26af14620007c55780638c160fb314620007ed57600080fd5b806376d258f8146200072e5780637eea43981462000767578063816bbc2e146200077e57600080fd5b80632ee3d92f11620003095780635231e24f116200029f5780635e5e33ef116200026a5780635e5e33ef14620006ca5780636ed71ede14620006e157806370a0823114620006eb57806372dcf679146200071757600080fd5b80635231e24f146200064c57806354441311146200067457806356c571cf146200068b5780635b74905414620006b357600080fd5b8063392e53cd11620002e0578063392e53cd14620005ff5780633c939dc1146200061457806340e9903b146200062b578063516885be146200063557600080fd5b80632ee3d92f14620005ab5780632f9ffaf614620005d3578063313ce56714620005ea57600080fd5b80630d97c9fa116200038b57806318160ddd116200035657806318160ddd146200055957806323b872dd146200056257806326949f9e146200057957806329db1be6146200058357600080fd5b80630d97c9fa14620004d457806312e667e914620004eb57806315c14a4a146200051157806316774ba0146200052a57600080fd5b8063095ea7b311620003cc578063095ea7b3146200046757806309da2c54146200048d5780630a3ee46114620004a45780630bfe176014620004bd57600080fd5b8062a28b3614620003f5578063037ec8c8146200043557806306fdde03146200044e575b600080fd5b6200041d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516200042c919062003fd0565b60405180910390f35b6200043f62000a43565b6040516200042c91906200404b565b6200045862000a9d565b6040516200042c9190620040c2565b6200047e6200047836600462004110565b62000b2e565b6040516200042c91906200415c565b6200041d6200049e3660046200416c565b62000b4a565b620004bb620004b5366004620041f1565b62000b89565b005b620004bb620004ce3660046200423f565b62000e9b565b620004bb620004e5366004620042ad565b62000f3a565b62000502620004fc36600462004301565b62000f90565b6040516200042c91906200433a565b6200051b62000fe9565b6040516200042c91906200436f565b6200047e6200053b3660046200416c565b6001600160a01b03166000908152600b602052604090205460ff1690565b60025462000502565b6200047e620005733660046200437f565b6200100d565b62000502600f5481565b6200041d7f000000000000000000000000000000000000000000000000000000000000000081565b6200051b7f000000000000000000000000000000000000000000000000000000000000000081565b620004bb620005e4366004620042ad565b62001037565b60055460ff166040516200042c9190620043c4565b6005546200047e90600160a81b900460ff1681565b620004bb62000625366004620043d4565b620010d4565b6200050260105481565b620004bb62000646366004620043fc565b6200135f565b6200041d7f000000000000000000000000000000000000000000000000000000000000000081565b620004bb6200068536600462004110565b62001412565b620005027f000000000000000000000000000000000000000000000000000000000000000081565b620004bb620006c436600462004110565b620014b4565b620004bb620006db36600462004422565b62001556565b6200050260065481565b62000502620006fc3660046200416c565b6001600160a01b031660009081526020819052604090205490565b620004bb620007283660046200416c565b62001574565b6200041d6200073f36600462004110565b6001600160a01b039182166000908152600d6020908152604080832093835292905220541690565b620005026200077836600462004447565b62001660565b620007956200078f36600462004422565b620016c5565b6040516200042c9190620044fc565b620004bb620007b5366004620041f1565b62001795565b6200043f620017e2565b620005027f000000000000000000000000000000000000000000000000000000000000000081565b6200047e620007fe3660046200416c565b6200183a565b620004bb620008153660046200416c565b62001891565b620004bb6200082c366004620043fc565b620018ab565b6200045862001960565b6200047e6200084d36600462004110565b62001971565b620004bb6200086436600462004422565b620019da565b6005546200041d9061010090046001600160a01b031681565b6200047e6200089436600462004110565b620019f4565b6200041d620008ab3660046200416c565b6001600160a01b039081166000908152600a60205260409020541690565b6011546001600160a01b03166200051b565b6200041d620008ec3660046200416c565b62001a04565b620004bb6200090336600462004529565b62001a52565b6200041d6200091a3660046200416c565b6001600160a01b039081166000908152600960205260409020541690565b6200041d62000949366004620043fc565b62001f18565b6200041d7f000000000000000000000000000000000000000000000000000000000000000081565b6200051b7f000000000000000000000000000000000000000000000000000000000000000081565b6200041d62001fd2565b6200050260075481565b6200050262002057565b62000502620009ce366004620045ad565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b620004bb62000a0a366004620042ad565b6200208b565b60016200047e565b620004bb62000a29366004620041f1565b6200217e565b6011546200051b906001600160a01b031681565b6060601280548060200260200160405190810160405280929190818152602001828054801562000a9357602002820191906000526020600020905b81548152602001906001019080831162000a7e575b5050505050905090565b60606003805462000aae90620045fc565b80601f016020809104026020016040519081016040528092919081815260200182805462000adc90620045fc565b801562000a935780601f1062000b015761010080835404028352916020019162000a93565b820191906000526020600020905b81548152906001019060200180831162000b0f57509395945050505050565b60003362000b3e818585620022ac565b60019150505b92915050565b600062000b448260405160200162000b63919062004656565b6040516020818303038152906040528051906020012062000b8362002057565b62002368565b3362000bea62000b9862001fd2565b6001600160a01b0316826001600160a01b0316147127b7363ca237b637b6b4ba32a6b0b933b4b760711b7f43616c6c6572206973206e6f74206f776e6572206f6620446f6c6f6d697465008462002377565b60055462000c2a90600160a81b900460ff161560008051602062005cd383398151915272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b620021cb565b62000c3462000fe9565b6001600160a01b0316638fae3be1306040518263ffffffff1660e01b815260040162000c61919062003fd0565b60206040518083038186803b15801562000c7a57600080fd5b505afa15801562000c8f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000cb591906200467a565b60065562000d8062000cc662000fe9565b6001600160a01b0316635ac7d17c6006546040518263ffffffff1660e01b815260040162000cf591906200433a565b60206040518083038186803b15801562000d0e57600080fd5b505afa15801562000d23573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d499190620046ac565b60008051602062005cd38339815191527f4d61726b65742063616e6e6f7420616c6c6f7720626f72726f77696e67000000620021cb565b61dead6000819052600a6020527f20677881080440a9b3c87e826370bb5d9c2f74efd4dede686d52d77a6a09f8bb5462000dc491906001600160a01b0316620023c6565b60005b8281101562000e1d5762000e0884848381811062000de95762000de9620046d1565b905060200201602081019062000e0091906200416c565b6001620025d9565b8062000e1481620046fd565b91505062000dc7565b506005805460ff60a81b1916600160a81b1790556040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c890600090a162000e96600654601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900155565b505050565b336000818152600b602052604090205462000eda9060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b03808516600090815260096020526040902054859162000f269116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b62000f3385858562002682565b5050505050565b60055462000f7590600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b3362000f8462000b9862001fd2565b62000e968383620025d9565b6001600160a01b0382166000908152600e602052604081208183600181111562000fbe5762000fbe6200471b565b600181111562000fd25762000fd26200471b565b815260200190815260200160002054905092915050565b7f000000000000000000000000000000000000000000000000000000000000000090565b6000336200101d858285620026f9565b6200102a85858562002751565b60019150505b9392505050565b336000818152600b6020526040902054620010769060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b038084166000908152600960205260409020548491620010c29116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce848462002c94565b50505050565b336000818152600960205260409020546200111c906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b6200114f60065484141560008051602062005cd38339815191526d125b9d985b1a59081b585c9ad95d60921b8662002cc2565b60408051600280825260608201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620011675790505090506040518060400160405280336001600160a01b03168152602001600081525081600081518110620011c657620011c6620046d1565b6020908102919091018101919091526040805180820182523360009081526009845291909120546001600160a01b03168152908101869052815182906001908110620012165762001216620046d1565b602090810291909101015260408051600280825260608201909252600091816020015b6200124362003ec1565b815260200190600190039081620012395750506040805160808101909152600181529091506200128d90600090879060208101838152602001600081526020018890523362002cf5565b81600081518110620012a357620012a3620046d1565b6020026020010181905250620012c960006001876000620012c360001990565b62002d60565b81600181518110620012df57620012df620046d1565b6020026020010181905250620012f462000fe9565b6001600160a01b031663a67a6a4583836040518363ffffffff1660e01b815260040162001323929190620049b4565b600060405180830381600087803b1580156200133e57600080fd5b505af115801562001353573d6000803e3d6000fd5b50505050505050505050565b33600081815260096020526040902054620013a7906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b33620013bf81620013b762000fe9565b858462002e82565b620010ce620013cd62000fe9565b828387600654604051806080016040528060011515815260200160006001811115620013fd57620013fd6200471b565b8152602001600081526020018a905262003080565b336000818152600b6020526040902054620014519060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b0380841660009081526009602052604090205484916200149d9116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce620014ab62000fe9565b33858762002e82565b336000818152600b6020526040902054620014f39060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b0380841660009081526009602052604090205484916200153f9116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce336200154e62000fe9565b858762002e82565b336200156562000b9862001fd2565b6200157082620031d5565b5050565b600554620015af90600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b33620015be62000b9862001fd2565b620016056001600160a01b038316151560008051602062005cd38339815191527f496e76616c6964207573657220696d706c656d656e746174696f6e0000000000620021cb565b600580546001600160a01b03848116610100818102610100600160a81b031985161790945560405193909204169182907fdc5a954098cef71f25bbe48bbd58cd5866495daacabf32492424363af66dd01890600090a3505050565b6001600160a01b0383166000908152600c602090815260408083208584529091528120818360018111156200169957620016996200471b565b6001811115620016ad57620016ad6200471b565b81526020019081526020016000205490509392505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526200173160075483111560008051602062005cd38339815191527f496e76616c6964207472616e7366657220637572736f72000000000000000000620021cb565b50600090815260086020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015493810193909352600301549081166060830152600160a01b900460ff161515608082015290565b33620017a462000b9862001fd2565b62000e968383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506200325992505050565b6060601380548060200260200160405190810160405280929190818152602001828054801562000a93576020028201919060005260206000209081548152602001906001019080831162000a7e575050505050905090565b6001600160a01b0381166000908152600e6020908152604080832083805290915281205415158062000b445750506001600160a01b03166000908152600e6020908152604080832060018452909152902054151590565b33620018a062000b9862001fd2565b6200157082620033c4565b33600081815260096020526040902054620018f3906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b336200190b6200190262000fe9565b82858462002e82565b620010ce6200191962000fe9565b8286846006546040518060800160405280600015158152602001600060018111156200194957620019496200471b565b8152602001600081526020018a9052600162003411565b60606004805462000aae90620045fc565b6001600160a01b0382166000908152600c602090815260408083208484528252808320838052909152812054151580620010305750506001600160a01b03919091166000908152600c602090815260408083209383529281528282206001835290522054151590565b33620019e962000b9862001fd2565b6200157082620035dc565b60003362000b3e81858562002751565b60055460009062001a4290600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b62000b448262003613565b919050565b336000818152600b602052604090205462001b6a9060ff168062001a8f57506001600160a01b038281166000908152600960205260409020541615155b8062001b295750816001600160a01b031662001aaa62000fe9565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801562001ae357600080fd5b505afa15801562001af8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b1e9190620049ea565b6001600160a01b0316145b74467265657a61626c655661756c74466163746f727960581b7f43616c6c6572206973206e6f74206120617574686f72697a65640000000000008462002377565b6001600160a01b03808716600090815260096020526040902054879162001bb69116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b6001600160a01b038088166000908152600d602090815260408083208a84529091529020541662001c3781158062001bff5750846001600160a01b0316826001600160a01b0316145b74467265657a61626c655661756c74466163746f727960581b7324b73b30b634b21037baba383aba103a37b5b2b760611b8762002377565b62001c5262001c4c3687900387018762004aab565b620037b4565b1562001d3f576001600160a01b0388166000908152600c602090815260408083208a845282528220908701359188600181111562001c945762001c946200471b565b600181111562001ca85762001ca86200471b565b8152602001908152602001600020600082825462001cc7919062004ad0565b90915550506001600160a01b0388166000908152600e602090815260408220908701359188600181111562001d005762001d006200471b565b600181111562001d145762001d146200471b565b8152602001908152602001600020600082825462001d33919062004ad0565b9091555062001e419050565b62001d5a62001d543687900387018762004aab565b620037cc565b1562001e41576001600160a01b0388166000908152600c602090815260408083208a845282528220908701359188600181111562001d9c5762001d9c6200471b565b600181111562001db05762001db06200471b565b8152602001908152602001600020600082825462001dcf919062004aea565b90915550506001600160a01b0388166000908152600e602090815260408220908701359188600181111562001e085762001e086200471b565b600181111562001e1c5762001e1c6200471b565b8152602001908152602001600020600082825462001e3b919062004aea565b90915550505b600062001e4f898962001971565b9050801562001e97576001600160a01b038981166000908152600d602090815260408083208c8452909152902080546001600160a01b03191691871691909117905562001ec9565b6001600160a01b0389166000908152600d602090815260408083208b8452909152902080546001600160a01b03191690555b87896001600160a01b03167f74d76887c0c124ce17a77f76f9256a35d4630551e4dd4977ab439e3dc368e5b28360405162001f0591906200415c565b60405180910390a3505050505050505050565b60055460009062001f5690600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b600062001f633362003613565b604051637d49eb4d60e11b81529091506001600160a01b0382169063fa93d69a9062001f96908790879060040162004b05565b600060405180830381600087803b15801562001fb157600080fd5b505af115801562001fc6573d6000803e3d6000fd5b50929695505050505050565b600062001fde62000fe9565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200201757600080fd5b505afa1580156200202c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620020529190620049ea565b905090565b6000604051806020016200206b9062003f38565b6020820181038252601f19601f8201166040525080519060200120905090565b336000818152600b6020526040902054620020ca9060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b038084166000908152600960205260409020548491620021169116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b604051630509ab1b60e31b81526001600160a01b0385169063284d58d890620021449086906004016200415c565b600060405180830381600087803b1580156200215f57600080fd5b505af115801562002174573d6000803e3d6000fd5b5050505050505050565b336200218d62000b9862001fd2565b62000e96838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250620037e392505050565b8262000e9657620021dc826200382a565b6101d160f51b620021ed836200382a565b604051602001620022019392919062004b5a565b60408051601f198184030181529082905262461bcd60e51b82526200222991600401620040c2565b60405180910390fd5b600083471015620022575760405162461bcd60e51b8152600401620022299062004bbf565b8151620022785760405162461bcd60e51b8152600401620022299062004c04565b8282516020840186f590506001600160a01b038116620010305760405162461bcd60e51b8152600401620022299062004c4b565b6001600160a01b038316620022d55760405162461bcd60e51b8152600401620022299062004ca1565b6001600160a01b038216620022fe5760405162461bcd60e51b8152600401620022299062004cf3565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906200235b9085906200433a565b60405180910390a3505050565b600062001030838330620038d1565b83620010ce5762002388836200382a565b6101d160f51b62002399846200382a565b61080f60f21b620023aa85620038fa565b60405162002201959493929190601f60f91b9060200162004d16565b6001600160a01b03821615801590620023e757506001600160a01b03811615155b620023f657620023f662004d80565b60405163189acdbd60e31b81526001600160a01b0382169063c4d66de8906200242490859060040162003fd0565b600060405180830381600087803b1580156200243f57600080fd5b505af115801562002454573d6000803e3d6000fd5b505060405163f697ae9960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063f697ae999150620024a990849060019060040162004d96565b600060405180830381600087803b158015620024c457600080fd5b505af1158015620024d9573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f68ebbbd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200253757600080fd5b505afa1580156200254c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002572919062004dcd565b6001600160a01b03166305c4fdf983836040518363ffffffff1660e01b8152600401620025a192919062004df2565b600060405180830381600087803b158015620025bc57600080fd5b505af1158015620025d1573d6000803e3d6000fd5b505050505050565b620026206001600160a01b038316151560008051602062005cd38339815191527f496e76616c696420746f6b656e20636f6e766572746572000000000000000000620021cb565b6001600160a01b0382166000818152600b602052604090819020805460ff1916841515179055517f1a2aaf8fb443c30344ac3e041f678060eb802aa3e68057d31682b9909d5693a490620026769084906200415c565b60405180910390a25050565b6200268f83600162002c94565b620026a6836200269e62000fe9565b838662002e82565b62000e96620026b462000fe9565b848585600654604051806080016040528060011515815260200160006001811115620026e457620026e46200471b565b81526020016000815260200188905262003080565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205481811015620027425760405162461bcd60e51b8152600401620022299062004e46565b620010ce8484848403620022ac565b33620027b26200276062000fe9565b6001600160a01b0316826001600160a01b0316147127b7363ca237b637b6b4ba32a6b0b933b4b760711b7f4f6e6c7920446f6c6f6d6974652063616e2063616c6c2066756e6374696f6e008462002377565b620027f96001600160a01b038516151560008051602062005cd38339815191527f5472616e736665722066726f6d20746865207a65726f20616464726573730000620021cb565b620028406001600160a01b038416151560008051602062005cd38339815191527f5472616e7366657220746f20746865207a65726f206164647265737300000000620021cb565b60006200284c62000fe9565b9050620028bb816001600160a01b0316866001600160a01b03161480620028845750816001600160a01b0316856001600160a01b0316145b60008051602062005cd38339815191527f66726f6d2f746f206d75737420657120446f6c6f6d6974654d617267696e0000620021cb565b600754600081815260086020908152604091829020825160a08101845281546001600160a01b0390811680835260018401548216948301949094526002830154948201949094526003909101548084166060830152600160a01b900460ff161515608082015291620029bf919089161480156200294d5750866001600160a01b031682602001516001600160a01b0316145b80156200295d5750858260400151145b801562002988575060608201516001600160a01b039081166000908152600960205260409020541615155b60008051602062005cd38339815191527f496e76616c696420717565756564207472616e73666572000000000000000000620021cb565b62002a0181608001511560008051602062005cd38339815191527f5472616e7366657220616c7265616479206578656375746564000000000000008562002cc2565b6000828152600860205260409020600301805460ff60a01b1916600160a01b1790556001600160a01b03868116908416141562002b65576001600160a01b038088166000908152600960205260409020541662002ac6811580159062002a7c575082606001516001600160a01b0316896001600160a01b0316145b8062002aa057506001600160a01b0389166000908152600b602052604090205460ff165b60008051602062005cd38339815191526b496e76616c69642066726f6d60a01b620021cb565b81606001516001600160a01b0316638ddab4e560006001600160a01b0316836001600160a01b0316141562002afc578962002afe565b825b886040518363ffffffff1660e01b815260040162002b1e92919062004e58565b600060405180830381600087803b15801562002b3957600080fd5b505af115801562002b4e573d6000803e3d6000fd5b5050505062002b5e878762003a5a565b5062002c8b565b826001600160a01b0316876001600160a01b03161462002b895762002b8962004d80565b6001600160a01b038087166000908152600960205260409020541662002bf38115158062002bcf57506001600160a01b0388166000908152600b602052604090205460ff165b60008051602062005cd383398151915269496e76616c696420746f60b01b620021cb565b81606001516001600160a01b031663797b512560006001600160a01b0316836001600160a01b0316141562002c29578862002c2b565b825b886040518363ffffffff1660e01b815260040162002c4b92919062004e58565b600060405180830381600087803b15801562002c6657600080fd5b505af115801562002c7b573d6000803e3d6000fd5b5050505062002174888762003af7565b50505050505050565b60405163065f3c3360e41b81526001600160a01b038316906365f3c33090620025a19084906004016200415c565b83620010ce5762002cd3836200382a565b6101d160f51b62002ce4846200382a565b61080f60f21b620023aa8562003bb6565b62002cff62003ec1565b6040805161010081019091528060005b815260200186815260200184815260200185815260200160008152602001836001600160a01b0316815260200160008152602001604051806020016040528060008152508152509050949350505050565b62002d6a62003ec1565b62002d97604080516080810190915260008082526020820190815260200160008152602001600081525090565b60001983141562002de457604051806080016040528060001515815260200185600181111562002dcb5762002dcb6200471b565b8152602001600181526020016000815250905062002e1f565b604051806080016040528060001515815260200185600181111562002e0d5762002e0d6200471b565b81526020016000815260200184905290505b60408051610100810190915280600281526020018881526020018281526020018681526020016000815260200160006001600160a01b03168152602001878152602001604051806020016040528060008152508152509150505b95945050505050565b600754600090815260086020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015493810193909352600301549081166060830152600160a01b900460ff161580156080830181905262002f11575062002ef862000fe9565b6001600160a01b031681602001516001600160a01b0316145b1562002f2d5762002f2d816060015182602001516000620022ac565b816001600160a01b0316856001600160a01b031614801562002f69575062002f5462000fe9565b6001600160a01b0316846001600160a01b0316145b1562002f7c5762002f7c828585620022ac565b60016007600082825462002f91919062004aea565b90915550506040805160a0810182526001600160a01b038088168252868116602080840191825283850188815287841660608601908152600060808701818152600780548352600890955290889020965187549087166001600160a01b03199182161788559451600188018054918816919096161790945590516002860155516003909401805492511515600160a01b026001600160a81b031990931694909316939093171790555490517f41f436ede2f45a36c2a15333e202b31f7040c914a78d7eb62d6f7caa6414a756906200307190889088908890889062004e68565b60405180910390a25050505050565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620030975790505090506040518060400160405280876001600160a01b031681526020018581525081600081518110620030f557620030f5620046d1565b6020908102919091010152604080516001808252818301909252600091816020015b6200312162003ec1565b8152602001906001900390816200311757905050905062003146600085858962002cf5565b816000815181106200315c576200315c620046d1565b602090810291909101015260405163a67a6a4560e01b81526001600160a01b0389169063a67a6a4590620031979085908590600401620049b4565b600060405180830381600087803b158015620031b257600080fd5b505af1158015620031c7573d6000803e3d6000fd5b505050505050505050505050565b62003217600f5482111574467265657a61626c655661756c74466163746f727960581b74496e76616c696420657865637574696f6e2066656560581b620021cb565b60108190556040517f34243bbc545b7abbfc8001dc34d1ae65eef90e6bbccd634ddf433247734c9d7a906200324e9083906200433a565b60405180910390a150565b805160005b8181101562003370576200335b6200327562000fe9565b6001600160a01b0316635ac7d17c858481518110620032985762003298620046d1565b60200260200101516040518263ffffffff1660e01b8152600401620032be91906200433a565b60206040518083038186803b158015620032d757600080fd5b505afa158015620032ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620033129190620046ac565b157f53696d706c6549736f6c6174696f6e4d6f64655661756c74466163746f7279007f4d61726b65742063616e6e6f7420626520636c6f73696e670000000000000000620021cb565b806200336781620046fd565b9150506200325e565b5081516200338690601290602085019062003f46565b507fe394f8a439e499167cfe98e403f35fc54387abe3f9db4e5c0632c8ec8e9b193482604051620033b891906200404b565b60405180910390a15050565b601180546001600160a01b0319166001600160a01b0383161790556040517fd61d47c7844ec2c99fa7e2b21baaacf489203aa183ed706df8a3f169acd7b38e906200324e90839062003fd0565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620034285790505090506040518060400160405280886001600160a01b031681526020018781525081600081518110620034865762003486620046d1565b6020908102919091010152604080516001808252818301909252600091816020015b620034b262003ec1565b815260200190600190039081620034a8579050509050620034d7600086868962003cda565b81600081518110620034ed57620034ed620046d1565b602090810291909101015260405163a67a6a4560e01b81526001600160a01b038a169063a67a6a4590620035289085908590600401620049b4565b600060405180830381600087803b1580156200354357600080fd5b505af115801562003558573d6000803e3d6000fd5b506000925062003566915050565b8360038111156200357b576200357b6200471b565b14806200359c575060018360038111156200359a576200359a6200471b565b145b15620035d157620035d18983600081518110620035bd57620035bd620046d1565b602002602001015160000151898862003cf9565b505050505050505050565b600f8190556040517f4d4feaf092299649d71328c4c35afb429aba48782a3f1078b3295a48322ee8b5906200324e9083906200433a565b60006200364e6001600160a01b038316151560008051602062005cd38339815191526e125b9d985b1a59081858d8dbdd5b9d608a1b620021cb565b6001600160a01b038281166000908152600a60205260409020546200369d91161560008051602062005cd3833981519152735661756c7420616c72656164792065786973747360601b620021cb565b6000620036f9600084604051602001620036b8919062004656565b6040516020818303038152906040528051906020012060405180602001620036e09062003f38565b601f1982820381018352601f9091011660405262002232565b90506001600160a01b03811662003714576200371462004d80565b826001600160a01b03167f5d9c31ffa0fecffd7cf379989a3c7af252f0335e0d2a1320b55245912c781f53826040516200374f919062003fd0565b60405180910390a26001600160a01b03808216600081815260096020908152604080832080549589166001600160a01b03199687168117909155808452600a909252909120805490931690911790915561dead1462000b445762000b448382620023c6565b805160009015801562000b4457505060200151151590565b8051600090801562000b4457505060200151151590565b8051620037f890601390602084019062003f46565b507f3ef7cb7777c10315913a05aed0c0c3f1b40e11bbe9df01be0a5d1f71db93faff816040516200324e91906200404b565b606060008260405160200162003841919062004ea5565b60408051601f19818403018152919052905060205b8015620038b65780620038698162004ebc565b915050818181518110620038815762003881620046d1565b01602001516001600160f81b03191615620038b0576000620038a582600162004aea565b835250909392505050565b62003856565b5060408051600080825260208201909252905b509392505050565b6000604051836040820152846020820152828152600b810160ff81536055902095945050505050565b60408051602a80825260608281019093526001600160a01b03841691600091602082018180368337019050509050603060f81b81600081518110620039435762003943620046d1565b60200101906001600160f81b031916908160001a905350607860f81b81600181518110620039755762003975620046d1565b60200101906001600160f81b031916908160001a90535060005b6014811015620038c9576000620039a882600262004ed6565b9050620039b8600f851662003dfd565b83620039c683602962004ad0565b81518110620039d957620039d9620046d1565b60200101906001600160f81b031916908160001a905350600484901c935062003a05600f851662003dfd565b8362003a1383602862004ad0565b8151811062003a265762003a26620046d1565b60200101906001600160f81b031916908160001a9053505060049290921c918062003a5181620046fd565b9150506200398f565b6001600160a01b03821662003a835760405162461bcd60e51b8152600401620022299062004f2d565b806002600082825462003a97919062004aea565b90915550506001600160a01b038216600081815260208190526040808220805485019055517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9062003aeb9085906200433a565b60405180910390a35050565b6001600160a01b03821662003b205760405162461bcd60e51b8152600401620022299062004f7e565b6001600160a01b0382166000908152602081905260409020548181101562003b5c5760405162461bcd60e51b8152600401620022299062004fd0565b6001600160a01b0383166000818152602081905260408082208585039055600280548690039055519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906200235b9086906200433a565b60608162003bdb5750506040805180820190915260018152600360fc1b602082015290565b8160005b811562003c0b578062003bf281620046fd565b915062003c039050600a8362004ff8565b915062003bdf565b60008167ffffffffffffffff81111562003c295762003c2962004731565b6040519080825280601f01601f19166020018201604052801562003c54576020820181803683370190505b508593509050815b801562003cd1578062003c6f8162004ebc565b915062003c809050600a856200500f565b62003c8d90603062004aea565b60f81b82828151811062003ca55762003ca5620046d1565b60200101906001600160f81b031916908160001a90535062003cc9600a8562004ff8565b935062003c5c565b50949350505050565b62003ce462003ec1565b60408051610100810190915280600162002d0f565b6040805180820182526001600160a01b0380861682526020820185905291516311f46d4f60e21b81529091600091908716906347d1b53c9062003d43908590879060040162005026565b604080518083038186803b15801562003d5b57600080fd5b505afa15801562003d70573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003d969190620050a8565b9050620025d162003da78262003e2c565b8062003dbe575060208201516001600160801b0316155b7020b1b1b7bab73a2130b630b731b2a634b160791b7f6163636f756e742063616e6e6f7420676f206e6567617469766500000000000088888862003e4c565b6000600a82101562003e1f5762003e1660308362004aea565b60f81b92915050565b62003e1660578362004aea565b8051600090801562000b44575050602001516001600160801b0316151590565b85620025d15762003e5d856200382a565b6101d160f51b62003e6e866200382a565b61080f60f21b62003e7f87620038fa565b61016160f51b62003e908862003bb6565b61016160f51b62003ea18962003bb6565b6040516200220199989796959493929190601f60f91b90602001620050cd565b60408051610100810182526000808252602082015290810162003f06604080516080810190915260008082526020820190815260200160008152602001600081525090565b8152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b610b37806200517c83390190565b82805482825590600052602060002090810192821562003f84579160200282015b8281111562003f8457825182559160200191906001019062003f67565b5062003f9292915062003f96565b5090565b5b8082111562003f92576000815560010162003f97565b60006001600160a01b03821662000b44565b62003fca8162003fad565b82525050565b6020810162000b44828462003fbf565b8062003fca565b600062003ff5838362003fe0565b505060200190565b600062004008825190565b80845260209384019383018060005b83811015620040405781516200402e888262003fe7565b97506020830192505060010162004017565b509495945050505050565b6020808252810162001030818462003ffd565b60005b838110156200407b57818101518382015260200162004061565b83811115620010ce5750506000910152565b600062004098825190565b808452602084019350620040b18185602086016200405e565b601f01601f19169290920192915050565b602080825281016200103081846200408d565b620040e08162003fad565b8114620040ec57600080fd5b50565b803562000b4481620040d5565b80620040e0565b803562000b4481620040fc565b60008060408385031215620041285762004128600080fd5b6000620041368585620040ef565b9250506020620041498582860162004103565b9150509250929050565b80151562003fca565b6020810162000b44828462004153565b600060208284031215620041835762004183600080fd5b6000620041918484620040ef565b949350505050565b60008083601f840112620041b057620041b0600080fd5b50813567ffffffffffffffff811115620041cd57620041cd600080fd5b602083019150836020820283011115620041ea57620041ea600080fd5b9250929050565b60008060208385031215620042095762004209600080fd5b823567ffffffffffffffff811115620042255762004225600080fd5b620042338582860162004199565b92509250509250929050565b600080600060608486031215620042595762004259600080fd5b6000620042678686620040ef565b93505060206200427a8682870162004103565b92505060406200428d8682870162004103565b9150509250925092565b801515620040e0565b803562000b448162004297565b60008060408385031215620042c557620042c5600080fd5b6000620042d38585620040ef565b92505060206200414985828601620042a0565b60028110620040ec57600080fd5b803562000b4481620042e6565b60008060408385031215620043195762004319600080fd5b6000620043278585620040ef565b92505060206200414985828601620042f4565b6020810162000b44828462003fe0565b600062000b448262003fad565b600062000b44826200434a565b62003fca8162004357565b6020810162000b44828462004364565b600080600060608486031215620043995762004399600080fd5b6000620043a78686620040ef565b93505060206200427a86828701620040ef565b60ff811662003fca565b6020810162000b448284620043ba565b600080600060608486031215620043ee57620043ee600080fd5b600062004267868662004103565b60008060408385031215620044145762004414600080fd5b600062004136858562004103565b600060208284031215620044395762004439600080fd5b600062004191848462004103565b600080600060608486031215620044615762004461600080fd5b60006200446f8686620040ef565b9350506020620044828682870162004103565b92505060406200428d86828701620042f4565b805160a0830190620044a8848262003fbf565b506020820151620044bd602085018262003fbf565b506040820151620044d2604085018262003fe0565b506060820151620044e7606085018262003fbf565b506080820151620010ce608085018262004153565b60a0810162000b44828462004495565b600060408284031215620045235762004523600080fd5b50919050565b600080600080600060c08688031215620045465762004546600080fd5b6000620045548888620040ef565b9550506020620045678882890162004103565b94505060406200457a88828901620042f4565b93505060606200458d888289016200450c565b92505060a0620045a088828901620040ef565b9150509295509295909350565b60008060408385031215620045c557620045c5600080fd5b6000620045d38585620040ef565b92505060206200414985828601620040ef565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200461157607f821691505b60208210811415620045235762004523620045e6565b600062000b448260601b90565b600062000b448262004627565b62003fca620046508262003fad565b62004634565b600062004664828462004641565b50601401919050565b805162000b4481620040fc565b600060208284031215620046915762004691600080fd5b60006200419184846200466d565b805162000b448162004297565b600060208284031215620046c357620046c3600080fd5b60006200419184846200469f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620047145762004714620046e7565b5060010190565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b805160408301906200475a848262003fbf565b506020820151620010ce602085018262003fe0565b60006200477d838362004747565b505060400190565b600062004790825190565b80845260209384019383018060005b8381101562004040578151620047b688826200476f565b9750602083019250506001016200479f565b60098110620040ec57620040ec6200471b565b8062001a4d81620047c8565b600062000b4482620047db565b62003fca81620047e7565b60028110620040ec57620040ec6200471b565b8062001a4d81620047ff565b600062000b448262004812565b62003fca816200481e565b8051608083019062004849848262004153565b5060208201516200485e60208501826200482b565b5060408201516200487360408501826200482b565b506060820151620010ce606085018262003fe0565b80516000906101608401906200489f8582620047f4565b506020830151620048b4602086018262003fe0565b506040830151620048c9604086018262004836565b506060830151620048de60c086018262003fe0565b506080830151620048f360e086018262003fe0565b5060a08301516200490961010086018262003fbf565b5060c08301516200491f61012086018262003fe0565b5060e083015184820361014086015262002e7982826200408d565b600062001030838362004888565b600062004953825190565b808452602084019350836020820285016200496e8560200190565b8060005b85811015620049a757848403895281516200498e85826200493a565b94506020830160209a909a019992505060010162004972565b5091979650505050505050565b60408082528101620049c7818562004785565b9050818103602083015262004191818462004948565b805162000b4481620040d5565b60006020828403121562004a015762004a01600080fd5b6000620041918484620049dd565b601f19601f830116810181811067ffffffffffffffff8211171562004a385762004a3862004731565b6040525050565b600062004a4b60405190565b905062001a4d828262004a0f565b60006040828403121562004a705762004a70600080fd5b62004a7c604062004a3f565b9050600062004a8c8484620042a0565b825250602062004a9f8484830162004103565b60208301525092915050565b60006040828403121562004ac25762004ac2600080fd5b600062004191848462004a59565b60008282101562004ae55762004ae5620046e7565b500390565b6000821982111562004b005762004b00620046e7565b500190565b6040810162004b15828562003fe0565b62001030602083018462003fe0565b600062004b2f825190565b62004b3f8185602086016200405e565b9290920192915050565b6001600160f01b0319811662003fca565b600062004b68828662004b24565b915062004b76828562004b49565b60028201915062002e79828462004b24565b601d81526000602082017f437265617465323a20696e73756666696369656e742062616c616e6365000000815291505b5060200190565b6020808252810162000b448162004b88565b60208082527f437265617465323a2062797465636f6465206c656e677468206973207a65726f9101908152600062004bb8565b6020808252810162000b448162004bd1565b601981526000602082017f437265617465323a204661696c6564206f6e206465706c6f79000000000000008152915062004bb8565b6020808252810162000b448162004c16565b602481526000602082017f45524332303a20417070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015291505b5060400190565b6020808252810162000b448162004c5d565b602281526000602082017f45524332303a20417070726f766520746f20746865207a65726f206164647265815261737360f01b6020820152915062004c9a565b6020808252810162000b448162004cb3565b6001600160f81b0319811662003fca565b600062004d24828962004b24565b915062004d32828862004b49565b60028201915062004d44828762004b24565b915062004d52828662004b49565b60028201915062004d64828562004b24565b915062004d72828462004d05565b506001019695505050505050565b634e487b7160e01b600052600160045260246000fd5b6040810162004da6828562003fbf565b62001030602083018462004153565b620040e0816200434a565b805162000b448162004db5565b60006020828403121562004de45762004de4600080fd5b600062004191848462004dc0565b6040810162004e02828562003fbf565b62001030602083018462003fbf565b601d81526000602082017f45524332303a20496e73756666696369656e7420616c6c6f77616e63650000008152915062004bb8565b6020808252810162000b448162004e11565b6040810162004b15828562003fbf565b6080810162004e78828762003fbf565b62004e87602083018662003fbf565b62004e96604083018562003fe0565b62002e79606083018462003fbf565b600062004eb3828462003fe0565b50602001919050565b60008162004ece5762004ece620046e7565b506000190190565b600081600019048311821515161562004ef35762004ef3620046e7565b500290565b601f81526000602082017f45524332303a204d696e7420746f20746865207a65726f2061646472657373008152915062004bb8565b6020808252810162000b448162004ef8565b602181526000602082017f45524332303a204275726e2066726f6d20746865207a65726f206164647265738152607360f81b6020820152915062004c9a565b6020808252810162000b448162004f3f565b602281526000602082017f45524332303a204275726e20616d6f756e7420657863656564732062616c616e815261636560f01b6020820152915062004c9a565b6020808252810162000b448162004f90565b634e487b7160e01b600052601260045260246000fd5b6000826200500a576200500a62004fe2565b500490565b60008262005021576200502162004fe2565b500690565b6060810162005036828562004747565b62001030604083018462003fe0565b6001600160801b038116620040e0565b805162000b448162005045565b600060408284031215620050795762005079600080fd5b62005085604062004a3f565b905060006200509584846200469f565b825250602062004a9f8484830162005055565b600060408284031215620050bf57620050bf600080fd5b600062004191848462005062565b6000620050db828d62004b24565b9150620050e9828c62004b49565b600282019150620050fb828b62004b24565b915062005109828a62004b49565b6002820191506200511b828962004b24565b915062005129828862004b49565b6002820191506200513b828762004b24565b915062005149828662004b49565b6002820191506200515b828562004b24565b915062005169828462004d05565b506001019a995050505050505050505056fe608060405234801561001057600080fd5b5061004461003f60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef361005f565b339055565b610076565b634e487b7160e01b600052601160045260246000fd5b60008282101561007157610071610049565b500390565b610ab2806100856000396000f3fe60806040526004361061004e5760003560e01c8063392e53cd146100b45780635c60da1b146100df5780638da5cb5b14610101578063c4d66de814610116578063d8a06f7314610136576100a9565b366100a95761009761005e61014b565b7f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e139bdd081a5b9a5d1a585b1a5e9959608a1b610187565b6100a76100a26101ea565b610269565b005b61009761005e61014b565b3480156100c057600080fd5b506100c961014b565b6040516100d6919061077d565b60405180910390f35b3480156100eb57600080fd5b506100f46101ea565b6040516100d691906107a5565b34801561010d57600080fd5b506100f461028d565b34801561012257600080fd5b506100a76101313660046107d2565b6102bd565b34801561014257600080fd5b506100f4610473565b600061017f61017b60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b5490565b600114905090565b826101e557610195826104a3565b6101d160f51b6101a4836104a3565b6040516020016101b693929190610886565b60408051601f198184030181529082905262461bcd60e51b82526101dc916004016108e9565b60405180910390fd5b505050565b60006101f4610473565b6001600160a01b031663a6e7d83f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561022c57600080fd5b505afa158015610240573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610264919061090c565b905090565b3660008037600080366000845af43d6000803e808015610288573d6000f35b3d6000fd5b600061026461017b60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b6103066102c861014b565b157f49736f6c6174696f6e4d6f64655570677261646561626c6550726f787900000072105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b610187565b6103d130610312610473565b6001600160a01b031663b01f61e1846040518263ffffffff1660e01b815260040161033d91906107a5565b60206040518083038186803b15801561035557600080fd5b505afa158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d919061090c565b6001600160a01b0316147f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e125b9d985b1a59081858d8dbdd5b9d608a1b8461053e565b6104046103ff60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b829055565b61043b61040f6101ea565b6040516104279063204a7f0760e21b9060200161093d565b60405160208183030381529060405261058a565b5061047061046a60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b60019055565b50565b600061026461017b60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef3610811565b60606000826040516020016104b89190610958565b60408051601f19818403018152919052905060205b801561052357806104dd8161096d565b9150508181815181106104f2576104f2610984565b01602001516001600160f81b0319161561051e57600061051382600161099a565b835250909392505050565b6104cd565b5060408051600080825260208201909252905b509392505050565b836105845761054c836104a3565b6101d160f51b61055b846104a3565b61080f60f21b61056a85610603565b6040516101b6959493929190601f60f91b906020016109c2565b50505050565b6060600080846001600160a01b0316846040516105a79190610a20565b600060405180830381855af49150503d80600081146105e2576040519150601f19603f3d011682016040523d82523d6000602084013e6105e7565b606091505b5091509150816105f9576105f9610a2c565b9150505b92915050565b60408051602a80825260608281019093526001600160a01b03841691600091602082018180368337019050509050603060f81b8160008151811061064957610649610984565b60200101906001600160f81b031916908160001a905350607860f81b8160018151811061067857610678610984565b60200101906001600160f81b031916908160001a90535060005b60148110156105365760006106a8826002610a42565b90506106b6600f8516610749565b836106c2836029610811565b815181106106d2576106d2610984565b60200101906001600160f81b031916908160001a905350600484901c93506106fc600f8516610749565b83610708836028610811565b8151811061071857610718610984565b60200101906001600160f81b031916908160001a9053505060049290921c918061074181610a61565b915050610692565b6000600a8210156107685761075f60308361099a565b60f81b92915050565b61075f60578361099a565b8015155b82525050565b602081016105fd8284610773565b60006001600160a01b0382166105fd565b6107778161078b565b602081016105fd828461079c565b6107bc8161078b565b811461047057600080fd5b80356105fd816107b3565b6000602082840312156107e7576107e7600080fd5b60006107f384846107c7565b949350505050565b634e487b7160e01b600052601160045260246000fd5b600082821015610823576108236107fb565b500390565b60005b8381101561084357818101518382015260200161082b565b838111156105845750506000910152565b600061085e825190565b61086c818560208601610828565b9290920192915050565b6001600160f01b03198116610777565b60006108928286610854565b915061089e8285610876565b6002820191506108ae8284610854565b95945050505050565b60006108c1825190565b8084526020840193506108d8818560208601610828565b601f01601f19169290920192915050565b602080825281016108fa81846108b7565b9392505050565b80516105fd816107b3565b60006020828403121561092157610921600080fd5b60006107f38484610901565b6001600160e01b03198116610777565b6000610949828461092d565b50600401919050565b80610777565b60006109648284610952565b50602001919050565b60008161097c5761097c6107fb565b506000190190565b634e487b7160e01b600052603260045260246000fd5b600082198211156109ad576109ad6107fb565b500190565b6001600160f81b03198116610777565b60006109ce8289610854565b91506109da8288610876565b6002820191506109ea8287610854565b91506109f68286610876565b600282019150610a068285610854565b9150610a1282846109b2565b506001019695505050505050565b60006108fa8284610854565b634e487b7160e01b600052600160045260246000fd5b6000816000190483118215151615610a5c57610a5c6107fb565b500290565b6000600019821415610a7557610a756107fb565b506001019056fea264697066735822122075a44ae10adcae9b874b7ea4e5b0292a10ae4024647e2db8988dc6bce3251ef064736f6c6343000809003343616c6c6572206973206e6f74206120746f6b656e20636f6e7665727465720049736f6c6174696f6e4d6f64655661756c74466163746f727900000000000000a2646970667358221220c6b8b3bc2e2aba99020c6dac720af0f5bf8df79bb8099efa144df162112dc85f64736f6c63430008090033608060405234801561001057600080fd5b5061004461003f60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef361005f565b339055565b610076565b634e487b7160e01b600052601160045260246000fd5b60008282101561007157610071610049565b500390565b610ab2806100856000396000f3fe60806040526004361061004e5760003560e01c8063392e53cd146100b45780635c60da1b146100df5780638da5cb5b14610101578063c4d66de814610116578063d8a06f7314610136576100a9565b366100a95761009761005e61014b565b7f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e139bdd081a5b9a5d1a585b1a5e9959608a1b610187565b6100a76100a26101ea565b610269565b005b61009761005e61014b565b3480156100c057600080fd5b506100c961014b565b6040516100d6919061077d565b60405180910390f35b3480156100eb57600080fd5b506100f46101ea565b6040516100d691906107a5565b34801561010d57600080fd5b506100f461028d565b34801561012257600080fd5b506100a76101313660046107d2565b6102bd565b34801561014257600080fd5b506100f4610473565b600061017f61017b60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b5490565b600114905090565b826101e557610195826104a3565b6101d160f51b6101a4836104a3565b6040516020016101b693929190610886565b60408051601f198184030181529082905262461bcd60e51b82526101dc916004016108e9565b60405180910390fd5b505050565b60006101f4610473565b6001600160a01b031663a6e7d83f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561022c57600080fd5b505afa158015610240573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610264919061090c565b905090565b3660008037600080366000845af43d6000803e808015610288573d6000f35b3d6000fd5b600061026461017b60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b6103066102c861014b565b157f49736f6c6174696f6e4d6f64655570677261646561626c6550726f787900000072105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b610187565b6103d130610312610473565b6001600160a01b031663b01f61e1846040518263ffffffff1660e01b815260040161033d91906107a5565b60206040518083038186803b15801561035557600080fd5b505afa158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d919061090c565b6001600160a01b0316147f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e125b9d985b1a59081858d8dbdd5b9d608a1b8461053e565b6104046103ff60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b829055565b61043b61040f6101ea565b6040516104279063204a7f0760e21b9060200161093d565b60405160208183030381529060405261058a565b5061047061046a60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b60019055565b50565b600061026461017b60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef3610811565b60606000826040516020016104b89190610958565b60408051601f19818403018152919052905060205b801561052357806104dd8161096d565b9150508181815181106104f2576104f2610984565b01602001516001600160f81b0319161561051e57600061051382600161099a565b835250909392505050565b6104cd565b5060408051600080825260208201909252905b509392505050565b836105845761054c836104a3565b6101d160f51b61055b846104a3565b61080f60f21b61056a85610603565b6040516101b6959493929190601f60f91b906020016109c2565b50505050565b6060600080846001600160a01b0316846040516105a79190610a20565b600060405180830381855af49150503d80600081146105e2576040519150601f19603f3d011682016040523d82523d6000602084013e6105e7565b606091505b5091509150816105f9576105f9610a2c565b9150505b92915050565b60408051602a80825260608281019093526001600160a01b03841691600091602082018180368337019050509050603060f81b8160008151811061064957610649610984565b60200101906001600160f81b031916908160001a905350607860f81b8160018151811061067857610678610984565b60200101906001600160f81b031916908160001a90535060005b60148110156105365760006106a8826002610a42565b90506106b6600f8516610749565b836106c2836029610811565b815181106106d2576106d2610984565b60200101906001600160f81b031916908160001a905350600484901c93506106fc600f8516610749565b83610708836028610811565b8151811061071857610718610984565b60200101906001600160f81b031916908160001a9053505060049290921c918061074181610a61565b915050610692565b6000600a8210156107685761075f60308361099a565b60f81b92915050565b61075f60578361099a565b8015155b82525050565b602081016105fd8284610773565b60006001600160a01b0382166105fd565b6107778161078b565b602081016105fd828461079c565b6107bc8161078b565b811461047057600080fd5b80356105fd816107b3565b6000602082840312156107e7576107e7600080fd5b60006107f384846107c7565b949350505050565b634e487b7160e01b600052601160045260246000fd5b600082821015610823576108236107fb565b500390565b60005b8381101561084357818101518382015260200161082b565b838111156105845750506000910152565b600061085e825190565b61086c818560208601610828565b9290920192915050565b6001600160f01b03198116610777565b60006108928286610854565b915061089e8285610876565b6002820191506108ae8284610854565b95945050505050565b60006108c1825190565b8084526020840193506108d8818560208601610828565b601f01601f19169290920192915050565b602080825281016108fa81846108b7565b9392505050565b80516105fd816107b3565b60006020828403121561092157610921600080fd5b60006107f38484610901565b6001600160e01b03198116610777565b6000610949828461092d565b50600401919050565b80610777565b60006109648284610952565b50602001919050565b60008161097c5761097c6107fb565b506000190190565b634e487b7160e01b600052603260045260246000fd5b600082198211156109ad576109ad6107fb565b500190565b6001600160f81b03198116610777565b60006109ce8289610854565b91506109da8288610876565b6002820191506109ea8287610854565b91506109f68286610876565b600282019150610a068285610854565b9150610a1282846109b2565b506001019695505050505050565b60006108fa8284610854565b634e487b7160e01b600052600160045260246000fd5b6000816000190483118215151615610a5c57610a5c6107fb565b500290565b6000600019821415610a7557610a756107fb565b506001019056fea264697066735822122075a44ae10adcae9b874b7ea4e5b0292a10ae4024647e2db8988dc6bce3251ef064736f6c634300080900330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000adc1a8ad79e55ab9e8569e497775b63e737316a800000000000000000000000000000000000000000000000000038d7ea4c680000000000000000000000000001cbba6346f110c8a5ea739ef2d1eb182990e4eb2000000000000000000000000ba5ddd1f9d7f570dc94a51479a000e3bce967196000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000ba5ddd1f9d7f570dc94a51479a000e3bce967196000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000038e49a617305101216ec6306e3a18065d14bf3a700000000000000000000000094d1817ff561aeb637a42393f38c3efabf769e8f0000000000000000000000002a059d6d682e5fb1226eb8bc2977b512698c24040000000000000000000000006bd780e7fdf01d77e4d475c821f1e7ae05409072000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000005
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620003f05760003560e01c806376d258f81162000211578063b1a1e3bf1162000125578063cbffd92111620000bb578063de87cac61162000086578063de87cac614620009f9578063ed4e3a351462000a10578063f8a41f4f1462000a18578063fb82f8ee1462000a2f57600080fd5b8063cbffd921146200099f578063d143d59114620009a9578063d3f5f06214620009b3578063dd62ed3e14620009bd57600080fd5b8063bc08373211620000fc578063bc0837321462000909578063c1090d5a1462000938578063c11201f7146200094f578063c6d20c85146200097757600080fd5b8063b1a1e3bf14620008c9578063b4bd6f4614620008db578063bc01089914620008f257600080fd5b8063956f5c7811620001a7578063a269bfb71162000172578063a269bfb71462000853578063a6e7d83f146200086a578063a9059cbb1462000883578063b01f61e1146200089a57600080fd5b8063956f5c78146200080457806395b5b196146200081b57806395d89b411462000832578063a00c8438146200083c57600080fd5b806381a1219111620001e857806381a1219114620007a457806389c32efb14620007bb5780638b4d26af14620007c55780638c160fb314620007ed57600080fd5b806376d258f8146200072e5780637eea43981462000767578063816bbc2e146200077e57600080fd5b80632ee3d92f11620003095780635231e24f116200029f5780635e5e33ef116200026a5780635e5e33ef14620006ca5780636ed71ede14620006e157806370a0823114620006eb57806372dcf679146200071757600080fd5b80635231e24f146200064c57806354441311146200067457806356c571cf146200068b5780635b74905414620006b357600080fd5b8063392e53cd11620002e0578063392e53cd14620005ff5780633c939dc1146200061457806340e9903b146200062b578063516885be146200063557600080fd5b80632ee3d92f14620005ab5780632f9ffaf614620005d3578063313ce56714620005ea57600080fd5b80630d97c9fa116200038b57806318160ddd116200035657806318160ddd146200055957806323b872dd146200056257806326949f9e146200057957806329db1be6146200058357600080fd5b80630d97c9fa14620004d457806312e667e914620004eb57806315c14a4a146200051157806316774ba0146200052a57600080fd5b8063095ea7b311620003cc578063095ea7b3146200046757806309da2c54146200048d5780630a3ee46114620004a45780630bfe176014620004bd57600080fd5b8062a28b3614620003f5578063037ec8c8146200043557806306fdde03146200044e575b600080fd5b6200041d7f000000000000000000000000ba5ddd1f9d7f570dc94a51479a000e3bce96719681565b6040516200042c919062003fd0565b60405180910390f35b6200043f62000a43565b6040516200042c91906200404b565b6200045862000a9d565b6040516200042c9190620040c2565b6200047e6200047836600462004110565b62000b2e565b6040516200042c91906200415c565b6200041d6200049e3660046200416c565b62000b4a565b620004bb620004b5366004620041f1565b62000b89565b005b620004bb620004ce3660046200423f565b62000e9b565b620004bb620004e5366004620042ad565b62000f3a565b62000502620004fc36600462004301565b62000f90565b6040516200042c91906200433a565b6200051b62000fe9565b6040516200042c91906200436f565b6200047e6200053b3660046200416c565b6001600160a01b03166000908152600b602052604090205460ff1690565b60025462000502565b6200047e620005733660046200437f565b6200100d565b62000502600f5481565b6200041d7f0000000000000000000000001cbba6346f110c8a5ea739ef2d1eb182990e4eb281565b6200051b7f00000000000000000000000038e49a617305101216ec6306e3a18065d14bf3a781565b620004bb620005e4366004620042ad565b62001037565b60055460ff166040516200042c9190620043c4565b6005546200047e90600160a81b900460ff1681565b620004bb62000625366004620043d4565b620010d4565b6200050260105481565b620004bb62000646366004620043fc565b6200135f565b6200041d7f000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e583181565b620004bb6200068536600462004110565b62001412565b620005027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b620004bb620006c436600462004110565b620014b4565b620004bb620006db36600462004422565b62001556565b6200050260065481565b62000502620006fc3660046200416c565b6001600160a01b031660009081526020819052604090205490565b620004bb620007283660046200416c565b62001574565b6200041d6200073f36600462004110565b6001600160a01b039182166000908152600d6020908152604080832093835292905220541690565b620005026200077836600462004447565b62001660565b620007956200078f36600462004422565b620016c5565b6040516200042c9190620044fc565b620004bb620007b5366004620041f1565b62001795565b6200043f620017e2565b620005027f000000000000000000000000000000000000000000000000000000000000001181565b6200047e620007fe3660046200416c565b6200183a565b620004bb620008153660046200416c565b62001891565b620004bb6200082c366004620043fc565b620018ab565b6200045862001960565b6200047e6200084d36600462004110565b62001971565b620004bb6200086436600462004422565b620019da565b6005546200041d9061010090046001600160a01b031681565b6200047e6200089436600462004110565b620019f4565b6200041d620008ab3660046200416c565b6001600160a01b039081166000908152600a60205260409020541690565b6011546001600160a01b03166200051b565b6200041d620008ec3660046200416c565b62001a04565b620004bb6200090336600462004529565b62001a52565b6200041d6200091a3660046200416c565b6001600160a01b039081166000908152600960205260409020541690565b6200041d62000949366004620043fc565b62001f18565b6200041d7f000000000000000000000000ba5ddd1f9d7f570dc94a51479a000e3bce96719681565b6200051b7f0000000000000000000000002a059d6d682e5fb1226eb8bc2977b512698c240481565b6200041d62001fd2565b6200050260075481565b6200050262002057565b62000502620009ce366004620045ad565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b620004bb62000a0a366004620042ad565b6200208b565b60016200047e565b620004bb62000a29366004620041f1565b6200217e565b6011546200051b906001600160a01b031681565b6060601280548060200260200160405190810160405280929190818152602001828054801562000a9357602002820191906000526020600020905b81548152602001906001019080831162000a7e575b5050505050905090565b60606003805462000aae90620045fc565b80601f016020809104026020016040519081016040528092919081815260200182805462000adc90620045fc565b801562000a935780601f1062000b015761010080835404028352916020019162000a93565b820191906000526020600020905b81548152906001019060200180831162000b0f57509395945050505050565b60003362000b3e818585620022ac565b60019150505b92915050565b600062000b448260405160200162000b63919062004656565b6040516020818303038152906040528051906020012062000b8362002057565b62002368565b3362000bea62000b9862001fd2565b6001600160a01b0316826001600160a01b0316147127b7363ca237b637b6b4ba32a6b0b933b4b760711b7f43616c6c6572206973206e6f74206f776e6572206f6620446f6c6f6d697465008462002377565b60055462000c2a90600160a81b900460ff161560008051602062005cd383398151915272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b620021cb565b62000c3462000fe9565b6001600160a01b0316638fae3be1306040518263ffffffff1660e01b815260040162000c61919062003fd0565b60206040518083038186803b15801562000c7a57600080fd5b505afa15801562000c8f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000cb591906200467a565b60065562000d8062000cc662000fe9565b6001600160a01b0316635ac7d17c6006546040518263ffffffff1660e01b815260040162000cf591906200433a565b60206040518083038186803b15801562000d0e57600080fd5b505afa15801562000d23573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d499190620046ac565b60008051602062005cd38339815191527f4d61726b65742063616e6e6f7420616c6c6f7720626f72726f77696e67000000620021cb565b61dead6000819052600a6020527f20677881080440a9b3c87e826370bb5d9c2f74efd4dede686d52d77a6a09f8bb5462000dc491906001600160a01b0316620023c6565b60005b8281101562000e1d5762000e0884848381811062000de95762000de9620046d1565b905060200201602081019062000e0091906200416c565b6001620025d9565b8062000e1481620046fd565b91505062000dc7565b506005805460ff60a81b1916600160a81b1790556040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c890600090a162000e96600654601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900155565b505050565b336000818152600b602052604090205462000eda9060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b03808516600090815260096020526040902054859162000f269116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b62000f3385858562002682565b5050505050565b60055462000f7590600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b3362000f8462000b9862001fd2565b62000e968383620025d9565b6001600160a01b0382166000908152600e602052604081208183600181111562000fbe5762000fbe6200471b565b600181111562000fd25762000fd26200471b565b815260200190815260200160002054905092915050565b7f0000000000000000000000006bd780e7fdf01d77e4d475c821f1e7ae0540907290565b6000336200101d858285620026f9565b6200102a85858562002751565b60019150505b9392505050565b336000818152600b6020526040902054620010769060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b038084166000908152600960205260409020548491620010c29116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce848462002c94565b50505050565b336000818152600960205260409020546200111c906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b6200114f60065484141560008051602062005cd38339815191526d125b9d985b1a59081b585c9ad95d60921b8662002cc2565b60408051600280825260608201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620011675790505090506040518060400160405280336001600160a01b03168152602001600081525081600081518110620011c657620011c6620046d1565b6020908102919091018101919091526040805180820182523360009081526009845291909120546001600160a01b03168152908101869052815182906001908110620012165762001216620046d1565b602090810291909101015260408051600280825260608201909252600091816020015b6200124362003ec1565b815260200190600190039081620012395750506040805160808101909152600181529091506200128d90600090879060208101838152602001600081526020018890523362002cf5565b81600081518110620012a357620012a3620046d1565b6020026020010181905250620012c960006001876000620012c360001990565b62002d60565b81600181518110620012df57620012df620046d1565b6020026020010181905250620012f462000fe9565b6001600160a01b031663a67a6a4583836040518363ffffffff1660e01b815260040162001323929190620049b4565b600060405180830381600087803b1580156200133e57600080fd5b505af115801562001353573d6000803e3d6000fd5b50505050505050505050565b33600081815260096020526040902054620013a7906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b33620013bf81620013b762000fe9565b858462002e82565b620010ce620013cd62000fe9565b828387600654604051806080016040528060011515815260200160006001811115620013fd57620013fd6200471b565b8152602001600081526020018a905262003080565b336000818152600b6020526040902054620014519060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b0380841660009081526009602052604090205484916200149d9116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce620014ab62000fe9565b33858762002e82565b336000818152600b6020526040902054620014f39060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b0380841660009081526009602052604090205484916200153f9116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b620010ce336200154e62000fe9565b858762002e82565b336200156562000b9862001fd2565b6200157082620031d5565b5050565b600554620015af90600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b33620015be62000b9862001fd2565b620016056001600160a01b038316151560008051602062005cd38339815191527f496e76616c6964207573657220696d706c656d656e746174696f6e0000000000620021cb565b600580546001600160a01b03848116610100818102610100600160a81b031985161790945560405193909204169182907fdc5a954098cef71f25bbe48bbd58cd5866495daacabf32492424363af66dd01890600090a3505050565b6001600160a01b0383166000908152600c602090815260408083208584529091528120818360018111156200169957620016996200471b565b6001811115620016ad57620016ad6200471b565b81526020019081526020016000205490509392505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526200173160075483111560008051602062005cd38339815191527f496e76616c6964207472616e7366657220637572736f72000000000000000000620021cb565b50600090815260086020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015493810193909352600301549081166060830152600160a01b900460ff161515608082015290565b33620017a462000b9862001fd2565b62000e968383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506200325992505050565b6060601380548060200260200160405190810160405280929190818152602001828054801562000a93576020028201919060005260206000209081548152602001906001019080831162000a7e575050505050905090565b6001600160a01b0381166000908152600e6020908152604080832083805290915281205415158062000b445750506001600160a01b03166000908152600e6020908152604080832060018452909152902054151590565b33620018a062000b9862001fd2565b6200157082620033c4565b33600081815260096020526040902054620018f3906001600160a01b0316151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b336200190b6200190262000fe9565b82858462002e82565b620010ce6200191962000fe9565b8286846006546040518060800160405280600015158152602001600060018111156200194957620019496200471b565b8152602001600081526020018a9052600162003411565b60606004805462000aae90620045fc565b6001600160a01b0382166000908152600c602090815260408083208484528252808320838052909152812054151580620010305750506001600160a01b03919091166000908152600c602090815260408083209383529281528282206001835290522054151590565b33620019e962000b9862001fd2565b6200157082620035dc565b60003362000b3e81858562002751565b60055460009062001a4290600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b62000b448262003613565b919050565b336000818152600b602052604090205462001b6a9060ff168062001a8f57506001600160a01b038281166000908152600960205260409020541615155b8062001b295750816001600160a01b031662001aaa62000fe9565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801562001ae357600080fd5b505afa15801562001af8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001b1e9190620049ea565b6001600160a01b0316145b74467265657a61626c655661756c74466163746f727960581b7f43616c6c6572206973206e6f74206120617574686f72697a65640000000000008462002377565b6001600160a01b03808716600090815260096020526040902054879162001bb69116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b6001600160a01b038088166000908152600d602090815260408083208a84529091529020541662001c3781158062001bff5750846001600160a01b0316826001600160a01b0316145b74467265657a61626c655661756c74466163746f727960581b7324b73b30b634b21037baba383aba103a37b5b2b760611b8762002377565b62001c5262001c4c3687900387018762004aab565b620037b4565b1562001d3f576001600160a01b0388166000908152600c602090815260408083208a845282528220908701359188600181111562001c945762001c946200471b565b600181111562001ca85762001ca86200471b565b8152602001908152602001600020600082825462001cc7919062004ad0565b90915550506001600160a01b0388166000908152600e602090815260408220908701359188600181111562001d005762001d006200471b565b600181111562001d145762001d146200471b565b8152602001908152602001600020600082825462001d33919062004ad0565b9091555062001e419050565b62001d5a62001d543687900387018762004aab565b620037cc565b1562001e41576001600160a01b0388166000908152600c602090815260408083208a845282528220908701359188600181111562001d9c5762001d9c6200471b565b600181111562001db05762001db06200471b565b8152602001908152602001600020600082825462001dcf919062004aea565b90915550506001600160a01b0388166000908152600e602090815260408220908701359188600181111562001e085762001e086200471b565b600181111562001e1c5762001e1c6200471b565b8152602001908152602001600020600082825462001e3b919062004aea565b90915550505b600062001e4f898962001971565b9050801562001e97576001600160a01b038981166000908152600d602090815260408083208c8452909152902080546001600160a01b03191691871691909117905562001ec9565b6001600160a01b0389166000908152600d602090815260408083208b8452909152902080546001600160a01b03191690555b87896001600160a01b03167f74d76887c0c124ce17a77f76f9256a35d4630551e4dd4977ab439e3dc368e5b28360405162001f0591906200415c565b60405180910390a3505050505050505050565b60055460009062001f5690600160a81b900460ff1660008051602062005cd38339815191526e139bdd081a5b9a5d1a585b1a5e9959608a1b620021cb565b600062001f633362003613565b604051637d49eb4d60e11b81529091506001600160a01b0382169063fa93d69a9062001f96908790879060040162004b05565b600060405180830381600087803b15801562001fb157600080fd5b505af115801562001fc6573d6000803e3d6000fd5b50929695505050505050565b600062001fde62000fe9565b6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200201757600080fd5b505afa1580156200202c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620020529190620049ea565b905090565b6000604051806020016200206b9062003f38565b6020820181038252601f19601f8201166040525080519060200120905090565b336000818152600b6020526040902054620020ca9060ff1660008051602062005cd383398151915260008051602062005cb38339815191528462002377565b6001600160a01b038084166000908152600960205260409020548491620021169116151560008051602062005cd38339815191526c125b9d985b1a59081d985d5b1d609a1b8462002377565b604051630509ab1b60e31b81526001600160a01b0385169063284d58d890620021449086906004016200415c565b600060405180830381600087803b1580156200215f57600080fd5b505af115801562002174573d6000803e3d6000fd5b5050505050505050565b336200218d62000b9862001fd2565b62000e96838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250620037e392505050565b8262000e9657620021dc826200382a565b6101d160f51b620021ed836200382a565b604051602001620022019392919062004b5a565b60408051601f198184030181529082905262461bcd60e51b82526200222991600401620040c2565b60405180910390fd5b600083471015620022575760405162461bcd60e51b8152600401620022299062004bbf565b8151620022785760405162461bcd60e51b8152600401620022299062004c04565b8282516020840186f590506001600160a01b038116620010305760405162461bcd60e51b8152600401620022299062004c4b565b6001600160a01b038316620022d55760405162461bcd60e51b8152600401620022299062004ca1565b6001600160a01b038216620022fe5760405162461bcd60e51b8152600401620022299062004cf3565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906200235b9085906200433a565b60405180910390a3505050565b600062001030838330620038d1565b83620010ce5762002388836200382a565b6101d160f51b62002399846200382a565b61080f60f21b620023aa85620038fa565b60405162002201959493929190601f60f91b9060200162004d16565b6001600160a01b03821615801590620023e757506001600160a01b03811615155b620023f657620023f662004d80565b60405163189acdbd60e31b81526001600160a01b0382169063c4d66de8906200242490859060040162003fd0565b600060405180830381600087803b1580156200243f57600080fd5b505af115801562002454573d6000803e3d6000fd5b505060405163f697ae9960e01b81526001600160a01b037f00000000000000000000000038e49a617305101216ec6306e3a18065d14bf3a716925063f697ae999150620024a990849060019060040162004d96565b600060405180830381600087803b158015620024c457600080fd5b505af1158015620024d9573d6000803e3d6000fd5b505050507f0000000000000000000000002a059d6d682e5fb1226eb8bc2977b512698c24046001600160a01b031663f68ebbbd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156200253757600080fd5b505afa1580156200254c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002572919062004dcd565b6001600160a01b03166305c4fdf983836040518363ffffffff1660e01b8152600401620025a192919062004df2565b600060405180830381600087803b158015620025bc57600080fd5b505af1158015620025d1573d6000803e3d6000fd5b505050505050565b620026206001600160a01b038316151560008051602062005cd38339815191527f496e76616c696420746f6b656e20636f6e766572746572000000000000000000620021cb565b6001600160a01b0382166000818152600b602052604090819020805460ff1916841515179055517f1a2aaf8fb443c30344ac3e041f678060eb802aa3e68057d31682b9909d5693a490620026769084906200415c565b60405180910390a25050565b6200268f83600162002c94565b620026a6836200269e62000fe9565b838662002e82565b62000e96620026b462000fe9565b848585600654604051806080016040528060011515815260200160006001811115620026e457620026e46200471b565b81526020016000815260200188905262003080565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205481811015620027425760405162461bcd60e51b8152600401620022299062004e46565b620010ce8484848403620022ac565b33620027b26200276062000fe9565b6001600160a01b0316826001600160a01b0316147127b7363ca237b637b6b4ba32a6b0b933b4b760711b7f4f6e6c7920446f6c6f6d6974652063616e2063616c6c2066756e6374696f6e008462002377565b620027f96001600160a01b038516151560008051602062005cd38339815191527f5472616e736665722066726f6d20746865207a65726f20616464726573730000620021cb565b620028406001600160a01b038416151560008051602062005cd38339815191527f5472616e7366657220746f20746865207a65726f206164647265737300000000620021cb565b60006200284c62000fe9565b9050620028bb816001600160a01b0316866001600160a01b03161480620028845750816001600160a01b0316856001600160a01b0316145b60008051602062005cd38339815191527f66726f6d2f746f206d75737420657120446f6c6f6d6974654d617267696e0000620021cb565b600754600081815260086020908152604091829020825160a08101845281546001600160a01b0390811680835260018401548216948301949094526002830154948201949094526003909101548084166060830152600160a01b900460ff161515608082015291620029bf919089161480156200294d5750866001600160a01b031682602001516001600160a01b0316145b80156200295d5750858260400151145b801562002988575060608201516001600160a01b039081166000908152600960205260409020541615155b60008051602062005cd38339815191527f496e76616c696420717565756564207472616e73666572000000000000000000620021cb565b62002a0181608001511560008051602062005cd38339815191527f5472616e7366657220616c7265616479206578656375746564000000000000008562002cc2565b6000828152600860205260409020600301805460ff60a01b1916600160a01b1790556001600160a01b03868116908416141562002b65576001600160a01b038088166000908152600960205260409020541662002ac6811580159062002a7c575082606001516001600160a01b0316896001600160a01b0316145b8062002aa057506001600160a01b0389166000908152600b602052604090205460ff165b60008051602062005cd38339815191526b496e76616c69642066726f6d60a01b620021cb565b81606001516001600160a01b0316638ddab4e560006001600160a01b0316836001600160a01b0316141562002afc578962002afe565b825b886040518363ffffffff1660e01b815260040162002b1e92919062004e58565b600060405180830381600087803b15801562002b3957600080fd5b505af115801562002b4e573d6000803e3d6000fd5b5050505062002b5e878762003a5a565b5062002c8b565b826001600160a01b0316876001600160a01b03161462002b895762002b8962004d80565b6001600160a01b038087166000908152600960205260409020541662002bf38115158062002bcf57506001600160a01b0388166000908152600b602052604090205460ff165b60008051602062005cd383398151915269496e76616c696420746f60b01b620021cb565b81606001516001600160a01b031663797b512560006001600160a01b0316836001600160a01b0316141562002c29578862002c2b565b825b886040518363ffffffff1660e01b815260040162002c4b92919062004e58565b600060405180830381600087803b15801562002c6657600080fd5b505af115801562002c7b573d6000803e3d6000fd5b5050505062002174888762003af7565b50505050505050565b60405163065f3c3360e41b81526001600160a01b038316906365f3c33090620025a19084906004016200415c565b83620010ce5762002cd3836200382a565b6101d160f51b62002ce4846200382a565b61080f60f21b620023aa8562003bb6565b62002cff62003ec1565b6040805161010081019091528060005b815260200186815260200184815260200185815260200160008152602001836001600160a01b0316815260200160008152602001604051806020016040528060008152508152509050949350505050565b62002d6a62003ec1565b62002d97604080516080810190915260008082526020820190815260200160008152602001600081525090565b60001983141562002de457604051806080016040528060001515815260200185600181111562002dcb5762002dcb6200471b565b8152602001600181526020016000815250905062002e1f565b604051806080016040528060001515815260200185600181111562002e0d5762002e0d6200471b565b81526020016000815260200184905290505b60408051610100810190915280600281526020018881526020018281526020018681526020016000815260200160006001600160a01b03168152602001878152602001604051806020016040528060008152508152509150505b95945050505050565b600754600090815260086020908152604091829020825160a08101845281546001600160a01b0390811682526001830154811693820193909352600282015493810193909352600301549081166060830152600160a01b900460ff161580156080830181905262002f11575062002ef862000fe9565b6001600160a01b031681602001516001600160a01b0316145b1562002f2d5762002f2d816060015182602001516000620022ac565b816001600160a01b0316856001600160a01b031614801562002f69575062002f5462000fe9565b6001600160a01b0316846001600160a01b0316145b1562002f7c5762002f7c828585620022ac565b60016007600082825462002f91919062004aea565b90915550506040805160a0810182526001600160a01b038088168252868116602080840191825283850188815287841660608601908152600060808701818152600780548352600890955290889020965187549087166001600160a01b03199182161788559451600188018054918816919096161790945590516002860155516003909401805492511515600160a01b026001600160a81b031990931694909316939093171790555490517f41f436ede2f45a36c2a15333e202b31f7040c914a78d7eb62d6f7caa6414a756906200307190889088908890889062004e68565b60405180910390a25050505050565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620030975790505090506040518060400160405280876001600160a01b031681526020018581525081600081518110620030f557620030f5620046d1565b6020908102919091010152604080516001808252818301909252600091816020015b6200312162003ec1565b8152602001906001900390816200311757905050905062003146600085858962002cf5565b816000815181106200315c576200315c620046d1565b602090810291909101015260405163a67a6a4560e01b81526001600160a01b0389169063a67a6a4590620031979085908590600401620049b4565b600060405180830381600087803b158015620031b257600080fd5b505af1158015620031c7573d6000803e3d6000fd5b505050505050505050505050565b62003217600f5482111574467265657a61626c655661756c74466163746f727960581b74496e76616c696420657865637574696f6e2066656560581b620021cb565b60108190556040517f34243bbc545b7abbfc8001dc34d1ae65eef90e6bbccd634ddf433247734c9d7a906200324e9083906200433a565b60405180910390a150565b805160005b8181101562003370576200335b6200327562000fe9565b6001600160a01b0316635ac7d17c858481518110620032985762003298620046d1565b60200260200101516040518263ffffffff1660e01b8152600401620032be91906200433a565b60206040518083038186803b158015620032d757600080fd5b505afa158015620032ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620033129190620046ac565b157f53696d706c6549736f6c6174696f6e4d6f64655661756c74466163746f7279007f4d61726b65742063616e6e6f7420626520636c6f73696e670000000000000000620021cb565b806200336781620046fd565b9150506200325e565b5081516200338690601290602085019062003f46565b507fe394f8a439e499167cfe98e403f35fc54387abe3f9db4e5c0632c8ec8e9b193482604051620033b891906200404b565b60405180910390a15050565b601180546001600160a01b0319166001600160a01b0383161790556040517fd61d47c7844ec2c99fa7e2b21baaacf489203aa183ed706df8a3f169acd7b38e906200324e90839062003fd0565b604080516001808252818301909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081620034285790505090506040518060400160405280886001600160a01b031681526020018781525081600081518110620034865762003486620046d1565b6020908102919091010152604080516001808252818301909252600091816020015b620034b262003ec1565b815260200190600190039081620034a8579050509050620034d7600086868962003cda565b81600081518110620034ed57620034ed620046d1565b602090810291909101015260405163a67a6a4560e01b81526001600160a01b038a169063a67a6a4590620035289085908590600401620049b4565b600060405180830381600087803b1580156200354357600080fd5b505af115801562003558573d6000803e3d6000fd5b506000925062003566915050565b8360038111156200357b576200357b6200471b565b14806200359c575060018360038111156200359a576200359a6200471b565b145b15620035d157620035d18983600081518110620035bd57620035bd620046d1565b602002602001015160000151898862003cf9565b505050505050505050565b600f8190556040517f4d4feaf092299649d71328c4c35afb429aba48782a3f1078b3295a48322ee8b5906200324e9083906200433a565b60006200364e6001600160a01b038316151560008051602062005cd38339815191526e125b9d985b1a59081858d8dbdd5b9d608a1b620021cb565b6001600160a01b038281166000908152600a60205260409020546200369d91161560008051602062005cd3833981519152735661756c7420616c72656164792065786973747360601b620021cb565b6000620036f9600084604051602001620036b8919062004656565b6040516020818303038152906040528051906020012060405180602001620036e09062003f38565b601f1982820381018352601f9091011660405262002232565b90506001600160a01b03811662003714576200371462004d80565b826001600160a01b03167f5d9c31ffa0fecffd7cf379989a3c7af252f0335e0d2a1320b55245912c781f53826040516200374f919062003fd0565b60405180910390a26001600160a01b03808216600081815260096020908152604080832080549589166001600160a01b03199687168117909155808452600a909252909120805490931690911790915561dead1462000b445762000b448382620023c6565b805160009015801562000b4457505060200151151590565b8051600090801562000b4457505060200151151590565b8051620037f890601390602084019062003f46565b507f3ef7cb7777c10315913a05aed0c0c3f1b40e11bbe9df01be0a5d1f71db93faff816040516200324e91906200404b565b606060008260405160200162003841919062004ea5565b60408051601f19818403018152919052905060205b8015620038b65780620038698162004ebc565b915050818181518110620038815762003881620046d1565b01602001516001600160f81b03191615620038b0576000620038a582600162004aea565b835250909392505050565b62003856565b5060408051600080825260208201909252905b509392505050565b6000604051836040820152846020820152828152600b810160ff81536055902095945050505050565b60408051602a80825260608281019093526001600160a01b03841691600091602082018180368337019050509050603060f81b81600081518110620039435762003943620046d1565b60200101906001600160f81b031916908160001a905350607860f81b81600181518110620039755762003975620046d1565b60200101906001600160f81b031916908160001a90535060005b6014811015620038c9576000620039a882600262004ed6565b9050620039b8600f851662003dfd565b83620039c683602962004ad0565b81518110620039d957620039d9620046d1565b60200101906001600160f81b031916908160001a905350600484901c935062003a05600f851662003dfd565b8362003a1383602862004ad0565b8151811062003a265762003a26620046d1565b60200101906001600160f81b031916908160001a9053505060049290921c918062003a5181620046fd565b9150506200398f565b6001600160a01b03821662003a835760405162461bcd60e51b8152600401620022299062004f2d565b806002600082825462003a97919062004aea565b90915550506001600160a01b038216600081815260208190526040808220805485019055517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9062003aeb9085906200433a565b60405180910390a35050565b6001600160a01b03821662003b205760405162461bcd60e51b8152600401620022299062004f7e565b6001600160a01b0382166000908152602081905260409020548181101562003b5c5760405162461bcd60e51b8152600401620022299062004fd0565b6001600160a01b0383166000818152602081905260408082208585039055600280548690039055519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906200235b9086906200433a565b60608162003bdb5750506040805180820190915260018152600360fc1b602082015290565b8160005b811562003c0b578062003bf281620046fd565b915062003c039050600a8362004ff8565b915062003bdf565b60008167ffffffffffffffff81111562003c295762003c2962004731565b6040519080825280601f01601f19166020018201604052801562003c54576020820181803683370190505b508593509050815b801562003cd1578062003c6f8162004ebc565b915062003c809050600a856200500f565b62003c8d90603062004aea565b60f81b82828151811062003ca55762003ca5620046d1565b60200101906001600160f81b031916908160001a90535062003cc9600a8562004ff8565b935062003c5c565b50949350505050565b62003ce462003ec1565b60408051610100810190915280600162002d0f565b6040805180820182526001600160a01b0380861682526020820185905291516311f46d4f60e21b81529091600091908716906347d1b53c9062003d43908590879060040162005026565b604080518083038186803b15801562003d5b57600080fd5b505afa15801562003d70573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003d969190620050a8565b9050620025d162003da78262003e2c565b8062003dbe575060208201516001600160801b0316155b7020b1b1b7bab73a2130b630b731b2a634b160791b7f6163636f756e742063616e6e6f7420676f206e6567617469766500000000000088888862003e4c565b6000600a82101562003e1f5762003e1660308362004aea565b60f81b92915050565b62003e1660578362004aea565b8051600090801562000b44575050602001516001600160801b0316151590565b85620025d15762003e5d856200382a565b6101d160f51b62003e6e866200382a565b61080f60f21b62003e7f87620038fa565b61016160f51b62003e908862003bb6565b61016160f51b62003ea18962003bb6565b6040516200220199989796959493929190601f60f91b90602001620050cd565b60408051610100810182526000808252602082015290810162003f06604080516080810190915260008082526020820190815260200160008152602001600081525090565b8152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b610b37806200517c83390190565b82805482825590600052602060002090810192821562003f84579160200282015b8281111562003f8457825182559160200191906001019062003f67565b5062003f9292915062003f96565b5090565b5b8082111562003f92576000815560010162003f97565b60006001600160a01b03821662000b44565b62003fca8162003fad565b82525050565b6020810162000b44828462003fbf565b8062003fca565b600062003ff5838362003fe0565b505060200190565b600062004008825190565b80845260209384019383018060005b83811015620040405781516200402e888262003fe7565b97506020830192505060010162004017565b509495945050505050565b6020808252810162001030818462003ffd565b60005b838110156200407b57818101518382015260200162004061565b83811115620010ce5750506000910152565b600062004098825190565b808452602084019350620040b18185602086016200405e565b601f01601f19169290920192915050565b602080825281016200103081846200408d565b620040e08162003fad565b8114620040ec57600080fd5b50565b803562000b4481620040d5565b80620040e0565b803562000b4481620040fc565b60008060408385031215620041285762004128600080fd5b6000620041368585620040ef565b9250506020620041498582860162004103565b9150509250929050565b80151562003fca565b6020810162000b44828462004153565b600060208284031215620041835762004183600080fd5b6000620041918484620040ef565b949350505050565b60008083601f840112620041b057620041b0600080fd5b50813567ffffffffffffffff811115620041cd57620041cd600080fd5b602083019150836020820283011115620041ea57620041ea600080fd5b9250929050565b60008060208385031215620042095762004209600080fd5b823567ffffffffffffffff811115620042255762004225600080fd5b620042338582860162004199565b92509250509250929050565b600080600060608486031215620042595762004259600080fd5b6000620042678686620040ef565b93505060206200427a8682870162004103565b92505060406200428d8682870162004103565b9150509250925092565b801515620040e0565b803562000b448162004297565b60008060408385031215620042c557620042c5600080fd5b6000620042d38585620040ef565b92505060206200414985828601620042a0565b60028110620040ec57600080fd5b803562000b4481620042e6565b60008060408385031215620043195762004319600080fd5b6000620043278585620040ef565b92505060206200414985828601620042f4565b6020810162000b44828462003fe0565b600062000b448262003fad565b600062000b44826200434a565b62003fca8162004357565b6020810162000b44828462004364565b600080600060608486031215620043995762004399600080fd5b6000620043a78686620040ef565b93505060206200427a86828701620040ef565b60ff811662003fca565b6020810162000b448284620043ba565b600080600060608486031215620043ee57620043ee600080fd5b600062004267868662004103565b60008060408385031215620044145762004414600080fd5b600062004136858562004103565b600060208284031215620044395762004439600080fd5b600062004191848462004103565b600080600060608486031215620044615762004461600080fd5b60006200446f8686620040ef565b9350506020620044828682870162004103565b92505060406200428d86828701620042f4565b805160a0830190620044a8848262003fbf565b506020820151620044bd602085018262003fbf565b506040820151620044d2604085018262003fe0565b506060820151620044e7606085018262003fbf565b506080820151620010ce608085018262004153565b60a0810162000b44828462004495565b600060408284031215620045235762004523600080fd5b50919050565b600080600080600060c08688031215620045465762004546600080fd5b6000620045548888620040ef565b9550506020620045678882890162004103565b94505060406200457a88828901620042f4565b93505060606200458d888289016200450c565b92505060a0620045a088828901620040ef565b9150509295509295909350565b60008060408385031215620045c557620045c5600080fd5b6000620045d38585620040ef565b92505060206200414985828601620040ef565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200461157607f821691505b60208210811415620045235762004523620045e6565b600062000b448260601b90565b600062000b448262004627565b62003fca620046508262003fad565b62004634565b600062004664828462004641565b50601401919050565b805162000b4481620040fc565b600060208284031215620046915762004691600080fd5b60006200419184846200466d565b805162000b448162004297565b600060208284031215620046c357620046c3600080fd5b60006200419184846200469f565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415620047145762004714620046e7565b5060010190565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b805160408301906200475a848262003fbf565b506020820151620010ce602085018262003fe0565b60006200477d838362004747565b505060400190565b600062004790825190565b80845260209384019383018060005b8381101562004040578151620047b688826200476f565b9750602083019250506001016200479f565b60098110620040ec57620040ec6200471b565b8062001a4d81620047c8565b600062000b4482620047db565b62003fca81620047e7565b60028110620040ec57620040ec6200471b565b8062001a4d81620047ff565b600062000b448262004812565b62003fca816200481e565b8051608083019062004849848262004153565b5060208201516200485e60208501826200482b565b5060408201516200487360408501826200482b565b506060820151620010ce606085018262003fe0565b80516000906101608401906200489f8582620047f4565b506020830151620048b4602086018262003fe0565b506040830151620048c9604086018262004836565b506060830151620048de60c086018262003fe0565b506080830151620048f360e086018262003fe0565b5060a08301516200490961010086018262003fbf565b5060c08301516200491f61012086018262003fe0565b5060e083015184820361014086015262002e7982826200408d565b600062001030838362004888565b600062004953825190565b808452602084019350836020820285016200496e8560200190565b8060005b85811015620049a757848403895281516200498e85826200493a565b94506020830160209a909a019992505060010162004972565b5091979650505050505050565b60408082528101620049c7818562004785565b9050818103602083015262004191818462004948565b805162000b4481620040d5565b60006020828403121562004a015762004a01600080fd5b6000620041918484620049dd565b601f19601f830116810181811067ffffffffffffffff8211171562004a385762004a3862004731565b6040525050565b600062004a4b60405190565b905062001a4d828262004a0f565b60006040828403121562004a705762004a70600080fd5b62004a7c604062004a3f565b9050600062004a8c8484620042a0565b825250602062004a9f8484830162004103565b60208301525092915050565b60006040828403121562004ac25762004ac2600080fd5b600062004191848462004a59565b60008282101562004ae55762004ae5620046e7565b500390565b6000821982111562004b005762004b00620046e7565b500190565b6040810162004b15828562003fe0565b62001030602083018462003fe0565b600062004b2f825190565b62004b3f8185602086016200405e565b9290920192915050565b6001600160f01b0319811662003fca565b600062004b68828662004b24565b915062004b76828562004b49565b60028201915062002e79828462004b24565b601d81526000602082017f437265617465323a20696e73756666696369656e742062616c616e6365000000815291505b5060200190565b6020808252810162000b448162004b88565b60208082527f437265617465323a2062797465636f6465206c656e677468206973207a65726f9101908152600062004bb8565b6020808252810162000b448162004bd1565b601981526000602082017f437265617465323a204661696c6564206f6e206465706c6f79000000000000008152915062004bb8565b6020808252810162000b448162004c16565b602481526000602082017f45524332303a20417070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015291505b5060400190565b6020808252810162000b448162004c5d565b602281526000602082017f45524332303a20417070726f766520746f20746865207a65726f206164647265815261737360f01b6020820152915062004c9a565b6020808252810162000b448162004cb3565b6001600160f81b0319811662003fca565b600062004d24828962004b24565b915062004d32828862004b49565b60028201915062004d44828762004b24565b915062004d52828662004b49565b60028201915062004d64828562004b24565b915062004d72828462004d05565b506001019695505050505050565b634e487b7160e01b600052600160045260246000fd5b6040810162004da6828562003fbf565b62001030602083018462004153565b620040e0816200434a565b805162000b448162004db5565b60006020828403121562004de45762004de4600080fd5b600062004191848462004dc0565b6040810162004e02828562003fbf565b62001030602083018462003fbf565b601d81526000602082017f45524332303a20496e73756666696369656e7420616c6c6f77616e63650000008152915062004bb8565b6020808252810162000b448162004e11565b6040810162004b15828562003fbf565b6080810162004e78828762003fbf565b62004e87602083018662003fbf565b62004e96604083018562003fe0565b62002e79606083018462003fbf565b600062004eb3828462003fe0565b50602001919050565b60008162004ece5762004ece620046e7565b506000190190565b600081600019048311821515161562004ef35762004ef3620046e7565b500290565b601f81526000602082017f45524332303a204d696e7420746f20746865207a65726f2061646472657373008152915062004bb8565b6020808252810162000b448162004ef8565b602181526000602082017f45524332303a204275726e2066726f6d20746865207a65726f206164647265738152607360f81b6020820152915062004c9a565b6020808252810162000b448162004f3f565b602281526000602082017f45524332303a204275726e20616d6f756e7420657863656564732062616c616e815261636560f01b6020820152915062004c9a565b6020808252810162000b448162004f90565b634e487b7160e01b600052601260045260246000fd5b6000826200500a576200500a62004fe2565b500490565b60008262005021576200502162004fe2565b500690565b6060810162005036828562004747565b62001030604083018462003fe0565b6001600160801b038116620040e0565b805162000b448162005045565b600060408284031215620050795762005079600080fd5b62005085604062004a3f565b905060006200509584846200469f565b825250602062004a9f8484830162005055565b600060408284031215620050bf57620050bf600080fd5b600062004191848462005062565b6000620050db828d62004b24565b9150620050e9828c62004b49565b600282019150620050fb828b62004b24565b915062005109828a62004b49565b6002820191506200511b828962004b24565b915062005129828862004b49565b6002820191506200513b828762004b24565b915062005149828662004b49565b6002820191506200515b828562004b24565b915062005169828462004d05565b506001019a995050505050505050505056fe608060405234801561001057600080fd5b5061004461003f60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef361005f565b339055565b610076565b634e487b7160e01b600052601160045260246000fd5b60008282101561007157610071610049565b500390565b610ab2806100856000396000f3fe60806040526004361061004e5760003560e01c8063392e53cd146100b45780635c60da1b146100df5780638da5cb5b14610101578063c4d66de814610116578063d8a06f7314610136576100a9565b366100a95761009761005e61014b565b7f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e139bdd081a5b9a5d1a585b1a5e9959608a1b610187565b6100a76100a26101ea565b610269565b005b61009761005e61014b565b3480156100c057600080fd5b506100c961014b565b6040516100d6919061077d565b60405180910390f35b3480156100eb57600080fd5b506100f46101ea565b6040516100d691906107a5565b34801561010d57600080fd5b506100f461028d565b34801561012257600080fd5b506100a76101313660046107d2565b6102bd565b34801561014257600080fd5b506100f4610473565b600061017f61017b60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b5490565b600114905090565b826101e557610195826104a3565b6101d160f51b6101a4836104a3565b6040516020016101b693929190610886565b60408051601f198184030181529082905262461bcd60e51b82526101dc916004016108e9565b60405180910390fd5b505050565b60006101f4610473565b6001600160a01b031663a6e7d83f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561022c57600080fd5b505afa158015610240573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610264919061090c565b905090565b3660008037600080366000845af43d6000803e808015610288573d6000f35b3d6000fd5b600061026461017b60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b6103066102c861014b565b157f49736f6c6174696f6e4d6f64655570677261646561626c6550726f787900000072105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b610187565b6103d130610312610473565b6001600160a01b031663b01f61e1846040518263ffffffff1660e01b815260040161033d91906107a5565b60206040518083038186803b15801561035557600080fd5b505afa158015610369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061038d919061090c565b6001600160a01b0316147f49736f6c6174696f6e4d6f64655570677261646561626c6550726f78790000006e125b9d985b1a59081858d8dbdd5b9d608a1b8461053e565b6104046103ff60017fa7b53796fd2d99cb1f5ae019b54f9e024446c3d12b483f733ccc62ed04eb126b610811565b829055565b61043b61040f6101ea565b6040516104279063204a7f0760e21b9060200161093d565b60405160208183030381529060405261058a565b5061047061046a60017f059687b4dba0a8c0c94866b6d34b3f94074057ac6e4d8d39cf07d3a0a55f2050610811565b60019055565b50565b600061026461017b60017f4c711eee7e3094af1816c5450bcb78a8ffe46729a7979be7e0bf539fb4d4eef3610811565b60606000826040516020016104b89190610958565b60408051601f19818403018152919052905060205b801561052357806104dd8161096d565b9150508181815181106104f2576104f2610984565b01602001516001600160f81b0319161561051e57600061051382600161099a565b835250909392505050565b6104cd565b5060408051600080825260208201909252905b509392505050565b836105845761054c836104a3565b6101d160f51b61055b846104a3565b61080f60f21b61056a85610603565b6040516101b6959493929190601f60f91b906020016109c2565b50505050565b6060600080846001600160a01b0316846040516105a79190610a20565b600060405180830381855af49150503d80600081146105e2576040519150601f19603f3d011682016040523d82523d6000602084013e6105e7565b606091505b5091509150816105f9576105f9610a2c565b9150505b92915050565b60408051602a80825260608281019093526001600160a01b03841691600091602082018180368337019050509050603060f81b8160008151811061064957610649610984565b60200101906001600160f81b031916908160001a905350607860f81b8160018151811061067857610678610984565b60200101906001600160f81b031916908160001a90535060005b60148110156105365760006106a8826002610a42565b90506106b6600f8516610749565b836106c2836029610811565b815181106106d2576106d2610984565b60200101906001600160f81b031916908160001a905350600484901c93506106fc600f8516610749565b83610708836028610811565b8151811061071857610718610984565b60200101906001600160f81b031916908160001a9053505060049290921c918061074181610a61565b915050610692565b6000600a8210156107685761075f60308361099a565b60f81b92915050565b61075f60578361099a565b8015155b82525050565b602081016105fd8284610773565b60006001600160a01b0382166105fd565b6107778161078b565b602081016105fd828461079c565b6107bc8161078b565b811461047057600080fd5b80356105fd816107b3565b6000602082840312156107e7576107e7600080fd5b60006107f384846107c7565b949350505050565b634e487b7160e01b600052601160045260246000fd5b600082821015610823576108236107fb565b500390565b60005b8381101561084357818101518382015260200161082b565b838111156105845750506000910152565b600061085e825190565b61086c818560208601610828565b9290920192915050565b6001600160f01b03198116610777565b60006108928286610854565b915061089e8285610876565b6002820191506108ae8284610854565b95945050505050565b60006108c1825190565b8084526020840193506108d8818560208601610828565b601f01601f19169290920192915050565b602080825281016108fa81846108b7565b9392505050565b80516105fd816107b3565b60006020828403121561092157610921600080fd5b60006107f38484610901565b6001600160e01b03198116610777565b6000610949828461092d565b50600401919050565b80610777565b60006109648284610952565b50602001919050565b60008161097c5761097c6107fb565b506000190190565b634e487b7160e01b600052603260045260246000fd5b600082198211156109ad576109ad6107fb565b500190565b6001600160f81b03198116610777565b60006109ce8289610854565b91506109da8288610876565b6002820191506109ea8287610854565b91506109f68286610876565b600282019150610a068285610854565b9150610a1282846109b2565b506001019695505050505050565b60006108fa8284610854565b634e487b7160e01b600052600160045260246000fd5b6000816000190483118215151615610a5c57610a5c6107fb565b500290565b6000600019821415610a7557610a756107fb565b506001019056fea264697066735822122075a44ae10adcae9b874b7ea4e5b0292a10ae4024647e2db8988dc6bce3251ef064736f6c6343000809003343616c6c6572206973206e6f74206120746f6b656e20636f6e7665727465720049736f6c6174696f6e4d6f64655661756c74466163746f727900000000000000a2646970667358221220c6b8b3bc2e2aba99020c6dac720af0f5bf8df79bb8099efa144df162112dc85f64736f6c63430008090033
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.