// 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;
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: 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 { 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;
/**
* @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 { 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 { 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 {
// ========================================================
// ======================== 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);
// ========================================================
// =================== Admin Functions ====================
// ========================================================
/**
*
* @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;
// ========================================================
// =================== 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 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 { IDolomiteInterestSetter } from "./IDolomiteInterestSetter.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;
}
/*
* 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 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;
}
struct TotalPar {
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 { IUpgradeableAsyncIsolationModeUnwrapperTrader } from "./IUpgradeableAsyncIsolationModeUnwrapperTrader.sol";
import { IUpgradeableAsyncIsolationModeWrapperTrader } from "./IUpgradeableAsyncIsolationModeWrapperTrader.sol";
/**
* @title IEventEmitterRegistry
* @author Dolomite
*
* Interface for a a singleton event emission contract, which makes tracking events easier for the Subgraph.
*/
interface IEventEmitterRegistry {
// ================================================
// ==================== Events ====================
// ================================================
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);
// ================================================
// ================== Functions ===================
// ================================================
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;
}
// 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";
/**
* @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 { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol";
import { AccountBalanceLib } from "../lib/AccountBalanceLib.sol";
/**
* @title IGenericTraderProxyV1
* @author Dolomite
*
* Trader proxy interface for trading assets using any trader from msg.sender
*/
interface IGenericTraderProxyV1 is IGenericTraderBase {
// ============ Structs ============
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;
}
// ============ 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 EXPIRY() external view returns (address);
function MARGIN_POSITION_REGISTRY() 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 "./IBorrowPositionProxyV2.sol";
import { IDolomiteRegistry } from "./IDolomiteRegistry.sol";
import { IGenericTraderBase } from "./IGenericTraderBase.sol";
import { IGenericTraderProxyV1 } from "./IGenericTraderProxyV1.sol";
import { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol";
import { IDolomiteStructs } from "../../protocol/interfaces/IDolomiteStructs.sol";
import { AccountBalanceLib } from "../lib/AccountBalanceLib.sol";
/**
* @title IIsolationModeTokenVaultV1
* @author Dolomite
*
* @notice Interface for the implementation contract used by proxy user vault contracts.
*/
interface IIsolationModeTokenVaultV1 {
// ===========================================================
// ======================== Functions ========================
// ===========================================================
/**
* @notice Initializes the vault contract. Should only be executable once by the proxy.
*/
function initialize() 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 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. 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 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 { IDolomiteMargin } from "../../protocol/interfaces/IDolomiteMargin.sol";
import { IDolomiteMarginExchangeWrapper } from "../../protocol/interfaces/IDolomiteMarginExchangeWrapper.sol";
/**
* @title IIsolationModeUnwrapperTrader
* @author Dolomite
*
* Interface for a contract that can convert an isolation mode token into an underlying component token.
*/
interface IIsolationModeUnwrapperTrader is IDolomiteMarginExchangeWrapper {
/**
* @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 _primaryAccountId The index of the account (according the Accounts[] array) that is performing the
* sell.
* @param _otherAccountId The index of the account (according the Accounts[] array) that is being liquidated.
* This is set to `_primaryAccountId` if a liquidation is not occurring.
* @param _primaryAccountOwner The address of the owner of the account that is performing the sell.
* @param _otherAccountOwner The address of the owner of the account that is being liquidated. This is set to
* `_primaryAccountOwner` if a liquidation is not occurring.
* @param _outputMarket The market that is being outputted by the unwrapping.
* @param _inputMarket The market that is being unwrapped, should be equal to `token()`.
* @param _minOutputAmount The min amount of `_outputMarket` that must be outputted by the unwrapping.
* @param _inputAmount The amount of the `_inputMarket` that the _primaryAccountId must sell.
* @param _orderData The calldata to pass through to any external sales that occur.
* @return The actions that will be executed to unwrap the `_inputMarket` into `_outputMarket`.
*/
function createActionsForUnwrapping(
uint256 _primaryAccountId,
uint256 _otherAccountId,
address _primaryAccountOwner,
address _otherAccountOwner,
uint256 _outputMarket,
uint256 _inputMarket,
uint256 _minOutputAmount,
uint256 _inputAmount,
bytes calldata _orderData
)
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 "./IBorrowPositionProxyV2.sol";
import { IOnlyDolomiteMargin } from "./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);
/**
*
* @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 IIsolationModeWrapperTrader
* @author Dolomite
*
* Interface for a contract that can convert a token into an isolation mode token.
*/
interface IIsolationModeWrapperTrader is IDolomiteMarginExchangeWrapper {
/**
* @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 _primaryAccountId The index of the account (according the Accounts[] array) that is performing the
* sell.
* @param _otherAccountId The index of the account (according the Accounts[] array) that is being liquidated.
* This is set to `_primaryAccountId` if a liquidation is not occurring.
* @param _primaryAccountOwner The address of the owner of the account that is performing the sell.
* @param _otherAccountOwner The address of the owner of the account that is being liquidated. This is set to
* `_primaryAccountOwner` if a liquidation is not occurring.
* @param _outputMarket The market that is being outputted by the wrapping, should be equal to `token().
* @param _inputMarket The market that is being used to wrap into `token()`.
* @param _minOutputAmount The min amount of `_outputMarket` that must be outputted by the wrapping.
* @param _inputAmount The amount of the `_inputMarket` that the _primaryAccountId must sell.
* @param _orderData The calldata to pass through to any external sales that occur.
* @return The actions that will be executed to wrap the `_inputMarket` into `_outputMarket`.
*/
function createActionsForWrapping(
uint256 _primaryAccountId,
uint256 _otherAccountId,
address _primaryAccountOwner,
address _otherAccountOwner,
uint256 _outputMarket,
uint256 _inputMarket,
uint256 _minOutputAmount,
uint256 _inputAmount,
bytes calldata _orderData
)
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;
/**
* @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 { IIsolationModeUnwrapperTrader } from "./IIsolationModeUnwrapperTrader.sol";
import { IIsolationModeVaultFactory } from "./IIsolationModeVaultFactory.sol";
import { IOnlyDolomiteMargin } from "./IOnlyDolomiteMargin.sol";
/**
* @title IUpgradeableAsyncIsolationModeUnwrapperTrader
* @author Dolomite
*
* Interface for an upgradeable contract that can convert an isolation mode token into another token.
*/
interface IUpgradeableAsyncIsolationModeUnwrapperTrader is IIsolationModeUnwrapperTrader, 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
}
// ===================================================
// ==================== Functions ====================
// ===================================================
/**
* 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 { IIsolationModeWrapperTrader } from "./IIsolationModeWrapperTrader.sol";
import { IOnlyDolomiteMargin } from "./IOnlyDolomiteMargin.sol";
/**
* @title IUpgradeableAsyncIsolationModeWrapperTrader
* @author Dolomite
*
* Interface for an upgradeable contract that can convert a token into an isolation mode token.
*/
interface IUpgradeableAsyncIsolationModeWrapperTrader is IIsolationModeWrapperTrader, 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 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 { Require } from "../../protocol/lib/Require.sol";
import { ProxyContractHelpers } from "../helpers/ProxyContractHelpers.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
{
// ============ 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 {} // solhint-disable-line no-empty-blocks
// 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;
/**
* @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 _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)
}
}
}
// 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;
}
}
{
"compilationTarget": {
"contracts/external/proxies/IsolationModeUpgradeableProxy.sol": "IsolationModeUpgradeableProxy"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"details": {
"constantOptimizer": true,
"cse": true,
"deduplicate": true,
"inliner": true,
"jumpdestRemover": true,
"orderLiterals": true,
"peephole": true,
"yul": false
},
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]