Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BestDexLens
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {WadRayMath} from "../libraries/utils/WadRayMath.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
import "./../libraries/Errors.sol";
import {IBestDexLens} from "../interfaces/IBestDexLens.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ILimitOrderManager} from "../LimitOrderManager/ILimitOrderManager.sol";
import {IDexAdapter} from "../interfaces/IDexAdapter.sol";
/**
* @dev All functions in this contract are intended to be called off-chain. Do not call functions from other contracts to avoid an out-of-gas error.
*/
contract BestDexLens is IBestDexLens, IERC165 {
using WadRayMath for uint256;
using SafeCast for uint256;
int256 internal constant VERY_NEGATIVE_VALUE = -1e72;
int256 internal constant VERY_POSITIVE_VALUE = 1e72;
/**
* @inheritdoc IBestDexLens
*/
function getBestDexByOrder(
BestDexByOrderParams memory _params
) external payable override returns (GetBestDexByOrderReturnParams memory _returnParams) {
_require(
IERC165(address(_params.positionManager)).supportsInterface(type(IPositionManagerV2).interfaceId) &&
IERC165(address(_params.limitOrderManager)).supportsInterface(type(ILimitOrderManager).interfaceId),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
_params.positionManager.priceOracle().updatePullOracle{value: msg.value}(
_params.pullOracleData,
_params.pullOracleTypes
);
LimitOrderLibrary.LimitOrder memory order = _params.limitOrderManager.getOrder(_params.orderId);
address borrowedAsset = order.leverage == WadRayMath.WAD
? order.depositAsset
: address(order.bucket.borrowedAsset());
IPrimexDNSV3 primexDns = _params.positionManager.primexDNS();
bool isBorrowedAsset = borrowedAsset == order.depositAsset;
bool isThirdAsset = !isBorrowedAsset && order.depositAsset != order.positionAsset;
if (!isBorrowedAsset) {
_returnParams.depositToBorrowedReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: borrowedAsset,
assetToSell: order.depositAsset,
amount: order.depositAmount,
isAmountToBuy: false,
shares: _params.shares.depositToBorrowedShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
uint256 depositAmountInBorrowed = PrimexPricingLibrary.getDepositAmountInBorrowed(
IDexAdapter.AmountParams({
tokenA: order.depositAsset,
tokenB: borrowedAsset,
amount: order.depositAmount,
megaRoutes: _returnParams.depositToBorrowedReturnParams.megaRoutes
}),
isThirdAsset,
payable(primexDns.dexAdapter()),
address(_params.positionManager.priceOracle()),
_params.depositBorrowedAssetOracleData
);
uint256 amountToTransfer = depositAmountInBorrowed.wmul(order.leverage - WadRayMath.WAD);
if (isBorrowedAsset) {
amountToTransfer += depositAmountInBorrowed;
} else if (isThirdAsset) {
_returnParams.depositInThirdAssetReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: order.positionAsset,
assetToSell: order.depositAsset,
amount: order.depositAmount,
isAmountToBuy: false,
shares: _params.shares.depositInThirdAssetShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
_returnParams.firstAssetReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: order.positionAsset,
assetToSell: borrowedAsset,
amount: amountToTransfer,
isAmountToBuy: false,
shares: _params.shares.firstAssetShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
/**
* @inheritdoc IBestDexLens
*/
function getBestDexByPosition(
IPositionManagerV2 _positionManager,
uint256 _positionId,
uint256 _shares,
DexWithAncillaryData[] memory _dexesWithAncillaryData
) public override returns (GetBestMultipleDexesReturnParams memory) {
_require(
IERC165(address(_positionManager)).supportsInterface(type(IPositionManagerV2).interfaceId),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
PositionLibrary.Position memory position = _positionManager.getPosition(_positionId);
return
getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _positionManager,
assetToBuy: position.soldAsset,
assetToSell: position.positionAsset,
amount: position.positionAmount,
isAmountToBuy: false,
shares: _shares,
gasPriceInCheckedAsset: 0,
dexes: _dexesWithAncillaryData
})
);
}
/**
* @inheritdoc IBestDexLens
*/
function getBestDexForOpenablePosition(
BestDexForOpenablePositionParams memory _params
)
public
override
returns (
GetBestMultipleDexesReturnParams memory _firstAssetReturnParams,
GetBestMultipleDexesReturnParams memory _depositInThirdAssetReturnParams,
GetBestMultipleDexesReturnParams memory _depositToBorrowedReturnParams
)
{
_require(
IERC165(address(_params.positionManager)).supportsInterface(type(IPositionManagerV2).interfaceId) &&
_params.borrowedAsset != address(0) &&
_params.depositAsset != address(0) &&
_params.positionAsset != address(0),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
_require(_params.depositAmount != 0, Errors.DEPOSITED_AMOUNT_IS_0.selector);
_require(
_params.borrowedAmount != 0 || _params.borrowedAsset == _params.depositAsset,
Errors.SPOT_DEPOSITED_ASSET_SHOULD_BE_EQUAL_BORROWED_ASSET.selector
);
bool isBorrowedAsset = _params.borrowedAsset == _params.depositAsset;
bool isThirdAsset = !isBorrowedAsset && _params.depositAsset != _params.positionAsset;
if (!isBorrowedAsset) {
_depositToBorrowedReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: _params.borrowedAsset,
assetToSell: _params.depositAsset,
amount: _params.depositAmount,
isAmountToBuy: false,
shares: _params.shares.depositToBorrowedShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
if (isThirdAsset) {
_depositInThirdAssetReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: _params.positionAsset,
assetToSell: _params.depositAsset,
amount: _params.depositAmount,
isAmountToBuy: false,
shares: _params.shares.depositInThirdAssetShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
_firstAssetReturnParams = getBestMultipleDexes(
GetBestMultipleDexesParams({
positionManager: _params.positionManager,
assetToBuy: _params.positionAsset,
assetToSell: _params.borrowedAsset,
amount: _params.borrowedAmount + (isBorrowedAsset ? _params.depositAmount : 0),
isAmountToBuy: false,
shares: _params.shares.firstAssetShares,
gasPriceInCheckedAsset: 0,
dexes: _params.dexes
})
);
}
/**
* @inheritdoc IBestDexLens
*/
function getBestMultipleDexes(
GetBestMultipleDexesParams memory _params
) public override returns (GetBestMultipleDexesReturnParams memory _returnParams) {
_require(
_params.assetToBuy != address(0) && _params.assetToSell != address(0),
Errors.ZERO_ASSET_ADDRESS.selector
);
_require(_params.assetToBuy != _params.assetToSell, Errors.ASSETS_SHOULD_BE_DIFFERENT.selector);
_require(_params.shares > 0, Errors.ZERO_SHARES.selector);
_require(_params.amount >= _params.shares, Errors.SHARES_AMOUNT_IS_GREATER_THAN_AMOUNT_TO_SELL.selector);
GetBestMultipleDexesVars memory vars;
DexWithAncillaryData[] memory activeDexes = new DexWithAncillaryData[](_params.dexes.length);
vars.shareCount = _params.shares;
// stores estimated gas to perform swap on each DEX
vars.gases = new uint256[](_params.dexes.length);
// matrix [allDexes.length][shareCount] containing the swapped amount
// on each DEX (rows) for each share (columns) minus estimated gas to perform the swap
int256[][] memory amountByDexByShare = new int256[][](_params.dexes.length);
vars.path = new address[](2);
vars.path[0] = _params.assetToSell;
vars.path[1] = _params.assetToBuy;
// filter out inactive DEXes and collect their outputs for all possible share splits
{
IDexAdapter.GetAmountsParams memory amountParams;
for (uint256 i; i < _params.dexes.length; i++) {
// if DEX is not supported or deactivated - set expected gas to a very large number
// slither-disable-next-line unused-return
try _params.positionManager.primexDNS().getDexAddress(_params.dexes[i].dex) returns (
// slither-disable-next-line unused-return,variable-scope
address currentRouter
) {
uint256 returnGas = IDexAdapter(payable(_params.positionManager.primexDNS().dexAdapter())).getGas(
currentRouter
);
amountParams.amount = _params.amount / vars.shareCount;
amountParams.dexRouter = currentRouter;
amountParams.encodedPath = PrimexPricingLibrary.encodePath(
vars.path,
currentRouter,
_params.dexes[i].ancillaryData,
payable(_params.positionManager.primexDNS().dexAdapter()),
_params.isAmountToBuy
);
uint256 amount = _getAmountsFromAdapter(
amountParams,
IDexAdapter(payable(_params.positionManager.primexDNS().dexAdapter())),
_params.isAmountToBuy
);
if (amount == type(uint256).max) continue;
// add DEX to active list
activeDexes[vars.activeDexesLength] = _params.dexes[i];
amountByDexByShare[vars.activeDexesLength] = new int256[](vars.shareCount);
// store estimated gas
vars.gases[vars.activeDexesLength] = returnGas;
vars.gasInCheckedAsset = ((returnGas * _params.gasPriceInCheckedAsset) / 1e18).toInt256();
amountByDexByShare[vars.activeDexesLength][0] = _params.isAmountToBuy
? amount.toInt256() + vars.gasInCheckedAsset
: amount.toInt256() - vars.gasInCheckedAsset;
} catch {
continue;
}
for (uint256 j = 1; j < vars.shareCount; j++) {
amountParams.amount = (_params.amount * (j + 1)) / vars.shareCount;
uint256 amount = _getAmountsFromAdapter(
amountParams,
IDexAdapter(payable(_params.positionManager.primexDNS().dexAdapter())),
_params.isAmountToBuy
);
amountByDexByShare[vars.activeDexesLength][j] = _params.isAmountToBuy
? (
amount == type(uint256).max
? VERY_POSITIVE_VALUE
: amount.toInt256() + vars.gasInCheckedAsset
)
: (
amount == type(uint256).max
? VERY_NEGATIVE_VALUE
: amount.toInt256() - vars.gasInCheckedAsset
);
}
// we should get here if first _getAmountsFromAdapter is successful and DEX is active
vars.activeDexesLength++;
}
}
_require(vars.activeDexesLength > 0, Errors.NO_ACTIVE_DEXES.selector);
// array with best splitting route
uint256[] memory distribution = new uint256[](vars.activeDexesLength);
uint256 involvedDexesLength;
{
// matrix [activeDexesLength][shareCount] containing the maximum amount you receive for swapping
// j parts of asset for each DEX
int256[][] memory answer = new int256[][](vars.activeDexesLength);
// matrix [activeDexesLength][shareCount] containing the amount of parts you should swap on previous DEXes
// if you swap j parts on current DEX
uint256[][] memory parentParts = new uint256[][](vars.activeDexesLength);
for (uint256 i; i < vars.activeDexesLength; i++) {
answer[i] = new int256[](vars.shareCount);
parentParts[i] = new uint256[](vars.shareCount);
}
// copy first DEX from `amountByDexByShare` to the `answer` first row
for (uint256 j; j < vars.shareCount; j++) {
answer[0][j] = amountByDexByShare[0][j];
}
for (uint256 i = 1; i < vars.activeDexesLength; i++) {
for (uint256 j; j < vars.shareCount; j++) {
// choose the value from the previous DEX as a max value
int256 bestValue = answer[i - 1][j];
// save current shares count
parentParts[i][j] = j + 1;
// current value is a sum of previous max shares so that total shares count is j + 1
int256 currentValue = amountByDexByShare[i][j];
if (
_params.isAmountToBuy ? (currentValue < bestValue || bestValue == 0) : currentValue > bestValue
) {
bestValue = currentValue;
parentParts[i][j] = 0;
}
for (uint256 k; k < j; k++) {
currentValue = answer[i - 1][j - k - 1] + amountByDexByShare[i][k];
// if current value of DEX + previous value of previous DEX is higher than max value
// update max value and save previous shares count
if (
_params.isAmountToBuy
? (currentValue < bestValue || bestValue == 0)
: currentValue > bestValue
) {
bestValue = currentValue;
parentParts[i][j] = j - k;
}
}
answer[i][j] = bestValue;
}
}
// iterate over `parentParts` backwards and collect the parts of the shares to get the resulting maximum amount
{
uint256 partsLeft = vars.shareCount;
for (uint256 i; i < vars.activeDexesLength; i++) {
if (partsLeft == 0) break;
uint256 curExchange = vars.activeDexesLength - i - 1;
distribution[curExchange] = partsLeft - parentParts[curExchange][partsLeft - 1];
partsLeft = parentParts[curExchange][partsLeft - 1];
if (distribution[curExchange] > 0) {
involvedDexesLength++;
}
}
}
}
if (involvedDexesLength == 0) return _returnParams;
_returnParams.megaRoutes = new PrimexPricingLibrary.MegaRoute[](1);
_returnParams.megaRoutes[0] = PrimexPricingLibrary.MegaRoute({
shares: 1, // 100%
routes: new PrimexPricingLibrary.Route[](1)
});
_returnParams.megaRoutes[0].routes[0] = PrimexPricingLibrary.Route({
to: _params.assetToBuy,
paths: new PrimexPricingLibrary.Path[](involvedDexesLength)
});
for (uint256 i; i < vars.activeDexesLength; i++) {
if (distribution[i] == 0) continue;
_returnParams.megaRoutes[0].routes[0].paths[vars.filledRoutes] = PrimexPricingLibrary.Path({
shares: distribution[i],
dexName: activeDexes[i].dex,
payload: PrimexPricingLibrary.encodePath(
vars.path,
_params.positionManager.primexDNS().getDexAddress(activeDexes[i].dex),
activeDexes[i].ancillaryData,
payable(_params.positionManager.primexDNS().dexAdapter()),
_params.isAmountToBuy
)
});
vars.filledRoutes++;
// collect some additional statistics: total return amount, estimate gas spending
_returnParams.estimateGasAmount = _returnParams.estimateGasAmount.add(vars.gases[i]);
int256 value = amountByDexByShare[i][distribution[i] - 1];
_returnParams.returnAmount =
_returnParams.returnAmount +
uint256(
(
value == 0 ? int256(0) : _params.isAmountToBuy
? (value - ((vars.gases[i] * _params.gasPriceInCheckedAsset) / 1e18).toInt256())
: (value + ((vars.gases[i] * _params.gasPriceInCheckedAsset) / 1e18).toInt256())
)
);
}
}
/**
* @notice Interface checker
* @param interfaceId The interface id to check
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IBestDexLens).interfaceId || interfaceId == type(IERC165).interfaceId;
}
/**
* @notice Retrieves the amounts from a DEX adapter contract.
* @param _params The parameters for getting amounts from the adapter.
* @param _adapter The DEX adapter contract.
* @param _isAmountToBuy A flag indicating whether the amount to retrieve is for buying or selling.
* @return The retrieved amount.
*/
function _getAmountsFromAdapter(
IDexAdapter.GetAmountsParams memory _params,
IDexAdapter _adapter,
bool _isAmountToBuy
) internal returns (uint256) {
if (_isAmountToBuy) {
try _adapter.getAmountsIn(_params) returns (uint256[3] memory answersList) {
return answersList[0];
} catch {
return type(uint256).max;
}
}
try _adapter.getAmountsOut(_params) returns (uint256[3] memory answersList) {
return answersList[1];
} catch {
return type(uint256).max;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(uint80 _roundId)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
import "./PythStructs.sol";
import "./IPythEvents.sol";
/// @title Consume prices from the Pyth Network (https://pyth.network/).
/// @dev Please refer to the guidance at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how to consume prices safely.
/// @author Pyth Data Association
interface IPyth is IPythEvents {
/// @notice Returns the period (in seconds) that a price feed is considered valid since its publish time
function getValidTimePeriod() external view returns (uint validTimePeriod);
/// @notice Returns the price and confidence interval.
/// @dev Reverts if the price has not been updated within the last `getValidTimePeriod()` seconds.
/// @param id The Pyth Price Feed ID of which to fetch the price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price and confidence interval.
/// @dev Reverts if the EMA price is not available.
/// @param id The Pyth Price Feed ID of which to fetch the EMA price and confidence interval.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPrice(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
/// This function is unsafe as the returned price update may be arbitrarily far in the past.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks.
/// @dev This function returns the same price as `getEmaPrice` in the case where the price is available.
/// However, if the price is not recent this function returns the latest available price.
///
/// The returned price can be from arbitrarily far in the past; this function makes no guarantees that
/// the returned price is recent or useful for any particular application.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceUnsafe(
bytes32 id
) external view returns (PythStructs.Price memory price);
/// @notice Returns the exponentially-weighted moving average price that is no older than `age` seconds
/// of the current time.
/// @dev This function is a sanity-checked version of `getEmaPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getEmaPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (PythStructs.Price memory price);
/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
/// Prices will be updated if they are more recent than the current stored prices.
/// The call will succeed even if the update is not the most recent.
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
function updatePriceFeeds(bytes[] calldata updateData) external payable;
/// @notice Wrapper around updatePriceFeeds that rejects fast if a price update is not necessary. A price update is
/// necessary if the current on-chain publishTime is older than the given publishTime. It relies solely on the
/// given `publishTimes` for the price feeds and does not read the actual price update publish time within `updateData`.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
/// `priceIds` and `publishTimes` are two arrays with the same size that correspond to senders known publishTime
/// of each priceId when calling this method. If all of price feeds within `priceIds` have updated and have
/// a newer or equal publish time than the given publish time, it will reject the transaction to save gas.
/// Otherwise, it calls updatePriceFeeds method to update the prices.
///
/// @dev Reverts if update is not needed or the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param publishTimes Array of publishTimes. `publishTimes[i]` corresponds to known `publishTime` of `priceIds[i]`
function updatePriceFeedsIfNecessary(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64[] calldata publishTimes
) external payable;
/// @notice Returns the required fee to update an array of price updates.
/// @param updateData Array of price update data.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
/// @notice Parse `updateData` and return price feeds of the given `priceIds` if they are all published
/// within `minPublishTime` and `maxPublishTime`.
///
/// You can use this method if you want to use a Pyth price at a fixed time and not the most recent price;
/// otherwise, please consider using `updatePriceFeeds`. This method may store the price updates on-chain, if they
/// are more recent than the current stored prices.
///
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
///
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdates(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
/// @notice Similar to `parsePriceFeedUpdates` but ensures the updates returned are
/// the first updates published in minPublishTime. That is, if there are multiple updates for a given timestamp,
/// this method will return the first update. This method may store the price updates on-chain, if they
/// are more recent than the current stored prices.
///
///
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid or there is
/// no update for any of the given `priceIds` within the given time range and uniqueness condition.
/// @param updateData Array of price update data.
/// @param priceIds Array of price ids.
/// @param minPublishTime minimum acceptable publishTime for the given `priceIds`.
/// @param maxPublishTime maximum acceptable publishTime for the given `priceIds`.
/// @return priceFeeds Array of the price feeds corresponding to the given `priceIds` (with the same order).
function parsePriceFeedUpdatesUnique(
bytes[] calldata updateData,
bytes32[] calldata priceIds,
uint64 minPublishTime,
uint64 maxPublishTime
) external payable returns (PythStructs.PriceFeed[] memory priceFeeds);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
/// @title IPythEvents contains the events that Pyth contract emits.
/// @dev This interface can be used for listening to the updates for off-chain and testing purposes.
interface IPythEvents {
/// @dev Emitted when the price feed with `id` has received a fresh update.
/// @param id The Pyth Price Feed ID.
/// @param publishTime Publish time of the given price update.
/// @param price Price of the given price update.
/// @param conf Confidence interval of the given price update.
event PriceFeedUpdate(
bytes32 indexed id,
uint64 publishTime,
int64 price,
uint64 conf
);
/// @dev Emitted when a batch price update is processed successfully.
/// @param chainId ID of the source chain that the batch price update comes from.
/// @param sequenceNumber Sequence number of the batch price update.
event BatchPriceFeedUpdate(uint16 chainId, uint64 sequenceNumber);
}// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;
contract PythStructs {
// A price with a degree of uncertainty, represented as a price +- a confidence interval.
//
// The confidence interval roughly corresponds to the standard error of a normal distribution.
// Both the price and confidence are stored in a fixed-point numeric representation,
// `x * (10^expo)`, where `expo` is the exponent.
//
// Please refer to the documentation at https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices for how
// to how this price safely.
struct Price {
// Price
int64 price;
// Confidence interval around the price
uint64 conf;
// Price exponent
int32 expo;
// Unix timestamp describing when the price was published
uint publishTime;
}
// PriceFeed represents a current aggregate price from pyth publisher feeds.
struct PriceFeed {
// The price ID.
bytes32 id;
// Latest available price
Price price;
// Latest available exponentially-weighted moving average price
Price emaPrice;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
/// @title Quoter Interface
/// @notice Supports quoting the calculated amounts from exact input or exact output swaps
/// @dev These functions are not marked view because they rely on calling non-view functions and reverting
/// to compute the result. They are also not gas efficient and should not be called on-chain.
interface IQuoter {
/// @notice Returns the amount out received for a given exact input swap without executing the swap
/// @param path The path of the swap, i.e. each token pair and the pool fee
/// @param amountIn The amount of the first token to swap
/// @return amountOut The amount of the last token that would be received
function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut);
/// @notice Returns the amount out received for a given exact input but for a swap of a single pool
/// @param tokenIn The token being swapped in
/// @param tokenOut The token being swapped out
/// @param fee The fee of the token pool to consider for the pair
/// @param amountIn The desired input amount
/// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// @return amountOut The amount of `tokenOut` that would be received
function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountOut);
/// @notice Returns the amount in required for a given exact output swap without executing the swap
/// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order
/// @param amountOut The amount of the last token to receive
/// @return amountIn The amount of first token required to be paid
function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn);
/// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool
/// @param tokenIn The token being swapped in
/// @param tokenOut The token being swapped out
/// @param fee The fee of the token pool to consider for the pair
/// @param amountOut The desired output amount
/// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap
/// @return amountIn The amount required as the input for the swap in order to receive `amountOut`
function quoteExactOutputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountOut,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountIn);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IActivityRewardDistributorStorage, IERC20, IPrimexDNSV3, ITraderBalanceVault} from "./IActivityRewardDistributorStorage.sol";
import {IWhiteBlackList} from "../WhiteBlackList/WhiteBlackList/IWhiteBlackList.sol";
import {IBucketV3} from "../Bucket/IBucket.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface IActivityRewardDistributor is IActivityRewardDistributorStorage, IPausable {
enum Role {
LENDER,
TRADER
}
struct BucketWithRole {
address bucketAddress;
Role role;
}
/**
* @notice Emitted on claimReward()
* @param user The address of the user who claimed reward
* @param bucket The address of the bucket this reward is related to
* @param role User role - TRADER or LENDER
* @param amount Claimed amount
*/
event ClaimReward(address indexed user, address indexed bucket, Role indexed role, uint256 amount);
/**
* @notice Initializes the ActivityRewardDistributor contract.
* @dev This function should only be called once during the initial setup of the contract.
* @param _pmx The address of the PMXToken contract.
* @param _dns The address of the PrimexDNS contract.
* @param _registry The address of the PrimexRegistry contract.
* @param _treasury The address of the treasury where fees will be collected.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _whiteBlackList The address of the WhiteBlackList contract.
*/
function initialize(
IERC20 _pmx,
IPrimexDNSV3 _dns,
address _registry,
address _treasury,
ITraderBalanceVault _traderBalanceVault,
IWhiteBlackList _whiteBlackList
) external;
/**
* @notice Saves user activity in the protocol for reward calculation
* @param bucket The address of the bucket
* @param user User address
* @param newBalance User balance after action
* @param role User role - TRADER or LENDER
*/
function updateUserActivity(IBucketV3 bucket, address user, uint256 newBalance, Role role) external;
/**
* @notice Saves activity of multiple users in the protocol for reward calculation
* @param bucket The address of the bucket
* @param users Array of user addresses
* @param newBalances Array of users balances after action
* @param length The length of the users and oldBalances arrays
* @param role User role - TRADER or LENDER
*/
function updateUsersActivities(
IBucketV3 bucket,
address[] calldata users,
uint256[] calldata newBalances,
uint256 length,
Role role
) external;
/**
* @notice Allows the caller to claim their accumulated reward from the specified buckets.
* @param bucketsArray The array of BucketWithRole objects containing the buckets from which to claim the rewards.
*/
function claimReward(BucketWithRole[] calldata bucketsArray) external;
/**
* @notice Sets up activity rewards distribution in bucket with the specified role and reward parameters.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param bucket The address of the bucket to set up.
* @param role The role associated with the bucket.
* @param increaseAmount The amount by which to increase the total reward for the bucket (in PMX).
* Adds specified amount to totalReward of the bucket. Initial value of totalReward is 0.
* @param rewardPerDay The reward amount per day for the bucket.
*/
function setupBucket(address bucket, Role role, uint256 increaseAmount, uint256 rewardPerDay) external;
/**
* @notice Allows the caller to withdraw PMX tokens from a specific bucket.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param bucket The address of the bucket from which to withdraw PMX tokens.
* @param role The role associated with the bucket.
* @param amount The amount of PMX tokens to withdraw.
*/
function withdrawPmx(address bucket, Role role, uint256 amount) external;
/**
* @notice Decreases the reward per day for a bucket and role.
* @dev Only callable by the EMERGENCY_ADMIN role.
* @param bucket The address of the bucket for which to decrease the reward per day.
* @param role The role associated with the bucket.
* @param rewardPerDay The amount by which to decrease the reward per day.
*/
function decreaseRewardPerDay(address bucket, Role role, uint256 rewardPerDay) external;
/**
* @notice Returns the accumulated reward for a specific bucket and role.
* @param bucket The address of the bucket for which to retrieve the accumulated reward.
* @param role The role associated with the bucket.
* @return The accumulated reward for the specified bucket and role.
*/
function getBucketAccumulatedReward(address bucket, Role role) external view returns (uint256);
/**
* @notice Returns the claimable reward for a user across multiple buckets.
* @param bucketsArray The array of BucketWithRole objects containing the buckets to check for claimable rewards.
* @param user The address of the user for whom to calculate the claimable reward.
* @return The total claimable reward for the specified user across all provided buckets.
*/
function getClaimableReward(BucketWithRole[] calldata bucketsArray, address user) external view returns (uint256);
/**
* @notice Retrieves the user information from a specific bucket and role.
* @param bucket The address of the bucket from which to retrieve the user information.
* @param role The role associated with the bucket.
* @param user The address of the user for whom to retrieve the information.
* @return A UserInfo struct containing the user information.
*/
function getUserInfoFromBucket(address bucket, Role role, address user) external view returns (UserInfo memory);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
interface IActivityRewardDistributorStorage {
/*
* @param oldBalance last updated balance for user
* @param fixedReward the accumulated value of the reward at the time lastUpdatedRewardIndex
* @param lastUpdatedRewardIndex last index with which the user's reward was accumulated
*/
struct UserInfo {
uint256 fixedReward;
uint256 lastUpdatedRewardIndex;
uint256 oldBalance;
}
/*
* @param users data to calculate users rewards in this bucket
* @param rewardIndex an index that accumulates user rewards
* @param lastUpdatedTimestamp timestamp of the last update of user activity
* @param rewardPerToken current reward for one token(PToken or DebtToken of bucket)
* @param isFinished Shows that the bucket has distributed all the rewards
* @param fixedReward reward distributed by a bucket over the past period
* with a certain reward per day or with the entire reward fully distributed
* @param lastUpdatedRewardTimestamp timestamp of last fixed reward update
* @param rewardPerDay current reward distributed for 1 day
* @param totalReward Full distributable reward
* @param endTimestamp end time of the distribution of rewards, which is calculated relative to the rewardPerDay and totalReward
*/
struct BucketInfo {
mapping(address => UserInfo) users;
//accumulated reward per token
uint256 rewardIndex;
uint256 lastUpdatedTimestamp;
uint256 rewardPerToken;
uint256 scaledTotalSupply;
bool isFinished;
// setted by admin's actions
uint256 fixedReward;
uint256 lastUpdatedRewardTimestamp;
uint256 rewardPerDay;
uint256 totalReward;
uint256 endTimestamp;
}
function pmx() external returns (IERC20);
function dns() external returns (IPrimexDNSV3);
function registry() external returns (address);
function traderBalanceVault() external returns (ITraderBalanceVault);
function treasury() external view returns (address);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IFeeExecutorStorage} from "./IFeeExecutorStorage.sol";
interface IFeeExecutor is IFeeExecutorStorage {
/**
* @dev Sets tier bonuses for a specific bucket.
* @param _bucket The address of the bucket.
* @param _tiers The array of tier values.
* @param _bonuses The array of NFT bonus parameters.
*/
function setTierBonus(address _bucket, uint256[] calldata _tiers, NFTBonusParams[] calldata _bonuses) external;
/**
* @dev Updates the accumulatedAmount and the lastUpdatedIndex of the existing ActivatedBonus. Called by the Debt-Token
* @param _user User for which the bonus will be updated. If user doesn't have the bonus for paused
* @param _oldScaledBalance Balance of the user before the operation at which the updateBonus function was called (e.g mint/burn)
* @param _bucket The Bucket to which the ActivatedBonus relates
**/
function updateBonus(address _user, uint256 _oldScaledBalance, address _bucket, uint256 _currentIndex) external;
/**
* @dev Updates the accumulatedAmount and the lastUpdatedIndex of the existing ActivatedBonus. Called directly by the user
* @param _nftId Id of activated token
**/
function updateBonus(uint256 _nftId) external;
/**
* @dev Updates the accumulatedAmount and the lastUpdatedIndex of the existing ActivatedBonus. Called by the P-Token or Debt-Token
* @param _users Array of the users for whom the bonus will be updated.
* @param _oldBalances Array of the balances before the operation at which the updateBonus function was called (e.g mint/transfer)
* @param _bucket The Bucket to which the ActivatedBonus relates
**/
function updateBonuses(
address[] memory _users,
uint256[] memory _oldBalances,
address _bucket,
uint256 _currentIndex
) external;
/**
* @dev Returns accumulated amount of p-tokens at the moment
* @param _user The user for which the accumatedAmount will return. If the bonus does not exist will return 0.
* If the NFT does not exist will throw an error
* @param _nftId Id of activated token
* @return The accumulated amount.
*/
function getAccumulatedAmount(address _user, uint256 _nftId) external returns (uint256);
/**
* @dev Returns the available amount (accumulated - claimedAmount) of p-tokens at the moment.
* @param _user The user for which the available amount will return. If the bonus does not exist will return 0.
* If the NFT does not exist will throw an error
* @param _nftId Id of activated token
**/
function getAvailableAmount(address _user, uint256 _nftId) external returns (uint256);
/**
* @dev Retrieves the bonus information for a user and NFT.
* @param _user The address of the user.
* @param _nftId The ID of the NFT.
* @return bonus The activated bonus information.
*/
function getBonus(address _user, uint256 _nftId) external view returns (ActivatedBonus memory);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IBucketV3} from "../Bucket/IBucket.sol";
interface IFeeExecutorStorage {
struct ActivatedBonus {
uint256 nftId;
IBucketV3 bucket;
uint256 percent;
uint256 maxAmount;
uint256 accumulatedAmount;
uint256 lastUpdatedIndex;
uint256 deadline;
//if we allow to claim funds before the end of the bonus
uint256 claimedAmount;
}
struct NFTBonusParams {
uint256 percent;
uint256 maxAmount;
uint256 duration;
}
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {IPToken} from "../PToken/IPToken.sol";
import {IDebtToken} from "../DebtToken/IDebtToken.sol";
import {IPositionManager, IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {IPriceOracle} from "../PriceOracle/IPriceOracle.sol";
import {IPrimexDNS, IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IWhiteBlackList} from "../WhiteBlackList/WhiteBlackList/IWhiteBlackList.sol";
import {IReserve} from "../Reserve/IReserve.sol";
import {ILiquidityMiningRewardDistributor} from "../LiquidityMiningRewardDistributor/ILiquidityMiningRewardDistributor.sol";
import {IInterestRateStrategy} from "../interfaces/IInterestRateStrategy.sol";
import {ISwapManager} from "../SwapManager/ISwapManager.sol";
import {IBucketStorage} from "./IBucketStorage.sol";
import {IBucketEvents} from "./IBucketEvents.sol";
interface IBucket is IBucketStorage, IBucketEvents {
struct ConstructorParams {
string name;
IPToken pToken;
IDebtToken debtToken;
IPositionManager positionManager;
IPriceOracle priceOracle;
IPrimexDNS dns;
IReserve reserve;
IWhiteBlackList whiteBlackList;
address[] assets;
IERC20Metadata borrowedAsset;
uint256 feeBuffer;
uint256 withdrawalFeeRate;
uint256 reserveRate;
// liquidityMining params
ILiquidityMiningRewardDistributor liquidityMiningRewardDistributor;
uint256 liquidityMiningAmount;
uint256 liquidityMiningDeadline;
uint256 stabilizationDuration;
IInterestRateStrategy interestRateStrategy;
uint128 estimatedBar;
uint128 estimatedLar;
uint256 maxAmountPerUser;
bool isReinvestToAaveEnabled;
bytes barCalcParams;
uint256 maxTotalDeposit;
}
event Deposit(address indexed depositer, address indexed pTokenReceiver, uint256 amount);
event DepositToAave(address indexed pool, uint256 amount);
event FeeBufferChanged(uint256 feeBuffer);
event ReserveRateChanged(uint256 reserveRate);
event RatesIndexesUpdated(
uint128 bar,
uint128 lar,
uint128 variableBorrowIndex,
uint128 liquidityIndex,
uint256 timestamp
);
event WithdrawalFeeChanged(uint256 withdrawalFeeRate);
event InterestRateStrategyChanged(address interestRateStrategy);
event AddAsset(address addedAsset);
event RemoveAsset(address deletedAsset);
event MaxTotalDepositChanged(uint256 maxTotalDeposit);
event BarCalculationParamsChanged(bytes params);
event BucketLaunched();
/**
* @dev Initializes the contract with the given parameters.
* @param _params The ConstructorParams struct containing initialization parameters.
* @param _registry The address of the registry contract.
*/
function initialize(ConstructorParams memory _params, address _registry) external;
/**
* @dev Function to add new trading asset for this bucket
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _newAsset The address of trading asset
*/
function addAsset(address _newAsset) external;
/**
* @notice Removes a trading asset from this bucket.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _assetToDelete The address of the asset to be removed.
*/
function removeAsset(address _assetToDelete) external;
/**
* @dev Sets barCalculationParams (urOptimal, k0, k1, b0, b1)
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setBarCalculationParams(bytes memory _params) external;
/**
* @dev Sets the reserve rate.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _reserveRate The new reserve rate value.
*/
function setReserveRate(uint256 _reserveRate) external;
/**
* @dev Sets the new fee buffer.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _feeBuffer The new fee buffer value.
*/
function setFeeBuffer(uint256 _feeBuffer) external;
/**
* @dev Sets the withdrawal fee.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _withdrawalFee The new withdrawal fee value.
*/
function setWithdrawalFee(uint256 _withdrawalFee) external;
/**
* @dev Sets the interest rate strategy contract address.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _interestRateStrategy The address of the interest rate strategy contract.
*/
function setInterestRateStrategy(address _interestRateStrategy) external;
/**
* @notice The function sets the max total deposit for the particular bucket
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _maxTotalDeposit The amount of max total deposit for the bucket
*/
function setMaxTotalDeposit(uint256 _maxTotalDeposit) external;
/**
* @dev Deposits the 'amount' of underlying asset into the bucket. The 'PTokenReceiver' receives overlying pTokens.
* @param _pTokenReceiver The address to receive the deposited pTokens.
* @param _amount The amount of underlying tokens to be deposited
*/
function deposit(address _pTokenReceiver, uint256 _amount) external;
/**
* @dev Withdraws the 'amount' of underlying asset from the bucket. The 'amount' of overlying pTokens will be burned.
* @param _borrowAssetReceiver The address of receiver of the borrowed asset.
* @param amount The amount of underlying tokens to be withdrawn.
*/
function withdraw(address _borrowAssetReceiver, uint256 amount) external;
/**
* @notice Allows the BIG_TIMELOCK_ADMIN role to withdraw a specified amount of tokens after delisting.
* @param _amount The amount of tokens to withdraw.
*/
function withdrawAfterDelisting(uint256 _amount) external;
/**
* @dev Receives a deposit and distributes it to the specified pToken receiver.
* @dev Can be called only by another bucket.
* @param _pTokenReceiver The address of the recipient of the pToken.
* @param _amount The amount of tokens being deposited.
* @param _duration The blocking time for a fixed-term deposit (if it's 0, then it will be a usual deposit)
* @param _bucketFrom The name of the bucket from which the deposit is being made.
*/
function receiveDeposit(
address _pTokenReceiver,
uint256 _amount,
uint256 _duration,
string memory _bucketFrom
) external;
/**
* @notice Deposits (reinvests) funds from a bucket to another bucket.
* Used only in the case of failed liquidity mining in the bucket from where the transfer happens.
* @param _bucketTo The name of the destination bucket.
* @param _swapManager The address of the swap manager.
* @param _megaRoutes The array of routes for swapping tokens.
* @param _amountOutMin The minimum amount of tokens to receive from the swap.
*/
function depositFromBucket(
string calldata _bucketTo,
ISwapManager _swapManager,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin
) external;
/**
* @dev Allows the SMALL_TIMELOCK_ADMIN to withdraw all liquidity from Aave to Bucket.
*/
function returnLiquidityFromAaveToBucket() external;
/**
* @dev Function to update rates and indexes when a trader opens a trading position.
* Mints debt tokens to trader. Calls only by positionManager contract.
* @param _trader The address of the trader, who opens position.
* @param _amount The 'amount' for which the deal is open, and 'amount' of debtTokens will be minted to the trader.
* @param _to The address to transfer the borrowed asset to.
*/
function increaseDebt(address _trader, uint256 _amount, address _to) external;
/**
* @dev Function to update rates and indexes.
* Burns debt tokens of trader. Called only by positionManager contract.
* @param _trader The address of the trader, who opened position.
* @param _debtToBurn The 'amount' of trader's debtTokens will be burned by the trader.
* @param _receiverOfAmountToReturn Treasury in case of liquidation. TraderBalanceVault in other cases
* @param _amountToReturn Amount to transfer from bucket
* @param _permanentLossAmount The amount of the protocol's debt to creditors accrued for this position
*/
function decreaseTraderDebt(
address _trader,
uint256 _debtToBurn,
address _receiverOfAmountToReturn,
uint256 _amountToReturn,
uint256 _permanentLossAmount
) external;
/**
* @notice Batch decreases the debt of multiple traders.
* @dev This function can only be called by the BATCH_MANAGER_ROLE.
* @param _traders An array of addresses representing the traders.
* @param _debtsToBurn An array of uint256 values representing the debts to burn for each trader.
* @param _receiverOfAmountToReturn The address that will receive the amount to be returned.
* @param _amountToReturn The amount to be returned.
* @param _permanentLossAmount The amount of permanent loss.
* @param _length The length of the traders array.
*/
function batchDecreaseTradersDebt(
address[] memory _traders,
uint256[] memory _debtsToBurn,
address _receiverOfAmountToReturn,
uint256 _amountToReturn,
uint256 _permanentLossAmount,
uint256 _length
) external;
/**
* @notice This function allows a user to pay back a permanent loss by burning his pTokens.
* @param amount The amount of pTokens to be burned to pay back the permanent loss.
*/
function paybackPermanentLoss(uint256 amount) external;
/**
* @dev Calculates the permanent loss based on the scaled permanent loss and the normalized income.
* @return The amount of permanent loss.
*/
function permanentLoss() external view returns (uint256);
/**
* @dev Checks if the bucket is deprecated in the protocol.
* @return Whether the bucket is deprecated or not.
*/
function isDeprecated() external view returns (bool);
/**
* @dev Returns a boolean value indicating whether the bucket is delisted.
* @return True if the bucket is delisted, otherwise false.
*/
function isDelisted() external view returns (bool);
/**
* @dev Checks if an admin can withdraw from the bucket after delisting.
* @return A boolean indicating whether withdrawal is available.
*/
function isWithdrawAfterDelistingAvailable() external view returns (bool);
/**
* @dev Checks if this bucket is active in the protocol.
* @return bool True if the bucket is active, false otherwise.
*/
function isActive() external view returns (bool);
/**
* @dev Returns the parameters for liquidity mining.
* @return LMparams The liquidity mining parameters.
*/
function getLiquidityMiningParams() external view returns (LiquidityMiningParams memory);
/**
* @dev Returns a boolean value indicating whether the bucket is stable in the liquidity mining event.
* @return A boolean value representing the stability of the bucket.
*/
function isBucketStable() external view returns (bool);
/**
* @dev Calculates the max leverage according to the following formula:
* ((1 + maintenanceBuffer) * feeBuffer) / ((1 + maintenanceBuffer) * feeBuffer - (1 - securityBuffer) *
* (1 - pairPriceDropBA) * (1 - oracleTolerableLimitAB) * (1 - oracleTolerableLimitBA))
* @param _asset The address of trading asset
* @return The maximum leverage as a uint256 value.
*/
function maxAssetLeverage(address _asset) external view returns (uint256);
/**
* @dev Returns the normalized income per unit of underlying asset, expressed in ray
* @return The normalized income per unit of underlying asset, expressed in ray
*/
function getNormalizedIncome() external view returns (uint256);
/**
* @dev Returns the normalized variable debt per unit of underlying asset, expressed in ray
*/
function getNormalizedVariableDebt() external view returns (uint256);
/**
* @dev Returns allowed trading assets for current bucket
* @return List of addresses of allowed assets
*/
function getAllowedAssets() external view returns (address[] memory);
/**
* @dev Returns current avalable liquidity of borrowedAsset for trading.
* @return The amount of available borrowedAsset
*/
function availableLiquidity() external view returns (uint256);
}
interface IBucketV2 is IBucket {
/**
* @dev Deposits the 'amount' of underlying asset into the bucket. The 'PTokenReceiver' receives overlying pTokens.
* @param _pTokenReceiver The address to receive the deposited pTokens.
* @param _amount The amount of underlying tokens to be deposited
* @param _takeDepositFromWallet A flag indicating whether to make the deposit from user wallet
*/
function deposit(address _pTokenReceiver, uint256 _amount, bool _takeDepositFromWallet) external;
}
interface IBucketV3 is IBucketV2 {
event ChangedBucketExtension(address newBucketExtension);
/**
* @dev Calculates the max leverage according to the following formula:
* ((1 + maintenanceBuffer) * feeBuffer) / ((1 + maintenanceBuffer) * feeBuffer - (1 - securityBuffer) *
* (1 - pairPriceDropBA) * (1 - oracleTolerableLimitAB) * (1 - oracleTolerableLimitBA) + protocolFeeInPositiontAsset / positionSize)
* @param _asset The address of trading asset
* @param _feeRate The ratio of protocolFeeInPositionAsset to positionSize
* @return The maximum leverage as a uint256 value.
*/
function maxAssetLeverage(address _asset, uint256 _feeRate) external view returns (uint256);
/**
* @notice Sets the bucketExtension.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _newBucketExtension The address of BucketExtension contract.
*/
function setBucketExtension(address _newBucketExtension) external;
}
interface IBucketV4 is IBucketV3 {
/**
* @notice Performs a flash loan transfer of a specified amount to a receiver address.
* @dev Only callable by the FLASH_LOAN_MANAGER_ROLE role.
* @param _to The address to which the flash loan amount will be transferred.
* @param _amount The amount of tokens to transfer in the flash loan.
*/
function performFlashLoanTransfer(address _to, uint256 _amount) external;
/**
* @notice Accumulates a predefined amount of asset to the bucket as a fixed, instantaneous income. Used
* to accumulate the flashloan fee to the bucket, and spread it between all the suppliers.
* @dev Only callable by the FLASH_LOAN_MANAGER_ROLE role.
* @param amount The amount to accumulate
* @param availableLiquidity The availableLiquidity before flashLoan
*/
function cumulateToLiquidityIndex(uint256 amount, uint256 availableLiquidity) external;
/**
* @notice Updates bucket's BAR and LAR.
* @dev Only callable by the FLASH_LOAN_MANAGER_ROLE role.
*/
function updateRates() external;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IBucketEvents {
event WithdrawFromAave(address indexed pool, uint256 amount);
event Withdraw(address indexed withdrawer, address indexed borrowAssetReceiver, uint256 amount);
event TopUpTreasury(address indexed sender, uint256 amount);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IPToken} from "../PToken/IPToken.sol";
import {IDebtToken} from "../DebtToken/IDebtToken.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {IPriceOracleV2} from "../PriceOracle/IPriceOracle.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IReserve} from "../Reserve/IReserve.sol";
import {ILiquidityMiningRewardDistributor} from "../LiquidityMiningRewardDistributor/ILiquidityMiningRewardDistributor.sol";
import {IWhiteBlackList} from "../WhiteBlackList/WhiteBlackList/IWhiteBlackList.sol";
import {IInterestRateStrategy} from "../interfaces/IInterestRateStrategy.sol";
interface IBucketStorage {
/**
* @dev Parameters of liquidity mining
*/
struct LiquidityMiningParams {
ILiquidityMiningRewardDistributor liquidityMiningRewardDistributor;
bool isBucketLaunched;
uint256 accumulatingAmount;
uint256 deadlineTimestamp;
uint256 stabilizationDuration;
uint256 stabilizationEndTimestamp;
uint256 maxAmountPerUser; // if maxAmountPerUser is >= accumulatingAmount then check on maxAmountPerUser is off
// Constant max variables are used for calculating users' points.
// These intervals are used for fair distribution of points among Lenders.
// Lenders who brought liquidity earlier receive more than the ones who deposited later.
// To get maximum points per token, a Lender should deposit immediately after the Bucket deployment.
uint256 maxDuration;
uint256 maxStabilizationEndTimestamp;
}
// 1. Corner case of bucket launch
//
// maxDuration
// ------------------------------------------------------------------------------------------------
// | |
// | stabilizationDuration |
// | -------------------------|
// | | bucket launch |
// +--+---------------------------------------------------------------------+-------------------------+------> time
// bucket deploy deadlineTimestamp maxStabilizationEndTimestamp
// (=stabilizationEndTimestamp here)
// (corner case of bucket launch)
// 2. One of cases of bucket launch
//
// | stabilizationDuration
// | -------------------------
// | | |
// +--+------------------+-------------------------+------------------------+-------------------------+------> time
// bucket deploy bucket launch stabilizationEndTimestamp deadlineTimestamp maxStabilizationEndTimestamp
// (after deadline bucket can't be launched)
struct Asset {
uint256 index;
bool isSupported;
}
function liquidityIndex() external returns (uint128);
function variableBorrowIndex() external returns (uint128);
function name() external view returns (string memory);
function registry() external view returns (address);
function positionManager() external view returns (IPositionManagerV2);
function reserve() external view returns (IReserve);
function permanentLossScaled() external view returns (uint256);
function pToken() external view returns (IPToken);
function debtToken() external view returns (IDebtToken);
function borrowedAsset() external view returns (IERC20Metadata);
function feeBuffer() external view returns (uint256);
function withdrawalFeeRate() external view returns (uint256);
/**
* @notice bar = borrowing annual rate (originally APR)
*/
function bar() external view returns (uint128);
/**
* @notice lar = lending annual rate (originally APY)
*/
function lar() external view returns (uint128);
function interestRateStrategy() external view returns (IInterestRateStrategy);
function estimatedBar() external view returns (uint128);
function estimatedLar() external view returns (uint128);
function allowedAssets(address _asset) external view returns (uint256, bool);
function whiteBlackList() external view returns (IWhiteBlackList);
function maxTotalDeposit() external view returns (uint256);
}
interface IBucketStorageV2 {
function bucketExtension() external view returns (address);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {IArbGasInfo} from "./interfaces/IArbGasInfo.sol";
import {IOVM_GasPriceOracle} from "./interfaces/IOVM_GasPriceOracle.sol";
// admin roles
bytes32 constant BIG_TIMELOCK_ADMIN = 0x00; // It's primary admin.
bytes32 constant MEDIUM_TIMELOCK_ADMIN = keccak256("MEDIUM_TIMELOCK_ADMIN");
bytes32 constant SMALL_TIMELOCK_ADMIN = keccak256("SMALL_TIMELOCK_ADMIN");
bytes32 constant EMERGENCY_ADMIN = keccak256("EMERGENCY_ADMIN");
bytes32 constant GUARDIAN_ADMIN = keccak256("GUARDIAN_ADMIN");
bytes32 constant NFT_MINTER = keccak256("NFT_MINTER");
bytes32 constant TRUSTED_TOLERABLE_LIMIT_ROLE = keccak256("TRUSTED_TOLERABLE_LIMIT_ROLE");
// inter-contract interactions roles
bytes32 constant NO_FEE_ROLE = keccak256("NO_FEE_ROLE");
bytes32 constant VAULT_ACCESS_ROLE = keccak256("VAULT_ACCESS_ROLE");
bytes32 constant PM_ROLE = keccak256("PM_ROLE");
bytes32 constant LOM_ROLE = keccak256("LOM_ROLE");
bytes32 constant BATCH_MANAGER_ROLE = keccak256("BATCH_MANAGER_ROLE");
bytes32 constant FLASH_LOAN_MANAGER_ROLE = keccak256("FLASH_LOAN_MANAGER_ROLE");
bytes32 constant FLASH_LOAN_FREE_BORROWER_ROLE = keccak256("FLASH_LOAN_FREE_BORROWER_ROLE");
// token constants
address constant NATIVE_CURRENCY = address(uint160(bytes20(keccak256("NATIVE_CURRENCY"))));
address constant USD = 0x0000000000000000000000000000000000000348;
address constant NATIVE_CURRENCY_CURVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 constant USD_MULTIPLIER = 10 ** (18 - 8); // usd decimals in chainlink is 8
uint8 constant MAX_ASSET_DECIMALS = 18;
// time constants
uint256 constant SECONDS_PER_YEAR = 365 days;
uint256 constant SECONDS_PER_DAY = 1 days;
uint256 constant HOUR = 1 hours;
uint256 constant TEN_WAD = 10 ether;
// constants for Arbitrum payment model
IArbGasInfo constant ARB_NITRO_ORACLE = IArbGasInfo(0x000000000000000000000000000000000000006C);
uint256 constant TRANSACTION_METADATA_BYTES = 140;
IOVM_GasPriceOracle constant OVM_GASPRICEORACLE = IOVM_GasPriceOracle(0x420000000000000000000000000000000000000F);
uint256 constant GAS_FOR_BYTE = 16;// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import {IDebtTokenStorage, IBucket, IFeeExecutor, IERC20Upgradeable, IActivityRewardDistributor} from "./IDebtTokenStorage.sol";
interface IDebtToken is IDebtTokenStorage {
/**
* @dev Emitted after the mint action
* @param from The address performing the mint
* @param value The amount being
**/
event Mint(address indexed from, uint256 value);
/**
* @dev Emitted after DebtTokens are burned
* @param from The owner of the aTokens, getting them burned
* @param value The amount being burned
**/
event Burn(address indexed from, uint256 value);
/**
* @dev contract initializer
* @param _name The name of the ERC20 token.
* @param _symbol The symbol of the ERC20 token.
* @param _decimals The number of decimals for the ERC20 token.
* @param _bucketsFactory Address of the buckets factory that will call the setBucket fucntion
*/
function initialize(string memory _name, string memory _symbol, uint8 _decimals, address _bucketsFactory) external;
/**
* @dev Sets the bucket for the contract.
* @param _bucket The address of the bucket to set.
*/
function setBucket(IBucket _bucket) external;
/**
* @dev Sets the FeeDecreaser for current DebtToken.
* @param _feeDecreaser The interest increaser address.
*/
function setFeeDecreaser(IFeeExecutor _feeDecreaser) external;
/**
* @dev Sets the trader reward distributor contract address.
* @param _traderRewardDistributor The address of the trader reward distributor contract.
* Only the BIG_TIMELOCK_ADMIN role can call this function.
*/
function setTraderRewardDistributor(IActivityRewardDistributor _traderRewardDistributor) external;
/**
* @dev Mints `amount` DebtTokens to `user`
* @param _user The address receiving the minted tokens
* @param _amount The amount of tokens getting minted
* @param _index The current variableBorrowIndex
*/
function mint(address _user, uint256 _amount, uint256 _index) external;
/**
* @dev Burns DebtTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @param _user The owner of the DebtTokens, getting them burned
* @param _amount The amount being burned
* @param _index The current variableBorrowIndex
**/
function burn(address _user, uint256 _amount, uint256 _index) external;
/**
* @dev Burns a batch of tokens from multiple users.
* @param _users An array of user addresses whose tokens will be burned.
* @param _amounts An array of token amounts to be burned for each user.
* @param _index The index used to calculate the scaled amounts.
* @param _length The length of the user and amounts arrays.
*/
function batchBurn(address[] memory _users, uint256[] memory _amounts, uint256 _index, uint256 _length) external;
/**
* @dev Returns the principal debt balance of the user
* @param _user The address of the user.
* @return The scaled balance of the user.
*/
function scaledBalanceOf(address _user) external view returns (uint256);
/**
* @dev Returns the scaled total supply of debtToken.
* @return The scaled total supply of the debtToken.
*/
function scaledTotalSupply() external view returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IBucket, IBucketV3} from "../Bucket/IBucket.sol";
import {IFeeExecutor} from "../BonusExecutor/IFeeExecutor.sol";
import {IActivityRewardDistributor} from "../ActivityRewardDistributor/IActivityRewardDistributor.sol";
interface IDebtTokenStorage is IERC20Upgradeable {
function bucket() external view returns (IBucketV3);
function feeDecreaser() external view returns (IFeeExecutor);
function traderRewardDistributor() external view returns (IActivityRewardDistributor);
}// Copyright 2020 Compound Labs, Inc.
// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.8.10;
/**
* @title EIP20NonStandardInterface
* @dev Version of ERC20 with no return values for `transfer` and `transferFrom`
* See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
*/
interface EIP20NonStandardInterface {
/**
* @notice Get the total number of tokens in circulation
* @return The supply of tokens
*/
function totalSupply() external view returns (uint256);
/**
* @notice Gets the balance of the specified address
* @param owner The address from which the balance will be retrieved
* @return balance The balance
*/
function balanceOf(address owner) external view returns (uint256 balance);
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transfer(address dst, uint256 amount) external;
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
*/
function transferFrom(address src, address dst, uint256 amount) external;
///
/// !!!!!!!!!!!!!!
/// !!! NOTICE !!! `approve` does not return a value, in violation of the ERC-20 specification
/// !!!!!!!!!!!!!!
///
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved
*/
function approve(address spender, uint256 amount) external;
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return remaining The number of tokens allowed to be spent
*/
function allowance(address owner, address spender) external view returns (uint256 remaining);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
}pragma solidity ^0.8.18;
/// Precompiled contract that exists in every Arbitrum Nitro chain at 0x000000000000000000000000000000000000006c.
interface IArbGasInfo {
// get ArbOS's estimate of the L1 gas price in wei
function getL1BaseFeeEstimate() external view returns (uint256);
/// @notice Get gas prices. Uses the caller's preferred aggregator, or the default if the caller doesn't have a preferred one.
/// @return return gas prices in wei
/// (
/// per L2 tx,
/// per L1 calldata byte
/// per storage allocation,
/// per ArbGas base,
/// per ArbGas congestion,
/// per ArbGas total
/// )
function getPricesInWei() external view returns (uint256, uint256, uint256, uint256, uint256, uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {ILimitOrderManager} from "../LimitOrderManager/ILimitOrderManager.sol";
interface IBestDexLens {
/**
* @dev Structure for the getBestDexForOpenablePosition function
* @param positionManager Instance of the PositionManager
* @param borrowedAsset The address of the borrowed asset of this `bucket`
* @param borrowedAmount The amount of borrowed token in this position
* @param depositAsset The address of the deposited asset
* @param depositAmount The amount of deposited trader funds of open position
* @param positionAsset The address of the bought asset of open position
* @param shares The number of parts into which the swap will be divided
* @param dexes An array with dexes by which the algorithm will iterate
*/
struct BestDexForOpenablePositionParams {
IPositionManagerV2 positionManager;
address borrowedAsset;
uint256 borrowedAmount;
address depositAsset;
uint256 depositAmount;
address positionAsset;
Shares shares;
DexWithAncillaryData[] dexes;
}
/**
* @dev Structure for different shares for swap
* @param firstAssetShares Shares for swap first asset to position asset
* @param depositInThirdAssetShares Shares for swap deposit asset to third asset
* @param depositToBorrowedShares Shares for swap deposit asset to borrowed asset
*/
struct Shares {
uint256 firstAssetShares;
uint256 depositInThirdAssetShares;
uint256 depositToBorrowedShares;
}
/**
* @param dex The name of dex
* @param ancillaryData Additional data required for certain dex type.
*/
struct DexWithAncillaryData {
string dex;
bytes32 ancillaryData;
}
/**
* @dev Structure for the getBestDexByOrderParams function
* @param positionManager instance of the PositionManager
* @param limitOrderManager instance of the LimitOrderManager
* @param orderId order id
* @param dexes dexes with ancillary data
*/
struct BestDexByOrderParams {
IPositionManagerV2 positionManager;
ILimitOrderManager limitOrderManager;
uint256 orderId;
Shares shares;
DexWithAncillaryData[] dexes;
bytes depositBorrowedAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
/**
* @dev Structure for the input params for getBestMultipleDexes
* @param positionManager instance of the PositionManager
* @param assetToBuy address
* @param assetToSell address
* @param amount amount to sell or amount to buy depending on the isAmountToBuy
* @param isAmountToBuy if true, then the best value, found via getAmountsIn
* @param shares The number of parts into which the swap will be divided
* @param gasPriceInCheckedAsset gas Price in asset to sell or asset to buy depending on the isAmountToBuy
* @param dexes An array with dexes by which the algorithm will iterate
*/
struct GetBestMultipleDexesParams {
IPositionManagerV2 positionManager;
address assetToBuy;
address assetToSell;
uint256 amount;
bool isAmountToBuy;
uint256 shares;
uint256 gasPriceInCheckedAsset;
DexWithAncillaryData[] dexes;
}
/**
* @dev Structure for the getBestMultipleDexes function
* @param shareCount Number of shares
* @param filledRoutes Number of filled routes
* @param path Path of assets
* @param activeDexesLength Count of active dexes
* @param gasInCheckedAsset The paid price for gas in the purchase token
* @param gases Estimated gas to perform swap on each dex
*/
struct GetBestMultipleDexesVars {
uint256 shareCount;
uint256 filledRoutes;
address[] path;
uint256 activeDexesLength;
int256 gasInCheckedAsset;
uint256[] gases;
}
/**
* @dev Structure for the return params for getBestMultipleDexes
* @param returnAmount expected return amount
* @param estimateGasAmount expected fee amount
* @param routes swap routes on dexes
*/
struct GetBestMultipleDexesReturnParams {
uint256 returnAmount;
uint256 estimateGasAmount;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
}
/**
* @dev Structure for the function getBestDex through the buy parameters
* @param assetToBuy Asset to buy on the dex(=_positionAsset in function openPosition)
* @param assetToSell Asset for sell on the dex(= an asset borrowed from a bucket)
* @param amountToSell Amount `assetToSell`(=borrowedAmount in function openPosition)
*/
struct BuyData {
address assetToBuy;
address assetToSell;
uint256 amountToSell;
}
/**
* @dev Structure for the getBestDexByOrder function
* @param firstAssetReturnParams GetBestMultipleDexesReturnParams for the first asset to position asset
* @param depositInThirdAssetReturnParams GetBestMultipleDexesReturnParams for deposit asset to third asset
* @param depositToBorrowedReturnParams GetBestMultipleDexesReturnParams for deposit asset to borrowed asset
*/
struct GetBestDexByOrderReturnParams {
GetBestMultipleDexesReturnParams firstAssetReturnParams;
GetBestMultipleDexesReturnParams depositInThirdAssetReturnParams;
GetBestMultipleDexesReturnParams depositToBorrowedReturnParams;
}
/**
* @notice Returns swap paths on best dexes, expected amount and estimateGasAmount.
* @dev This function calculates the best DEX to use for a given position based on various parameters.
* @param _positionManager The instance of the PositionManager contract.
* @param _positionId The ID of the position.
* @param _shares The number of shares for dexes.
* @param _dexesWithAncillaryData An array of DEXes along with their ancillary data.
* @return A GetBestMultipleDexesReturnParams struct.
*/
function getBestDexByPosition(
IPositionManagerV2 _positionManager,
uint256 _positionId,
uint256 _shares,
DexWithAncillaryData[] memory _dexesWithAncillaryData
) external returns (GetBestMultipleDexesReturnParams memory);
/**
* @notice Selects the best dex to open position by order.
* @param _params The BestDexByOrderParams struct specifying the order parameters.
* @return _returnParams The GetBestDexByOrderReturnParams struct
*/
function getBestDexByOrder(
BestDexByOrderParams memory _params
) external payable returns (GetBestDexByOrderReturnParams memory _returnParams);
/**
* @notice Selects the best multiple dexes to open a position
* @param _params GetBestMultipleDexesParams params
* @return _returnParams - the array of best dexes at the moment to open a position with the specified parameters
*/
function getBestMultipleDexes(
GetBestMultipleDexesParams memory _params
) external returns (GetBestMultipleDexesReturnParams memory _returnParams);
/**
* @notice Returns the best DEXes for opening a position.
* @param _params The parameters for the function.
* @return _firstAssetReturnParams The return parameters for the first asset.
* @return _depositInThirdAssetReturnParams The return parameters includes routes for converting a third asset
* (i.e. an asset which is not either underlying asset or position asset) to a position asset.
* @return _depositToBorrowedReturnParams The return parameters for converting deposit asset (which is a position
* asset or third asset) to borrowed asset (i.e. underlying asset).
*/
function getBestDexForOpenablePosition(
BestDexForOpenablePositionParams memory _params
)
external
returns (
GetBestMultipleDexesReturnParams memory _firstAssetReturnParams,
GetBestMultipleDexesReturnParams memory _depositInThirdAssetReturnParams,
GetBestMultipleDexesReturnParams memory _depositToBorrowedReturnParams
);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
interface IConditionalClosingManager {
/**
* @notice Checks if a position can be closed.
* @param _position The position details.
* @param _params The encoded parameters for closing the position.
* @param _additionalParams Additional encoded parameters (not used).
* @param _closeAmount The amount of the position to be closed, measured in the same decimal format as the position's asset.
* @param _borowedAssetAmount The amount of borrowed asset.
* @return A boolean indicating whether the position can be closed.
*/
function canBeClosedAfterSwap(
PositionLibrary.Position calldata _position,
bytes calldata _params,
bytes calldata _additionalParams,
uint256 _closeAmount,
uint256 _borowedAssetAmount,
bytes calldata _positionSoldAssetOracleData
) external payable returns (bool);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
interface IConditionalOpeningManager {
/**
* @notice Checks if a limit order can be filled based on the exchange rate.
* @dev This function compares the exchange rate with the limit price.
* @param _order The limit order details.
* @param _params Open condition parameters for the order.
* @param _additionalParams Additional parameters for the order.
* @param _exchangeRate The exchange rate in WAD format to compare with the limit price.
* @return A boolean value indicating if the limit order can be filled based on the exchange rate.
*/
function canBeFilledAfterSwap(
LimitOrderLibrary.LimitOrder calldata _order,
bytes calldata _params,
bytes calldata _additionalParams,
uint256 _exchangeRate
) external pure returns (bool);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IQuoter} from "@uniswap/v3-periphery/contracts/interfaces/IQuoter.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ICurveCalc} from "./routers/ICurveCalc.sol";
import {ICurveRegistry} from "./routers/ICurveRegistry.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
interface IDexAdapter {
/**
* @notice Possible dex types
*/
enum DexType {
none, // 0
UniswapV2, // 1 "uniswap", "sushiswap", "quickswap" (v2)
UniswapV3, // 2
Curve, // 3
Balancer, // 4
AlgebraV3, // 5
Meshswap, // 6
Paraswap, //7
Enso //8
}
/*
* @param encodedPath Swap path encoded in bytes
* Encoded differently for different dexes:
* Uniswap v2 - just encoded array of asset addresses
* Uniswap v3 - swap path is a sequence of bytes. In Solidity, a path can be built like that:
* bytes.concat(bytes20(address(weth)), bytes3(uint24(pool1Fee)), bytes20(address(usdc)), bytes3(uint24(pool2Fee)) ...)
* Quickswap - swap path is a sequence of bytes. In Solidity, a path can be built like that:
* bytes.concat(bytes20(address(weth)), bytes20(address(usdc)), bytes20(address(usdt) ...)
* Curve - encoded array of asset addresses and pool addresses
* Balancer - encoded array of asset addresses, pool ids and asset limits
* @param _amountIn TokenA amount in
* @param _amountOutMin Min tokenB amount out
* @param _to Destination address for swap
* @param _deadline Timestamp deadline for swap
* @param _dexRouter Dex router address
*/
struct SwapParams {
bytes encodedPath;
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 amountOutMin;
address to;
uint256 deadline;
address dexRouter;
}
/*
* @param encodedPath Swap path encoded in bytes
* @param _amountIn TokenA amount in
* @param _dexRouter Dex router address
*/
struct GetAmountsParams {
bytes encodedPath;
uint256 amount; // amountIn or amountOut
address dexRouter;
}
struct AmountParams {
address tokenA;
address tokenB;
uint256 amount;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
}
struct MegaSwapVars {
uint256 sumOfShares;
uint256 amountOnMegaRoute;
uint256 totalAmount;
uint256 remainder;
}
event QuoterChanged(address indexed dexRouter, address indexed quoter);
event DexTypeChanged(address indexed dexRouter, uint256 indexed dexType);
/**
* @param _dexRouter The router address for which the quoter is set
* @param _quoter The quoter address to set
*/
function setQuoter(address _dexRouter, address _quoter) external;
/**
* @notice Set a dex type for a dex router
* @param _dexRouter The dex router address
* @param _dexType The dex type from enum DexType
*/
function setDexType(address _dexRouter, uint256 _dexType) external;
/**
* @notice Swap ERC20 tokens
* @param _params SwapParams struct
*/
function swapExactTokensForTokens(SwapParams memory _params) external payable returns (uint256[3] memory);
/**
* @notice Performs chained getAmountOut calculations
* @notice given an input amount of an asset, returns the maximum output amount of the other asset
* @param _params GetAmountsParams struct
*/
function getAmountsOut(GetAmountsParams memory _params) external returns (uint256[3] memory);
/**
* @notice Performs chained getAmountIn calculations
* @notice given an output amount of an asset, returns the maximum input amount of the other asset
* @param _params GetAmountsParams struct
*/
function getAmountsIn(GetAmountsParams memory _params) external returns (uint256[3] memory);
/**
* @notice Dex type mapping dexRouter => dex type
*/
function dexType(address) external view returns (DexType);
/**
* @notice Mapping from the dexRouter to its quoter
*/
function quoters(address) external view returns (address);
/**
* @return The address of the Registry contract
*/
function registry() external view returns (address);
/**
* @notice Gets the average amount of gas that is required for the swap on some dex
* @param dexRouter The address of a router
*/
function getGas(address dexRouter) external view returns (uint256);
/**
* @notice perform swap of ERC20 tokens by Path structs
* @param tokenIn source token
* @param tokenOut destination token
* @param amountIn amount in the source token
* @param receiver destination address for swap
* @param paths Array of Path structs
*/
function performPathsSwap(
address tokenIn,
address tokenOut,
uint256 amountIn,
address receiver,
PrimexPricingLibrary.Path[] calldata paths
) external payable returns (uint256);
/**
@notice Performs chained getAmountOut calculations by Path structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param amountIn amount in the source token
* @param paths Array of Path structs
*/
function getAmountsOutByPaths(
uint256 amountIn,
PrimexPricingLibrary.Path[] calldata paths
) external returns (uint256);
/**
@notice Performs chained getAmountsIn calculations by Path structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param amountOut amount in the destination token
* @param paths Array of Path structs
*/
function getAmountsInByPaths(
uint256 amountOut,
PrimexPricingLibrary.Path[] calldata paths
) external returns (uint256);
/**
@notice perform swap of ERC20 tokens by MegaRoute structs
* @param _params MegaSwapParams struct
*/
function performMegaRoutesSwap(
PrimexPricingLibrary.MegaSwapParams calldata _params
) external payable returns (uint256);
/**
* @notice perform swap of ERC20 tokens by Route structs
* @param tokenIn source token
* @param amountIn amount in the source token
* @param receiver destination address for swap
* @param routes Array of Route structs
*/
function performRoutesSwap(
address tokenIn,
uint256 amountIn,
address receiver,
PrimexPricingLibrary.Route[] calldata routes
) external payable returns (uint256);
/**
@notice Performs chained getAmountsOut calculations by Route structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param amountIn amount in the source token
* @param routes Array of Route structs
*/
function getAmountsOutByRoutes(
uint256 amountIn,
PrimexPricingLibrary.Route[] calldata routes
) external returns (uint256);
/**
@notice Performs chained getAmountsOut calculations by MegaRoute structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param _params AmountParams struct
*/
function getAmountOutByMegaRoutes(AmountParams calldata _params) external returns (uint256);
/**
@notice Performs chained getAmountsIn calculations by Route structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param amountOut amountin the destination token
* @param routes Array of Route structs
*/
function getAmountsInByRoutes(
uint256 amountOut,
PrimexPricingLibrary.Route[] calldata routes
) external returns (uint256);
/**
@notice Performs chained getAmountsIn calculations by MegaRoute structs
@dev The function may not support some types of dex, e.g. the Paraswap
* @param _params AmountParams struct
*/
function getAmountInByMegaRoutes(AmountParams calldata _params) external returns (uint256);
receive() external payable;
/**
* @notice Initializes the DexAdapter contract.
* @dev This function should only be called once during the initial setup of the contract.
* @param _primexDNS The address of the PrimexDNS contract.
*/
function initialize(address _primexDNS) external;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IInterestRateStrategy {
/**
* @dev parameters for BAR calculation - they differ depending on bucket's underlying asset
*/
struct BarCalculationParams {
uint256 urOptimal;
uint256 k0;
uint256 k1;
uint256 b0;
int256 b1;
}
event BarCalculationParamsChanged(
address indexed bucket,
uint256 urOptimal,
uint256 k0,
uint256 k1,
uint256 b0,
int256 b1
);
/**
* @dev Updates bucket's BAR and LAR.
* Calculates using utilization ratio (UR):
* BAR = UR <= URoptimal ? (k0 * UR + b0) : (k1 * UR + b1), where 'b1' may be < 0,
* LAR = BAR * UR,
* if reserveRate != 0, then LAR = LAR * (1 - reserveRate)
* @param ur Utilization ratio
* @param reserveRate The reserve portion of the interest that goes to the Primex reserve
* @return tuple containing BAR and LAR
*/
function calculateInterestRates(uint256 ur, uint256 reserveRate) external returns (uint128, uint128);
/**
* @dev Set parameters for BAR calculation.
* @param _params parameters are represented in byte string
*/
function setBarCalculationParams(bytes memory _params) external;
/**
* @dev Retrieves the calculation parameters for the Bar calculation.
* @param _address an address of the bucket
* @return BarCalculationParams struct containing the parameters.
*/
function getBarCalculationParams(address _address) external view returns (BarCalculationParams memory);
}pragma solidity ^0.8.18;
/// Precompiled contract that exist on opBNB chain at 0x420000000000000000000000000000000000000F.
interface IOVM_GasPriceOracle {
/// @notice Retrieves the latest known L1 base fee.
/// @return Latest known L1 base fee.
function l1BaseFee() external view returns (uint256);
/// @notice Retrieves the current fee overhead.
/// @return Current fee overhead.
function overhead() external view returns (uint256);
/// @notice Retrieves the current fee scalar.
/// @return Current fee scalar.
function scalar() external view returns (uint256);
}// Copyright (c) 2016-2024 zOS Global Limited and contributors
// SPDX-License-Identifier: MIT
// Interface for OpenZeppelin's Pausable contract from https://github.com/OpenZeppelin/openzeppelin-contracts/
pragma solidity ^0.8.18;
interface IPausable {
/**
* @dev Triggers stopped state.
* This function can only be called by an address with the EMERGENCY_ADMIN role.
* Requirements:
*
* - The contract must not be paused.
*/
function pause() external;
/**
* @dev Returns to normal state.
* This function can only be called by an address with the SMALL_TIMELOCK_ADMIN or MEDIUM_TIMELOCK_ADMIN role depending on the contract.
* Requirements:
*
* - The contract must be paused.
*/
function unpause() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
interface ISupraOraclePull {
//Verified price data
struct PriceData {
// List of pairs
uint256[] pairs;
// List of prices
// prices[i] is the price of pairs[i]
uint256[] prices;
// List of decimals
// decimals[i] is the decimals of pairs[i]
uint256[] decimals;
}
function verifyOracleProof(bytes calldata _bytesproof) external returns (PriceData memory);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/* solhint-disable var-name-mixedcase */
interface ISupraSValueFeed {
struct derivedData {
int256 roundDifference;
uint256 derivedPrice;
uint256 decimals;
}
struct priceFeed {
uint256 round;
uint256 decimals;
uint256 time;
uint256 price;
}
function getDerivedSvalue(
uint256 pair_id_1,
uint256 pair_id_2,
uint256 operation
) external view returns (derivedData memory);
function getSvalue(uint256 _pairIndex) external view returns (priceFeed memory);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
interface ITakeProfitStopLossCCM {
struct CanBeClosedParams {
uint256 takeProfitPrice;
uint256 stopLossPrice;
}
/**
* @notice Checks if the take profit has been reached based on the given parameters.
* @dev Used in closeBatchPositions() function.
* @param _params The encoded parameters.
* @param exchangeRate The exchange rate in WAD format.
* @return A boolean indicating whether the take profit has been reached.
*/
function isTakeProfitReached(bytes calldata _params, uint256 exchangeRate) external view returns (bool);
/**
* @notice Checks if the stop loss price has been reached for a given position.
* @param _position The position details.
* @param _stopLossPrice The stop loss price in WAD format to compare against.
* @return True if the stop loss price is reached, false otherwise.
*/
function isStopLossReached(
PositionLibrary.Position calldata _position,
uint256 _stopLossPrice,
bytes calldata _positionSoldAssetOracleData
) external returns (bool);
/**
* @notice Checks if the stop loss price has been reached on the given parameters.
* @dev The takeProfitPrice and stopLossPrice values can be obtained from the encoded data via CanBeClosedParams struct.
* @param _params The encoded closing condition parameters containing stop loss price.
* @param oracleExchangeRate The current exchange rate from the oracle in WAD format.
* @return True if the stop loss price is reached, false otherwise.
*/
function isStopLossReached(bytes calldata _params, uint256 oracleExchangeRate) external view returns (bool);
/**
* @notice Retrieves the take profit and stop loss prices from the given parameters.
* @param _params The encoded parameters for closing a position.
* @return takeProfitPrice The take profit price.
* @return stopLossPrice The stop loss price.
*/
function getTakeProfitStopLossPrices(bytes calldata _params) external view returns (uint256, uint256);
/**
* @notice Initializes the TakeProfitStopLossCCM contract.
* @dev This function should only be called once during the initial setup of the contract.
* @param _primexDNS The address of the PrimexDNS contract.
* @param _priceOracle The address of the PriceOracle contract.
*/
function initialize(address _primexDNS, address _priceOracle) external;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface ICurveCalc {
// solhint-disable func-name-mixedcase
function get_dx(
// solhint-disable-next-line var-name-mixedcase
int128 n_coins,
uint256[8] memory balances,
uint256 amp,
uint256 fee,
uint256[8] memory rates,
uint256[8] memory precisions,
bool underlying,
int128 i,
int128 j,
uint256 dy
) external pure returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface ICurveRegistry {
// solhint-disable func-name-mixedcase
function get_n_coins(address _pool) external view returns (uint256[2] memory);
function get_rates(address _pool) external view returns (uint256[8] memory);
function get_coin_indices(address _pool, address _from, address _to) external view returns (int128, int128, bool);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IKeeperRewardDistributorStorage, IKeeperRewardDistributorStorageV2} from "./IKeeperRewardDistributorStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface IKeeperRewardDistributorV3 is IKeeperRewardDistributorStorageV2, IPausable {
struct DecreasingGasByReasonParams {
DecreasingReason reason;
uint256 amount;
}
struct MaxGasPerPositionParams {
KeeperActionType actionType;
KeeperActionRewardConfig config;
}
/**
* @dev Params for initialize() function
* @param priceOracle Address of the PriceOracle contract
* @param registry Address of the Registry contract
* @param pmx Address of PMXToken
* @param treasury Address of the Treasury contract
* @param pmxPartInReward Percentage of PMX in reward (in WAD)
* @param nativePartInReward Percentage of native token in reward (in WAD)
* @param positionSizeCoefficient The reward param which is needed to calculate rewards, in WAD
* @param additionalGas Additional gas added to actual gas spent
* @param defaultMaxGasPrice Max gas price allowed during reward calculation (used when no oracle price found)
* @param oracleGasPriceTolerance Percentage by which oracle gas price can be exceeded (in WAD)
* @param paymentModel The model of payment for gas in the network
* @param maxGasPerPositionParams Parameters for the setMaxGasPerPosition function
* @param decreasingGasByReasonParams Parameters for the setDecreasingGasByReason function
*/
struct InitParams {
address priceOracle;
address registry;
address pmx;
address treasury;
address whiteBlackList;
uint256 pmxPartInReward;
uint256 nativePartInReward;
uint256 positionSizeCoefficient;
uint256 additionalGas;
uint256 defaultMaxGasPrice;
uint256 oracleGasPriceTolerance;
PaymentModel paymentModel;
MaxGasPerPositionParams[] maxGasPerPositionParams;
DecreasingGasByReasonParams[] decreasingGasByReasonParams;
}
event ClaimFees(address indexed keeper, address indexed asset, uint256 amount);
event DefaultMaxGasPriceChanged(uint256 indexed defaultMaxGasPrice);
event OracleGasPriceToleranceChanged(uint256 indexed oracleGasPriceTolerance);
event MaxGasPerPositionChanged(KeeperActionType indexed actionType, KeeperActionRewardConfig config);
event DataLengthRestrictionsChanged(KeeperCallingMethod callingMethod, uint256 maxRoutesLength, uint256 baseLength);
event DecreasingGasByReasonChanged(DecreasingReason indexed reason, uint256 amount);
event PmxPartInRewardChanged(uint256 indexed pmxPartInReward);
event NativePartInRewardChanged(uint256 indexed nativePartInReward);
event PositionSizeCoefficientChanged(uint256 indexed positionSizeCoefficient);
event AdditionalGasChanged(uint256 indexed additionalGas);
event KeeperRewardUpdated(address indexed keeper, uint256 rewardInPmx, uint256 rewardInNativeCurrency);
event MinPositionSizeAddendChanged(uint256 newMinPositionSizeAddend);
event OptimisticGasCoefficientChanged(uint256 newOptimismGasCoefficient);
/**
* @notice Initializes the KeeperRewardDistributor contract.
* @param _params Parameters for initialization
*/
function initialize(InitParams calldata _params) external;
/**
* @dev Params for the updateReward function
* @param keeper Address of the keeper
* @param positionAsset Address of the position asset
* @param positionSize Size of the position
* @param action The action that was performed by the keeper
* @param numberOfActions Number of actions performed by the keeper
* @param gasSpent Gas spent on executing transaction
* @param decreasingCounter An array where each index contains the number of decreasing reasons according to the DecreasingReason enum
* @param routesLength The length of routes provided as input to the protocol function,
* subject to an additional commission in the ARBITRUM payment model.
*/
struct UpdateRewardParams {
address keeper;
address positionAsset;
uint256 positionSize;
KeeperActionType action;
uint256 numberOfActions;
uint256 gasSpent;
uint256[] decreasingCounter;
uint256 routesLength;
bytes nativePmxOracleData;
bytes positionNativeAssetOracleData;
}
/**
* @notice Updates reward for keeper for closing position or executing order
* @dev Only callable by the PM_ROLE, LOM_ROLE, BATCH_MANAGER_ROLE roles.
* @param _params The UpdateRewardParams params
*/
function updateReward(UpdateRewardParams calldata _params) external;
/**
* @notice Claims earned reward of the keeper
* @param _pmxAmount Amount of PMX token to claim
* @param _nativeAmount Amount of native token to claim
*/
function claim(uint256 _pmxAmount, uint256 _nativeAmount) external;
/**
* @notice Sets the default maximum gas price allowed.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _defaultMaxGasPrice The new default maximum gas price value.
*/
function setDefaultMaxGasPrice(uint256 _defaultMaxGasPrice) external;
/**
* @notice Sets the amount of gas to be removed for the specified reason
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _reason The reason for which an amount is set
* @param _amount Gas amount.
*/
function setDecreasingGasByReason(DecreasingReason _reason, uint256 _amount) external;
/**
* @notice Sets the KeeperActionRewardConfig for the specified action type
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _actionType The action type for which the config is set
* @param _config The KeeperActionRewardConfig struct
*/
function setMaxGasPerPosition(KeeperActionType _actionType, KeeperActionRewardConfig calldata _config) external;
/**
* @notice Sets the dataLengthRestrictions for the specified KeeperCallingMethod.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _callingMethod The calling method for which dataLengthRestrictions is set
* @param _maxRoutesLength The maximum routes length for which an additional fee will be paid in the ARBITRUM payment model, in bytes
* @param _baseLength The length of the data entering the protocol function including method signature
* and excluding dynamic types(e.g, routesLength), in bytes
*/
function setDataLengthRestrictions(
KeeperCallingMethod _callingMethod,
uint256 _maxRoutesLength,
uint256 _baseLength
) external;
/**
* @notice Sets the tolerance for gas price fluctuations from the oracle price.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _oracleGasPriceTolerance The new oracle gas price tolerance value (percent expressed as WAD).
*/
function setOracleGasPriceTolerance(uint256 _oracleGasPriceTolerance) external;
/**
* @notice Sets the PMX token's portion in the reward calculation.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _pmxPartInReward The new PMX token's portion in the reward calculation (percent expressed as WAD).
*/
function setPmxPartInReward(uint256 _pmxPartInReward) external;
/**
* @notice Sets the native token's portion in the reward calculation.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _nativePartInReward The new native token's portion in the reward calculation (percent expressed as WAD).
*/
function setNativePartInReward(uint256 _nativePartInReward) external;
/**
* @notice Sets the position size coefficients for reward calculations.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _positionSizeCoefficient The new positionSizeCoefficient value (in WAD).
*/
function setPositionSizeCoefficient(uint256 _positionSizeCoefficient) external;
/**
* @notice Sets the additional gas value for reward calculations.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _additionalGas The new additionalGas value.
*/
function setAdditionalGas(uint256 _additionalGas) external;
/**
* @notice Sets the minPositionSizeAddend for reward calculations.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _minPositionSizeAddend The new minPositionSizeAddend value (in WAD).
*/
function setMinPositionSizeAddend(uint256 _minPositionSizeAddend) external;
/**
* @notice Retrieves gas calculation params.
*
* @return oracleGasPriceTolerance The tolerance for gas price fluctuations based on the oracle.
* @return defaultMaxGasPrice The default maximum gas price allowed.
*/
function getGasCalculationParams() external view returns (uint256, uint256, uint256, PaymentModel);
/**
* @notice Sets the optimisticGasCoefficient for optimism paymentModel.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _newOptimisticGasCoefficient The new optimisticGasCoefficient value (in WAD).
*/
function setOptimisticGasCoefficient(uint256 _newOptimisticGasCoefficient) external;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IKeeperRewardDistributorStorage {
enum DecreasingReason {
NonExistentIdForLiquidation,
NonExistentIdForSLOrTP,
IncorrectConditionForLiquidation,
IncorrectConditionForSL,
ClosePostionInTheSameBlock
}
enum KeeperActionType {
OpenByOrder,
StopLoss,
TakeProfit,
Liquidation,
BucketDelisted
}
enum KeeperCallingMethod {
ClosePositionByCondition,
OpenPositionByOrder,
CloseBatchPositions
}
/**
* @dev Structure used in the calculation of keeper rewards in the ARBITRUM payment model
* @param maxRoutesLength The maximum length of routes for which will be paid keeper rewards, depending on KeeperCallingMethod
* @param baseLength The static length of the data entering the protocol function, depending on KeeperCallingMethod
*/
struct DataLengthRestrictions {
uint256 maxRoutesLength;
uint256 baseLength;
}
/**
* @dev Structure used in the calculation of maximum gas per position
* @param baseMaxGas1 Base gas amount that used to calculate max gas amount
* @param baseMaxGas2 Base gas amount that used to calculate max gas amount when number of keeper actions > inflectionPoint
* @param multiplier2 The multiplier which is multiplied by the number of keeper actions when number of keeper actions > inflectionPoint
* @param inflectionPoint Number of actions after which the multiplier2 takes effect
*/
struct KeeperActionRewardConfig {
uint256 baseMaxGas1;
uint256 baseMaxGas2;
uint256 multiplier1;
uint256 multiplier2;
uint256 inflectionPoint;
}
struct KeeperBalance {
uint256 pmxBalance;
uint256 nativeBalance;
}
enum PaymentModel {
DEFAULT,
ARBITRUM,
OPTIMISTIC
}
function priceOracle() external view returns (address);
function registry() external view returns (address);
function pmx() external view returns (address);
function treasury() external view returns (address payable);
function pmxPartInReward() external view returns (uint256);
function nativePartInReward() external view returns (uint256);
function positionSizeCoefficient() external view returns (uint256);
function positionSizeCoefficientB() external view returns (int256);
function additionalGas() external view returns (uint256);
function defaultMaxGasPrice() external view returns (uint256);
function oracleGasPriceTolerance() external view returns (uint256);
function paymentModel() external view returns (PaymentModel);
function keeperBalance(address) external view returns (uint256, uint256);
function maxGasPerPosition(KeeperActionType) external view returns (uint256, uint256, uint256, uint256, uint256);
function dataLengthRestrictions(KeeperCallingMethod) external view returns (uint256, uint256);
function decreasingGasByReason(DecreasingReason) external view returns (uint256);
function totalBalance() external view returns (uint256, uint256);
}
interface IKeeperRewardDistributorStorageV2 is IKeeperRewardDistributorStorage {
function minPositionSizeAddend() external view returns (uint256);
function optimisticGasCoefficient() external view returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
// solhint-disable-next-line func-visibility
function _require(bool condition, bytes4 selector) pure {
if (!condition) _revert(selector);
}
// solhint-disable-next-line func-visibility
function _revert(bytes4 selector) pure {
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
let free_mem_ptr := mload(64)
mstore(free_mem_ptr, selector)
revert(free_mem_ptr, 4)
}
}
library Errors {
event Log(bytes4 error);
//common
error ADDRESS_NOT_SUPPORTED();
error FORBIDDEN();
error AMOUNT_IS_0();
error CALLER_IS_NOT_TRADER();
error CONDITION_INDEX_IS_OUT_OF_BOUNDS();
error INVALID_PERCENT_NUMBER();
error INVALID_SECURITY_BUFFER();
error INVALID_MAINTENANCE_BUFFER();
error TOKEN_ADDRESS_IS_ZERO();
error IDENTICAL_TOKEN_ADDRESSES();
error ASSET_DECIMALS_EXCEEDS_MAX_VALUE();
error CAN_NOT_ADD_WITH_ZERO_ADDRESS();
error SHOULD_BE_DIFFERENT_ASSETS_IN_SPOT();
error TOKEN_NOT_SUPPORTED();
error INSUFFICIENT_DEPOSIT();
error SHOULD_NOT_HAVE_DUPLICATES();
error SWAP_DEADLINE_PASSED();
// error LIMIT_PRICE_IS_ZERO();
error BUCKET_IS_NOT_ACTIVE();
error DIFFERENT_DATA_LENGTH();
error RECIPIENT_OR_SENDER_MUST_BE_ON_WHITE_LIST();
error SLIPPAGE_TOLERANCE_EXCEEDED();
error OPERATION_NOT_SUPPORTED();
error SENDER_IS_BLACKLISTED();
error NATIVE_CURRENCY_CANNOT_BE_ASSET();
error INVALID_AMOUNT();
error POOL_CALL_FAILED();
// bonus executor
error CALLER_IS_NOT_NFT();
error BONUS_FOR_BUCKET_ALREADY_ACTIVATED();
error WRONG_LENGTH();
error BONUS_DOES_NOT_EXIST();
error CALLER_IS_NOT_DEBT_TOKEN();
error CALLER_IS_NOT_P_TOKEN();
error MAX_BONUS_COUNT_EXCEEDED();
error TIER_IS_NOT_ACTIVE();
error BONUS_PERCENT_IS_ZERO();
// bucket
error INCORRECT_LIQUIDITY_MINING_PARAMS();
error PAIR_PRICE_DROP_IS_NOT_CORRECT();
error ASSET_IS_NOT_SUPPORTED();
error BUCKET_OUTSIDE_PRIMEX_PROTOCOL();
error DEADLINE_IS_PASSED();
error DEADLINE_IS_NOT_PASSED();
error BUCKET_IS_NOT_LAUNCHED();
error BURN_AMOUNT_EXCEEDS_PROTOCOL_DEBT();
error LIQUIDITY_INDEX_OVERFLOW();
error BORROW_INDEX_OVERFLOW();
error BAR_OVERFLOW();
error LAR_OVERFLOW();
error UR_IS_MORE_THAN_1();
error ASSET_ALREADY_SUPPORTED();
error DEPOSIT_IS_MORE_AMOUNT_PER_USER();
error DEPOSIT_EXCEEDS_MAX_TOTAL_DEPOSIT();
error MINING_AMOUNT_WITHDRAW_IS_LOCKED_ON_STABILIZATION_PERIOD();
error WITHDRAW_RATE_IS_MORE_10_PERCENT();
error INVALID_FEE_BUFFER();
error RESERVE_RATE_SHOULD_BE_LESS_THAN_1();
error MAX_TOTAL_DEPOSIT_IS_ZERO();
error AMOUNT_SCALED_SHOULD_BE_GREATER_THAN_ZERO();
error NOT_ENOUGH_LIQUIDITY_IN_THE_BUCKET();
// p/debt token, PMXToken
error BUCKET_IS_IMMUTABLE();
error INVALID_MINT_AMOUNT();
error INVALID_BURN_AMOUNT();
error TRANSFER_NOT_SUPPORTED();
error APPROVE_NOT_SUPPORTED();
error CALLER_IS_NOT_BUCKET();
error CALLER_IS_NOT_A_BUCKET_FACTORY();
error CALLER_IS_NOT_P_TOKEN_RECEIVER();
error DURATION_MUST_BE_MORE_THAN_0();
error INCORRECT_ID();
error THERE_ARE_NO_LOCK_DEPOSITS();
error LOCK_TIME_IS_NOT_EXPIRED();
error TRANSFER_AMOUNT_EXCEED_ALLOWANCE();
error CALLER_IS_NOT_A_MINTER();
error ACTION_ONLY_WITH_AVAILABLE_BALANCE();
error FEE_DECREASER_CALL_FAILED();
error TRADER_REWARD_DISTRIBUTOR_CALL_FAILED();
error INTEREST_INCREASER_CALL_FAILED();
error LENDER_REWARD_DISTRIBUTOR_CALL_FAILED();
error DEPOSIT_DOES_NOT_EXIST();
error RECIPIENT_IS_BLACKLISTED();
//LOM
error ORDER_CAN_NOT_BE_FILLED();
error ORDER_DOES_NOT_EXIST();
error ORDER_IS_NOT_SPOT();
error LEVERAGE_MUST_BE_MORE_THAN_1();
error CANNOT_CHANGE_SPOT_ORDER_TO_MARGIN();
error SHOULD_HAVE_OPEN_CONDITIONS();
error INCORRECT_LEVERAGE();
error INCORRECT_DEADLINE();
error LEVERAGE_SHOULD_BE_1();
error LEVERAGE_EXCEEDS_MAX_LEVERAGE();
error SHOULD_OPEN_POSITION();
error IS_SPOT_ORDER();
error SHOULD_NOT_HAVE_CLOSE_CONDITIONS();
error ORDER_HAS_EXPIRED();
error INCORRECT_BORROWED_AMOUNT();
// LiquidityMiningRewardDistributor
error BUCKET_IS_NOT_STABLE();
error ATTEMPT_TO_WITHDRAW_MORE_THAN_DEPOSITED();
error WITHDRAW_PMX_BY_ADMIN_FORBIDDEN();
// nft
error TOKEN_IS_BLOCKED();
error ONLY_MINTERS();
error PROGRAM_IS_NOT_ACTIVE();
error CALLER_IS_NOT_OWNER();
error TOKEN_IS_ALREADY_ACTIVATED();
error WRONG_NETWORK();
error ID_DOES_NOT_EXIST();
error WRONG_URIS_LENGTH();
// PM
error ASSET_ADDRESS_NOT_SUPPORTED();
error IDENTICAL_ASSET_ADDRESSES();
error POSITION_DOES_NOT_EXIST();
error AMOUNT_IS_MORE_THAN_POSITION_AMOUNT();
error BORROWED_AMOUNT_IS_ZERO();
error IS_SPOT_POSITION();
error AMOUNT_IS_MORE_THAN_DEPOSIT();
error DECREASE_AMOUNT_IS_ZERO();
error INSUFFICIENT_DEPOSIT_SIZE();
error IS_NOT_RISKY_OR_CANNOT_BE_CLOSED();
error BUCKET_SHOULD_BE_UNDEFINED();
error DEPOSIT_IN_THIRD_ASSET_ROUTES_LENGTH_SHOULD_BE_0();
error POSITION_CANNOT_BE_CLOSED_FOR_THIS_REASON();
error ADDRESS_IS_ZERO();
error WRONG_TRUSTED_MULTIPLIER();
error POSITION_SIZE_EXCEEDED();
error POSITION_BUCKET_IS_INCORRECT();
error THERE_MUST_BE_AT_LEAST_ONE_POSITION();
error NOTHING_TO_CLOSE();
// BatchManager
error PARAMS_LENGTH_MISMATCH();
error BATCH_CANNOT_BE_CLOSED_FOR_THIS_REASON();
error CLOSE_CONDITION_IS_NOT_CORRECT();
error SOLD_ASSET_IS_INCORRECT();
// Price Oracle
error THERE_IS_DIRECT_ROUTE();
error ZERO_EXCHANGE_RATE();
error NO_PRICEFEED_FOUND();
error NO_PRICE_DROP_FEED_FOUND();
error WRONG_ORACLE_ROUTES_LENGTH();
error WRONG_ASSET_B();
error INCORRECT_ROUTE_SEQUENCE();
error INCORRECT_PYTH_PRICE();
error TOKEN_PAIR_IS_NOT_TRUSTED();
error INCORRECT_TOKEN_TO();
error INCORRECT_PYTH_ROUTE();
error INCORRECT_CHAINLINK_ROUTE();
error NOT_ENOUGH_MSG_VALUE();
error PUBLISH_TIME_EXCEEDS_THRESHOLD_TIME();
//DNS
error INCORRECT_FEE_RATE();
error INCORRECT_RESTRICTIONS();
error BUCKET_ALREADY_FROZEN();
error BUCKET_IS_ALREADY_ADDED();
error DEX_IS_ALREADY_ACTIVATED();
error DEX_IS_ALREADY_FROZEN();
error DEX_IS_ALREADY_ADDED();
error BUCKET_NOT_ADDED();
error BUCKET_ALREADY_ACTIVATED();
error DEX_NOT_ADDED();
error BUCKET_IS_INACTIVE();
error WITHDRAWAL_NOT_ALLOWED();
error BUCKET_IS_ALREADY_DEPRECATED();
error LEVERAGE_TOLERANCE_IS_NOT_CORRECT();
// Primex upkeep
error NUMBER_IS_0();
//referral program, WhiteBlackList
error CALLER_ALREADY_REGISTERED();
error MISMATCH();
error PARENT_NOT_WHITELISTED();
error ADDRESS_ALREADY_WHITELISTED();
error ADDRESS_ALREADY_BLACKLISTED();
error ADDRESS_NOT_BLACKLISTED();
error ADDRESS_NOT_WHITELISTED();
error ADDRESS_NOT_UNLISTED();
error ADDRESS_IS_WHITELISTED();
error ADDRESS_IS_NOT_CONTRACT();
//Reserve
error BURN_AMOUNT_IS_ZERO();
error CALLER_IS_NOT_EXECUTOR();
error ADDRESS_NOT_PRIMEX_BUCKET();
error NOT_SUFFICIENT_RESERVE_BALANCE();
error INCORRECT_TRANSFER_RESTRICTIONS();
//Vault
error AMOUNT_EXCEEDS_AVAILABLE_BALANCE();
error INSUFFICIENT_FREE_ASSETS();
error CALLER_IS_NOT_SPENDER();
//Pricing Library
error IDENTICAL_ASSETS();
error SUM_OF_SHARES_SHOULD_BE_GREATER_THAN_ZERO();
error DIFFERENT_PRICE_DEX_AND_ORACLE();
error LEVERAGE_TOLERANCE_EXCEEDED();
error TAKE_PROFIT_IS_LTE_LIMIT_PRICE();
error STOP_LOSS_IS_GTE_LIMIT_PRICE();
error STOP_LOSS_IS_LTE_LIQUIDATION_PRICE();
error INSUFFICIENT_POSITION_SIZE();
error INCORRECT_PATH();
error DEPOSITED_TO_BORROWED_ROUTES_LENGTH_SHOULD_BE_0();
error INCORRECT_CM_TYPE();
error FEE_RATE_IN_NATIVE_IS_ZERO();
error MIN_PROTOCOL_FEE_IS_GREATER_THAN_PAYMENT_AMOUNT();
// Token transfers
error TOKEN_TRANSFER_IN_FAILED();
error TOKEN_TRANSFER_IN_OVERFLOW();
error TOKEN_TRANSFER_OUT_FAILED();
error TOKEN_APPROVE_FAILED();
error NATIVE_TOKEN_TRANSFER_FAILED();
// Conditional Managers
error LOW_PRICE_ROUND_IS_LESS_HIGH_PRICE_ROUND();
error TRAILING_DELTA_IS_INCORRECT();
error DATA_FOR_ROUND_DOES_NOT_EXIST();
error HIGH_PRICE_TIMESTAMP_IS_INCORRECT();
error NO_PRICE_FEED_INTERSECTION();
error SHOULD_BE_CCM();
error SHOULD_BE_COM();
//Lens
error DEPOSITED_AMOUNT_IS_0();
error SPOT_DEPOSITED_ASSET_SHOULD_BE_EQUAL_BORROWED_ASSET();
error ZERO_ASSET_ADDRESS();
error ASSETS_SHOULD_BE_DIFFERENT();
error ZERO_SHARES();
error SHARES_AMOUNT_IS_GREATER_THAN_AMOUNT_TO_SELL();
error NO_ACTIVE_DEXES();
//Bots
error WRONG_BALANCES();
error INVALID_INDEX();
error INVALID_DIVIDER();
error ARRAYS_LENGTHS_IS_NOT_EQUAL();
error DENOMINATOR_IS_0();
//DexAdapter
error ZERO_AMOUNT_IN();
error ZERO_AMOUNT();
error UNKNOWN_DEX_TYPE();
error REVERTED_WITHOUT_A_STRING_TRY_TO_CHECK_THE_ANCILLARY_DATA();
error DELTA_OF_TOKEN_OUT_HAS_POSITIVE_VALUE();
error DELTA_OF_TOKEN_IN_HAS_NEGATIVE_VALUE();
error QUOTER_IS_NOT_PROVIDED();
error DEX_ROUTER_NOT_SUPPORTED();
error QUOTER_NOT_SUPPORTED();
//SpotTradingRewardDistributor
error PERIOD_DURATION_IS_ZERO();
error REWARD_AMOUNT_IS_ZERO();
error REWARD_PER_PERIOD_IS_NOT_CORRECT();
//ActivityRewardDistributor
error TOTAL_REWARD_AMOUNT_IS_ZERO();
error REWARD_PER_DAY_IS_NOT_CORRECT();
error ZERO_BUCKET_ADDRESS();
//KeeperRewardDistributor
error INCORRECT_PART_IN_REWARD();
error INCORRECT_MULTIPLIER();
error INCORRECT_OPTIMISM_GAS_COEFFICIENT();
//Treasury
error TRANSFER_RESTRICTIONS_NOT_MET();
error INSUFFICIENT_NATIVE_TOKEN_BALANCE();
error INSUFFICIENT_TOKEN_BALANCE();
error EXCEEDED_MAX_AMOUNT_DURING_TIMEFRAME();
error EXCEEDED_MAX_SPENDING_LIMITS();
error SPENDING_LIMITS_ARE_INCORRECT();
error SPENDER_IS_NOT_EXIST();
//FlashLoan
error INCONSISTENT_FLASHLOAN_PARAMS();
error INVALID_FLASHLOAN_EXECUTOR_RETURN();
error FLASH_LOAN_FEE_RATE_IS_MORE_10_PERCENT();
error FLASH_LOAN_PROTOCOL_RATE_IS_MORE_50_PERCENT();
// DepositManager
error REWARD_PERCENT_SHOULD_BE_GREATER_THAN_ZERO();
error TOKEN_CANNOT_BE_P_TOKEN();
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import {WadRayMath} from "./utils/WadRayMath.sol";
import {PrimexPricingLibrary} from "./PrimexPricingLibrary.sol";
import {TokenTransfersLibrary} from "./TokenTransfersLibrary.sol";
import {NATIVE_CURRENCY} from "../Constants.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IPrimexDNSStorageV3} from "../PrimexDNS/IPrimexDNSStorage.sol";
import {IPriceOracleV2} from "../PriceOracle/IPriceOracle.sol";
import {IBucketV3} from "../Bucket/IBucket.sol";
import {IConditionalOpeningManager} from "../interfaces/IConditionalOpeningManager.sol";
import {IConditionalClosingManager} from "../interfaces/IConditionalClosingManager.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {ISwapManager} from "../SwapManager/ISwapManager.sol";
import "./Errors.sol";
library LimitOrderLibrary {
using WadRayMath for uint256;
enum CloseReason {
FilledMargin,
FilledSpot,
FilledSwap,
Cancelled
}
struct Condition {
uint256 managerType;
bytes params;
}
/**
* @dev Creates a limit order and locks the deposit asset in the traderBalanceVault
* @param bucket The bucket, from which the loan will be taken
* @param positionAsset The address of output token for exchange
* @param depositAsset The address of the deposit token
* @param depositAmount The amount of deposit trader funds for deal
* @param feeToken An asset in which the fee will be paid. At this point it could be the pmx, the epmx or a positionAsset
* @param trader The trader, who has created the order
* @param deadline Unix timestamp after which the order will not be filled
* @param id The unique id of the order
* @param leverage leverage for trading
* @param shouldOpenPosition The flag to indicate whether position should be opened
* @param createdAt The timeStamp when the order was created
* @param updatedConditionsAt The timestamp when the open condition was updated
*/
struct LimitOrder {
IBucketV3 bucket;
address positionAsset;
address depositAsset;
uint256 depositAmount;
address feeToken;
uint256 protocolFee;
address trader;
uint256 deadline;
uint256 id;
uint256 leverage;
bool shouldOpenPosition;
uint256 createdAt;
uint256 updatedConditionsAt;
// The byte-encoded params, can be used for future updates
bytes extraParams;
}
/**
* @dev Structure for the сreateLimitOrder with parameters necessary to create limit order
* @param bucket The bucket, from which the loan will be taken
* @param depositAsset The address of the deposit token (collateral for margin trade or
* locked funds for spot)
* @param depositAmount The amount of deposit funds for deal
* @param positionAsset The address output token for exchange
* @param deadline Unix timestamp after which the order will not be filled
* @param takeDepositFromWallet Bool, add a collateral deposit within the current transaction
* @param leverage leverage for trading
* @param shouldOpenPosition Bool, indicate whether position should be opened
* @param openingManagerAddresses Array of contract addresses that will be called in canBeFilled
* @param openingManagerParams Array of bytes representing params for contracts in openingManagerAddresses
* @param closingManagerAddresses Array of contract addresses that will be called in canBeClosed
* @param closingManagerParams Array of bytes representing params for contracts in closingManagerAddresses
*/
struct CreateLimitOrderParams {
string bucket;
uint256 depositAmount;
address depositAsset;
address positionAsset;
uint256 deadline;
bool takeDepositFromWallet;
uint256 leverage;
bool shouldOpenPosition;
Condition[] openConditions;
Condition[] closeConditions;
bool isProtocolFeeInPmx;
bytes nativeDepositAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
struct CreateLimitOrderVars {
bool isSpot;
IBucketV3 bucket;
uint256 positionSize;
address priceOracle;
uint256 rate;
IPrimexDNSStorageV3.TradingOrderType tradingOrderType;
bool isThirdAsset;
}
/**
* @dev Opens a position on an existing order
* @param orderId order id
* @param com address of ConditionalOpeningManager
* @param comAdditionalParams params needed for ConditionalOpeningManager to calc canBeFilled
* @param firstAssetMegaRoutes routes to swap first asset
* @param depositInThirdAssetMegaRoutes routes to swap deposit asset
*/
struct OpenPositionParams {
uint256 orderId;
uint256 conditionIndex;
bytes comAdditionalParams;
PrimexPricingLibrary.MegaRoute[] firstAssetMegaRoutes;
PrimexPricingLibrary.MegaRoute[] depositInThirdAssetMegaRoutes;
address keeper;
bytes firstAssetOracleData;
bytes thirdAssetOracleData;
bytes depositSoldAssetOracleData;
bytes nativePmxOracleData;
bytes positionNativeAssetOracleData;
bytes nativePositionAssetOracleData;
bytes pmxPositionAssetOracleData;
bytes positionUsdOracleData;
bytes nativeSoldAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
uint256 borrowedAmount;
}
struct OpenPositionByOrderVars {
address assetIn;
address assetOut;
uint256 amountIn;
uint256 amountOut;
CloseReason closeReason;
uint256 newPositionId;
uint256 exchangeRate;
uint256 feeInPositionAsset;
uint256 feeInPmx;
}
/**
* @dev Params for PositionManager to open position
* @param order order
* @param firstAssetMegaRoutes routes to swap first asset on dex
* (borrowedAmount + depositAmount if deposit in borrowedAsset)
* @param depositInThirdAssetMegaRoutes routes to swap deposit in third asset on dex
*/
struct OpenPositionByOrderParams {
address sender;
LimitOrder order;
Condition[] closeConditions;
PrimexPricingLibrary.MegaRoute[] firstAssetMegaRoutes;
PrimexPricingLibrary.MegaRoute[] depositInThirdAssetMegaRoutes;
bytes firstAssetOracleData;
bytes thirdAssetOracleData;
bytes depositSoldAssetOracleData;
bytes positionUsdOracleData;
bytes nativePositionAssetOracleData;
bytes pmxPositionAssetOracleData;
bytes nativeSoldAssetOracleData;
uint256 borrowedAmount;
}
/**
* @dev Structure for the updateOrder with parameters necessary to update limit order
* @param orderId order id to update
* @param depositAmount The amount of deposit funds for deal
* @param makeDeposit Bool, add a collateral deposit within the current transaction
* @param leverage leverage for trading
* @param takeDepositFromWallet Bool, add a collateral deposit within the current transaction
*/
struct UpdateLimitOrderParams {
uint256 orderId;
uint256 depositAmount;
uint256 leverage;
bool isProtocolFeeInPmx;
bool takeDepositFromWallet;
bytes nativeDepositOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
/**
* @notice Updates the leverage of a limit order.
* @param _order The limit order to update.
* @param _leverage The new leverage value in WAD format for the order.
* @param _primexDNS The instance of the PrimexDNS contract
*/
function updateLeverage(LimitOrder storage _order, uint256 _leverage, IPrimexDNSV3 _primexDNS) public {
_require(_leverage > WadRayMath.WAD, Errors.LEVERAGE_MUST_BE_MORE_THAN_1.selector);
_require(_order.leverage != WadRayMath.WAD, Errors.CANNOT_CHANGE_SPOT_ORDER_TO_MARGIN.selector);
_require(
_leverage <
_order.bucket.maxAssetLeverage(
_order.positionAsset,
_primexDNS.protocolFeeRates(IPrimexDNSStorageV3.FeeRateType.MarginLimitOrderExecuted)
),
Errors.LEVERAGE_EXCEEDS_MAX_LEVERAGE.selector
);
_order.leverage = _leverage;
}
/**
* @notice Updates the deposit details of a LimitOrder.
* @param _order The LimitOrder to update.
* @param _amount The amount of the asset being deposited.
* @param _takeDepositFromWallet Boolean indicating whether to make a deposit or unlock the deposited asset.
* @param traderBalanceVault The instance of ITraderBalanceVault used for deposit and unlock operations.
*/
function updateDeposit(
LimitOrderLibrary.LimitOrder storage _order,
uint256 _amount,
bool _takeDepositFromWallet,
ITraderBalanceVault traderBalanceVault
) public {
depositLockOrUnlock(
traderBalanceVault,
_order.depositAsset,
(_amount > _order.depositAmount) ? _amount - _order.depositAmount : _order.depositAmount - _amount,
_takeDepositFromWallet,
_amount > _order.depositAmount
);
_order.depositAmount = _amount;
}
/**
* @notice Sets the open conditions for a LimitOrder.
* @param _order The limit order.
* @param openConditionsMap The mapping of order IDs to open conditions.
* @param openConditions The array of open conditions.
* @param primexDNS The instance of the Primex DNS contract.
*/
function setOpenConditions(
LimitOrderLibrary.LimitOrder memory _order,
mapping(uint256 => Condition[]) storage openConditionsMap,
Condition[] memory openConditions,
IPrimexDNSV3 primexDNS
) public {
_require(hasNoConditionManagerTypeDuplicates(openConditions), Errors.SHOULD_NOT_HAVE_DUPLICATES.selector);
_require(openConditions.length > 0, Errors.SHOULD_HAVE_OPEN_CONDITIONS.selector);
if (openConditionsMap[_order.id].length > 0) {
delete openConditionsMap[_order.id];
}
Condition memory condition;
for (uint256 i; i < openConditions.length; i++) {
condition = openConditions[i];
_require(
IERC165Upgradeable(primexDNS.cmTypeToAddress(condition.managerType)).supportsInterface(
type(IConditionalOpeningManager).interfaceId
),
Errors.SHOULD_BE_COM.selector
);
openConditionsMap[_order.id].push(condition);
}
}
/**
* @notice Sets the close conditions for a LimitOrder.
* @param _order The limit order.
* @param closeConditionsMap The mapping of order IDs to close conditions.
* @param closeConditions The array of close conditions to set.
* @param primexDNS The Primex DNS contract address.
*/
function setCloseConditions(
LimitOrderLibrary.LimitOrder memory _order,
mapping(uint256 => Condition[]) storage closeConditionsMap,
Condition[] memory closeConditions,
IPrimexDNSV3 primexDNS
) public {
_require(hasNoConditionManagerTypeDuplicates(closeConditions), Errors.SHOULD_NOT_HAVE_DUPLICATES.selector);
_require(
_order.shouldOpenPosition || closeConditions.length == 0,
Errors.SHOULD_NOT_HAVE_CLOSE_CONDITIONS.selector
);
if (closeConditionsMap[_order.id].length > 0) {
delete closeConditionsMap[_order.id];
}
Condition memory condition;
for (uint256 i; i < closeConditions.length; i++) {
condition = closeConditions[i];
_require(
IERC165Upgradeable(primexDNS.cmTypeToAddress(condition.managerType)).supportsInterface(
type(IConditionalClosingManager).interfaceId
),
Errors.SHOULD_BE_CCM.selector
);
closeConditionsMap[_order.id].push(condition);
}
}
/**
* @notice Creates a limit order.
* @param _params The struct containing the order parameters.
* @param pm The instance of the PositionManager contract.
* @param traderBalanceVault The instance of the TraderBalanceVault contract.
* @param primexDNS The instance of the PrimexDNS contract.
* @return The created limit order.
*/
function createLimitOrder(
CreateLimitOrderParams calldata _params,
IPositionManagerV2 pm,
ITraderBalanceVault traderBalanceVault,
IPrimexDNSV3 primexDNS
) public returns (LimitOrder memory) {
_require(_params.leverage >= WadRayMath.WAD, Errors.INCORRECT_LEVERAGE.selector);
_require(_params.deadline > block.timestamp, Errors.INCORRECT_DEADLINE.selector);
CreateLimitOrderVars memory vars;
vars.isSpot = bytes(_params.bucket).length == 0;
vars.positionSize = _params.depositAmount.wmul(_params.leverage);
vars.priceOracle = address(pm.priceOracle());
if (vars.isSpot) {
_require(_params.leverage == WadRayMath.WAD, Errors.LEVERAGE_SHOULD_BE_1.selector);
_require(_params.depositAsset != _params.positionAsset, Errors.SHOULD_BE_DIFFERENT_ASSETS_IN_SPOT.selector);
vars.tradingOrderType = _params.shouldOpenPosition
? IPrimexDNSStorageV3.TradingOrderType.SpotLimitOrder
: IPrimexDNSStorageV3.TradingOrderType.SwapLimitOrder;
} else {
_require(_params.shouldOpenPosition, Errors.SHOULD_OPEN_POSITION.selector);
_require(_params.leverage > WadRayMath.WAD, Errors.LEVERAGE_MUST_BE_MORE_THAN_1.selector);
vars.bucket = IBucketV3(primexDNS.getBucketAddress(_params.bucket));
_require(vars.bucket.getLiquidityMiningParams().isBucketLaunched, Errors.BUCKET_IS_NOT_LAUNCHED.selector);
(, bool tokenAllowed) = vars.bucket.allowedAssets(_params.positionAsset);
_require(tokenAllowed, Errors.TOKEN_NOT_SUPPORTED.selector);
_require(
_params.leverage <
vars.bucket.maxAssetLeverage(
_params.positionAsset,
primexDNS.protocolFeeRates(IPrimexDNSStorageV3.FeeRateType.MarginLimitOrderExecuted)
),
Errors.LEVERAGE_EXCEEDS_MAX_LEVERAGE.selector
);
vars.isThirdAsset =
_params.depositAsset != address(vars.bucket.borrowedAsset()) &&
_params.depositAsset != _params.positionAsset;
vars.tradingOrderType = vars.isThirdAsset
? IPrimexDNSStorageV3.TradingOrderType.MarginLimitOrderDepositInThirdAsset
: IPrimexDNSStorageV3.TradingOrderType.MarginLimitOrder;
}
LimitOrder memory order = LimitOrder({
bucket: IBucketV3(address(0)),
positionAsset: _params.positionAsset,
depositAsset: _params.depositAsset,
depositAmount: _params.depositAmount,
feeToken: _params.isProtocolFeeInPmx ? primexDNS.pmx() : _params.positionAsset,
protocolFee: 0,
trader: msg.sender,
deadline: _params.deadline,
id: 0,
leverage: _params.leverage,
shouldOpenPosition: _params.shouldOpenPosition,
createdAt: block.timestamp,
updatedConditionsAt: block.timestamp,
extraParams: ""
});
order.bucket = vars.bucket;
PrimexPricingLibrary.validateMinPositionSize(
vars.positionSize,
order.depositAsset,
vars.priceOracle,
pm.keeperRewardDistributor(),
primexDNS,
vars.tradingOrderType,
_params.nativeDepositAssetOracleData
);
// deposit locking
depositLockOrUnlock(
traderBalanceVault,
order.depositAsset,
order.depositAmount,
_params.takeDepositFromWallet,
true
);
return order;
}
/**
* @notice Opens a position by order.
* @param order The LimitOrder storage containing order details.
* @param _params The OpenPositionParams calldata containing additional position parameters.
* @param _closeConditions The Condition array containing close conditions for the position.
* @param pm The instance of the PositionManager contract.
* @param traderBalanceVault The instance of the TraderBalanceVault contract.
* @param swapManager The instance of the SwapManager contract.
* @return vars The OpenPositionByOrderVars struct containing the result of the open position operation.
*/
function openPositionByOrder(
LimitOrder storage order,
OpenPositionParams calldata _params,
Condition[] memory _closeConditions,
IPositionManagerV2 pm,
ITraderBalanceVault traderBalanceVault,
ISwapManager swapManager,
uint256 _initialGasLeft
) public returns (OpenPositionByOrderVars memory) {
OpenPositionByOrderVars memory vars;
bool isSpot = address(order.bucket) == address(0);
if (order.protocolFee != 0) {
traderBalanceVault.unlockAsset(
ITraderBalanceVault.UnlockAssetParams({
trader: order.trader,
receiver: order.trader,
asset: order.feeToken,
amount: order.protocolFee
})
);
order.protocolFee = 0;
order.feeToken = order.positionAsset;
}
if (order.shouldOpenPosition) {
vars.closeReason = isSpot ? CloseReason.FilledSpot : CloseReason.FilledMargin;
(vars.amountIn, vars.amountOut, vars.newPositionId, vars.exchangeRate, vars.feeInPositionAsset) = pm
.openPositionByOrder(
OpenPositionByOrderParams({
sender: msg.sender,
order: order,
closeConditions: _closeConditions,
firstAssetMegaRoutes: _params.firstAssetMegaRoutes,
depositInThirdAssetMegaRoutes: _params.depositInThirdAssetMegaRoutes,
firstAssetOracleData: _params.firstAssetOracleData,
thirdAssetOracleData: _params.thirdAssetOracleData,
depositSoldAssetOracleData: _params.depositSoldAssetOracleData,
positionUsdOracleData: _params.positionUsdOracleData,
nativePositionAssetOracleData: _params.nativePositionAssetOracleData,
pmxPositionAssetOracleData: _params.pmxPositionAssetOracleData,
nativeSoldAssetOracleData: _params.nativeSoldAssetOracleData,
borrowedAmount: _params.borrowedAmount
})
);
} else {
_require(
_params.depositInThirdAssetMegaRoutes.length == 0,
Errors.DEPOSIT_IN_THIRD_ASSET_ROUTES_LENGTH_SHOULD_BE_0.selector
);
vars.closeReason = CloseReason.FilledSwap;
vars.amountIn = order.depositAmount;
traderBalanceVault.unlockAsset(
ITraderBalanceVault.UnlockAssetParams({
trader: order.trader,
receiver: address(this),
asset: order.depositAsset,
amount: order.depositAmount
})
);
(vars.amountOut, vars.feeInPositionAsset) = swapManager.swapInLimitOrder(
ISwapManager.SwapInLimitOrderParams({
depositAsset: order.depositAsset,
positionAsset: order.positionAsset,
depositAmount: order.depositAmount,
megaRoutes: _params.firstAssetMegaRoutes,
trader: order.trader,
deadline: order.deadline,
feeToken: order.feeToken,
keeperRewardDistributor: address(pm.keeperRewardDistributor()),
gasSpent: _initialGasLeft - gasleft(),
depositPositionAssetOracleData: _params.firstAssetOracleData,
pmxPositionAssetOracleData: _params.pmxPositionAssetOracleData,
nativePositionAssetOracleData: _params.nativePositionAssetOracleData
}),
pm.getOracleTolerableLimit(order.depositAsset, order.positionAsset)
);
uint256 multiplierDepositAsset = 10 ** (18 - IERC20Metadata(order.depositAsset).decimals());
uint256 multiplierPositionAsset = 10 ** (18 - IERC20Metadata(order.positionAsset).decimals());
vars.exchangeRate =
(vars.amountIn * multiplierDepositAsset).wdiv(
(vars.amountOut + vars.feeInPositionAsset) * multiplierPositionAsset
) /
multiplierDepositAsset;
}
vars.assetIn = isSpot ? order.depositAsset : address(order.bucket.borrowedAsset());
vars.assetOut = order.positionAsset;
return vars;
}
/**
* @notice Checks if an array of Condition structs has no duplicate manager types.
* @param conditions The array of Condition structs to be checked.
* @return bool Boolean value indicating whether the array has no duplicate manager types.
*/
function hasNoConditionManagerTypeDuplicates(Condition[] memory conditions) public pure returns (bool) {
if (conditions.length == 0) {
return true;
}
for (uint256 i; i < conditions.length - 1; i++) {
for (uint256 j = i + 1; j < conditions.length; j++) {
if (conditions[i].managerType == conditions[j].managerType) {
return false;
}
}
}
return true;
}
/**
* @notice This function is used to either deposit or unlock assets in the trader balance vault.
* @param traderBalanceVault The instance of the trader balance vault.
* @param _depositAsset The address of the asset to be deposited or unlocked.
* @param _amount The amount of the asset to be deposited or unlocked.
* @param _takeDepositFromWallet Boolean indicating whether to make a deposit or not.
* @param _isAdd Boolean indicating whether to lock or unlock asset. Should lock asset, if true.
*/
function depositLockOrUnlock(
ITraderBalanceVault traderBalanceVault,
address _depositAsset,
uint256 _amount,
bool _takeDepositFromWallet,
bool _isAdd
) internal {
if (!_isAdd) {
traderBalanceVault.unlockAsset(
ITraderBalanceVault.UnlockAssetParams(msg.sender, msg.sender, _depositAsset, _amount)
);
return;
}
if (_takeDepositFromWallet) {
if (_depositAsset == NATIVE_CURRENCY) {
_require(msg.value >= _amount, Errors.INSUFFICIENT_DEPOSIT.selector);
traderBalanceVault.increaseLockedBalance{value: _amount}(msg.sender, _depositAsset, _amount);
if (msg.value > _amount) {
uint256 rest = msg.value - _amount;
traderBalanceVault.topUpAvailableBalance{value: rest}(msg.sender, NATIVE_CURRENCY, rest);
}
return;
}
TokenTransfersLibrary.doTransferFromTo(_depositAsset, msg.sender, address(traderBalanceVault), _amount);
traderBalanceVault.increaseLockedBalance(msg.sender, _depositAsset, _amount);
return;
}
traderBalanceVault.useTraderAssets(
ITraderBalanceVault.LockAssetParams(
msg.sender,
address(0),
_depositAsset,
_amount,
ITraderBalanceVault.OpenType.CREATE_LIMIT_ORDER
)
);
}
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import {WadRayMath} from "./utils/WadRayMath.sol";
import {PrimexPricingLibrary} from "./PrimexPricingLibrary.sol";
import {TokenTransfersLibrary} from "./TokenTransfersLibrary.sol";
import {LimitOrderLibrary} from "./LimitOrderLibrary.sol";
import "./Errors.sol";
import {NATIVE_CURRENCY} from "../Constants.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IPrimexDNSStorageV3} from "../PrimexDNS/IPrimexDNSStorage.sol";
import {IPriceOracleV2} from "../PriceOracle/IPriceOracle.sol";
import {IBucketV3} from "../Bucket/IBucket.sol";
import {IConditionalClosingManager} from "../interfaces/IConditionalClosingManager.sol";
import {ITakeProfitStopLossCCM} from "../interfaces/ITakeProfitStopLossCCM.sol";
import {IKeeperRewardDistributorStorage, IKeeperRewardDistributorV3} from "../KeeperRewardDistributor/IKeeperRewardDistributor.sol";
library PositionLibrary {
using WadRayMath for uint256;
event ClosePosition(
uint256 indexed positionId,
address indexed trader,
address indexed closedBy,
address bucketAddress,
address soldAsset,
address positionAsset,
uint256 decreasePositionAmount,
int256 profit,
uint256 positionDebt,
uint256 amountOut,
PositionLibrary.CloseReason reason
);
event PaidProtocolFee(
uint256 indexed positionId,
address indexed trader,
address paymentAsset,
IPrimexDNSStorageV3.FeeRateType indexed feeRateType,
uint256 feeInPaymentAsset,
uint256 feeInPmx
);
/**
* @notice This struct represents a trading position
* @param id unique identifier for the position
* @param scaledDebtAmount scaled debt amount associated with the position
* @param bucket instance of the Bucket associated for trading
* @param soldAsset bucket asset in the case of margin trading or deposit asset in the case of spot trading
* @param depositAmountInSoldAsset equivalent of trader deposit size (this deposit can be in any asset) in the sold asset
* or just deposit amount for spot trading
* @param positionAsset asset of the trading position
* @param positionAmount amount of the trading position
* @param trader address of the trader holding the position
* @param openBorrowIndex variable borrow index when position was opened
* @param createdAt timestamp when the position was created
* @param updatedConditionsAt timestamp when the close condition was updated
* @param extraParams byte-encoded params, utilized for the feeToken address
*/
struct Position {
uint256 id;
uint256 scaledDebtAmount;
IBucketV3 bucket;
address soldAsset;
uint256 depositAmountInSoldAsset;
address positionAsset;
uint256 positionAmount;
address trader;
uint256 openBorrowIndex;
uint256 createdAt;
uint256 updatedConditionsAt;
bytes extraParams;
}
struct IncreaseDepositParams {
uint256 amount;
address asset;
bool takeDepositFromWallet;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
IPrimexDNSV3 primexDNS;
IPriceOracleV2 priceOracle;
ITraderBalanceVault traderBalanceVault;
uint256 amountOutMin;
}
struct DecreaseDepositParams {
uint256 amount;
IPrimexDNSV3 primexDNS;
IPriceOracleV2 priceOracle;
ITraderBalanceVault traderBalanceVault;
uint256 pairPriceDrop;
uint256 securityBuffer;
uint256 oracleTolerableLimit;
uint256 maintenanceBuffer;
address keeperRewardDistributor;
bytes positionSoldAssetOracleData;
bytes nativeSoldAssetOracleData;
}
struct MegaSwapParams {
address tokenA;
address tokenB;
uint256 amountTokenA;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
address receiver;
uint256 deadline;
bool takeDepositFromWallet;
IPrimexDNSV3 primexDNS;
IPriceOracleV2 priceOracle;
ITraderBalanceVault traderBalanceVault;
}
struct ClosePositionParams {
uint256 closeAmount;
uint256 depositDecrease;
uint256 scaledDebtAmount;
address depositReceiver;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
uint256 amountOutMin;
uint256 oracleTolerableLimit;
IPrimexDNSV3 primexDNS;
IPriceOracleV2 priceOracle;
ITraderBalanceVault traderBalanceVault;
LimitOrderLibrary.Condition closeCondition;
bytes ccmAdditionalParams;
bool borrowedAmountIsNotZero;
uint256 pairPriceDrop;
uint256 securityBuffer;
bool needOracleTolerableLimitCheck;
uint256 initialGasLeft;
address keeperRewardDistributor;
bytes positionSoldAssetOracleData;
bytes pmxSoldAssetOracleData;
bytes nativeSoldAssetOracleData;
}
struct ClosePositionVars {
address payable dexAdapter;
uint256 borowedAssetAmount;
uint256 amountToReturn;
uint256 permanentLoss;
uint256 fee;
uint256 gasSpent;
}
struct ClosePositionEventData {
int256 profit;
uint256 debtAmount;
uint256 amountOut;
uint256 amountOutAfterFee;
IKeeperRewardDistributorStorage.KeeperActionType actionType;
address trader;
address paymentAsset;
IPrimexDNSStorageV3.FeeRateType feeRateType;
uint256 feeInPaymentAsset;
uint256 feeInPmx;
}
struct OpenPositionVars {
PrimexPricingLibrary.MegaRoute[] firstAssetMegaRoutes;
PrimexPricingLibrary.MegaRoute[] depositInThirdAssetMegaRoutes;
PrimexPricingLibrary.DepositData depositData;
uint256 borrowedAmount;
uint256 amountOutMin;
uint256 deadline;
bool isSpot;
bool isThirdAsset;
bool takeDepositFromWallet;
bool byOrder;
uint256 orderLeverage;
address sender;
LimitOrderLibrary.Condition[] closeConditions;
bool needOracleTolerableLimitCheck;
bytes firstAssetOracleData;
bytes thirdAssetOracleData;
bytes positionUsdOracleData;
bytes nativePositionAssetOracleData;
bytes pmxPositionAssetOracleData;
bytes nativeSoldAssetOracleData;
}
struct OpenPositionEventData {
uint256 feeInPositionAsset;
uint256 feeInPmx;
uint256 entryPrice;
uint256 leverage;
IPrimexDNSStorageV3.FeeRateType feeRateType;
}
/**
* The struct for openPosition function local vars
*/
struct OpenPositionLocalData {
uint256 amountToTransfer;
address payable dexAdapter;
address depositReceiver;
uint256 depositInPositionAsset;
bool isSpot;
IPrimexDNSStorageV3.TradingOrderType tradingOrderType;
uint256 positionAmountAfterFeeInSoldAsset;
uint256 borrowedAmountInPositionAsset;
uint256 leverage;
uint256 multiplierBorrowedAsset;
uint256 multiplierPositionAsset;
address positionAsset;
uint256 positionAmount;
}
/**
* @dev Structure for the OpenPositionParams when margin trading is activated
* @param bucket The bucket, from which the loan will be taken
* @param borrowedAmount The amount of tokens borrowed to be exchanged
* @param depositInThirdAssetMegaRoutes routes to swap deposit in third asset on dex
*/
struct OpenPositionMarginParams {
string bucket;
uint256 borrowedAmount;
PrimexPricingLibrary.MegaRoute[] depositInThirdAssetMegaRoutes;
}
/**
* @dev Structure for the openPosition with parameters necessary to open a position
* @param marginParams margin trading related params
* @param firstAssetMegaRoutes routes to swap first asset on dex
* (borrowedAmount + depositAmount if deposit in borrowedAsset)
* @param depositAsset The address of the deposit token (collateral for margin trade or
* locked funds for spot)
* @param depositAmount The amount of deposit funds for deal
* @param positionAsset The address output token for exchange
* @param amountOutMin The minimum amount of output tokens
* that must be received for the transaction not to revert.
* @param deadline Unix timestamp after which the transaction will revert.
* @param takeDepositFromWallet Bool, add a deposit within the current transaction
* @param closeConditions Array of conditions that position can be closed by
*/
struct OpenPositionParams {
OpenPositionMarginParams marginParams;
PrimexPricingLibrary.MegaRoute[] firstAssetMegaRoutes;
address depositAsset;
uint256 depositAmount;
address positionAsset;
uint256 amountOutMin;
uint256 deadline;
bool takeDepositFromWallet;
bool isProtocolFeeInPmx;
LimitOrderLibrary.Condition[] closeConditions;
bytes firstAssetOracleData;
bytes thirdAssetOracleData;
bytes depositSoldAssetOracleData;
bytes positionUsdOracleData;
bytes nativePositionAssetOracleData;
bytes pmxPositionAssetOracleData;
bytes nativeSoldAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
struct PositionManagerParams {
IPrimexDNSV3 primexDNS;
IPriceOracleV2 priceOracle;
ITraderBalanceVault traderBalanceVault;
uint256 oracleTolerableLimit;
uint256 oracleTolerableLimitForThirdAsset;
uint256 maxPositionSize;
uint256 initialGasLeft;
address keeperRewardDistributor;
}
struct ScaledParams {
uint256 decreasePercent;
uint256 scaledDebtAmount;
uint256 depositDecrease;
bool borrowedAmountIsNotZero;
}
enum CloseReason {
CLOSE_BY_TRADER,
RISKY_POSITION,
BUCKET_DELISTED,
LIMIT_CONDITION,
BATCH_LIQUIDATION,
BATCH_STOP_LOSS,
BATCH_TAKE_PROFIT
}
/**
* @dev Increases the deposit amount for a position.
* @param position The storage reference to the position.
* @param params The parameters for increasing the deposit.
* @return The amount of trader debtTokens burned.
*/
function increaseDeposit(Position storage position, IncreaseDepositParams memory params) public returns (uint256) {
_require(msg.sender == position.trader, Errors.CALLER_IS_NOT_TRADER.selector);
_require(position.scaledDebtAmount != 0, Errors.BORROWED_AMOUNT_IS_ZERO.selector);
address borrowedAsset = position.soldAsset;
uint256 depositAmountInBorrowed;
address depositReceiver = params.primexDNS.dexAdapter();
if (params.asset == borrowedAsset) {
depositReceiver = address(position.bucket);
depositAmountInBorrowed = params.amount;
}
if (params.takeDepositFromWallet) {
TokenTransfersLibrary.doTransferFromTo(params.asset, msg.sender, depositReceiver, params.amount);
} else {
params.traderBalanceVault.useTraderAssets(
ITraderBalanceVault.LockAssetParams(
msg.sender,
depositReceiver,
params.asset,
params.amount,
ITraderBalanceVault.OpenType.OPEN
)
);
}
if (params.asset != borrowedAsset) {
depositAmountInBorrowed = PrimexPricingLibrary.megaSwap(
PrimexPricingLibrary.MegaSwapParams({
tokenA: params.asset,
tokenB: borrowedAsset,
amountTokenA: params.amount,
megaRoutes: params.megaRoutes,
receiver: address(position.bucket),
deadline: block.timestamp
}),
0,
payable(params.primexDNS.dexAdapter()),
address(params.priceOracle),
false,
new bytes(0)
);
_require(depositAmountInBorrowed >= params.amountOutMin, Errors.SLIPPAGE_TOLERANCE_EXCEEDED.selector);
}
uint256 debt = getDebt(position);
uint256 amountToTrader;
uint256 debtToBurn = depositAmountInBorrowed;
if (depositAmountInBorrowed >= debt) {
amountToTrader = depositAmountInBorrowed - debt;
debtToBurn = debt;
position.scaledDebtAmount = 0;
if (amountToTrader > 0)
params.traderBalanceVault.topUpAvailableBalance(position.trader, borrowedAsset, amountToTrader);
} else {
position.scaledDebtAmount =
position.scaledDebtAmount -
debtToBurn.rdiv(position.bucket.getNormalizedVariableDebt());
}
position.depositAmountInSoldAsset += debtToBurn;
position.bucket.decreaseTraderDebt(
position.trader,
debtToBurn,
address(params.traderBalanceVault),
amountToTrader,
0
);
return debtToBurn;
}
/**
* @dev Decreases the deposit amount for a position.
* @param position The storage reference to the position.
* @param params The parameters for the decrease deposit operation.
*/
function decreaseDeposit(Position storage position, DecreaseDepositParams memory params) public {
_require(msg.sender == position.trader, Errors.CALLER_IS_NOT_TRADER.selector);
_require(position.bucket != IBucketV3(address(0)), Errors.IS_SPOT_POSITION.selector);
_require(position.bucket.isActive(), Errors.BUCKET_IS_NOT_ACTIVE.selector);
_require(params.amount > 0, Errors.DECREASE_AMOUNT_IS_ZERO.selector);
_require(params.amount <= position.depositAmountInSoldAsset, Errors.AMOUNT_IS_MORE_THAN_DEPOSIT.selector);
position.depositAmountInSoldAsset -= params.amount;
position.scaledDebtAmount =
position.scaledDebtAmount +
params.amount.rdiv(position.bucket.getNormalizedVariableDebt());
params.traderBalanceVault.topUpAvailableBalance(position.trader, position.soldAsset, params.amount);
uint256 feeInPaymentAsset = decodeFeeTokenAddress(position.extraParams) == address(0)
? 0
: PrimexPricingLibrary.calculateFeeInPaymentAsset(
PrimexPricingLibrary.CalculateFeeInPaymentAssetParams({
primexDNS: params.primexDNS,
priceOracle: address(params.priceOracle),
feeRateType: IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByKeeper,
paymentAsset: position.soldAsset,
paymentAmount: params.amount,
keeperRewardDistributor: params.keeperRewardDistributor,
gasSpent: 0,
isFeeProhibitedInPmx: true,
nativePaymentAssetOracleData: params.nativeSoldAssetOracleData
})
);
_require(
health(
position,
params.priceOracle,
params.pairPriceDrop,
params.securityBuffer,
params.oracleTolerableLimit,
feeInPaymentAsset,
params.positionSoldAssetOracleData
) >= WadRayMath.WAD + params.maintenanceBuffer,
Errors.INSUFFICIENT_DEPOSIT_SIZE.selector
);
position.bucket.increaseDebt(position.trader, params.amount, address(params.traderBalanceVault));
}
/**
* @notice Closes a position.
* @param position The position to be closed.
* @param params The parameters for closing the position.
* @param reason The reason for closing the position.
* @return posEventData The event data for the closed position.
*/
function closePosition(
Position memory position,
ClosePositionParams memory params,
CloseReason reason
) public returns (ClosePositionEventData memory) {
ClosePositionEventData memory posEventData;
ClosePositionVars memory vars;
if (params.borrowedAmountIsNotZero) {
posEventData.debtAmount = params.scaledDebtAmount.rmul(position.bucket.getNormalizedVariableDebt());
}
vars.dexAdapter = payable(params.primexDNS.dexAdapter());
TokenTransfersLibrary.doTransferOut(position.positionAsset, vars.dexAdapter, params.closeAmount);
posEventData.amountOut = PrimexPricingLibrary.megaSwap(
PrimexPricingLibrary.MegaSwapParams({
tokenA: position.positionAsset,
tokenB: position.soldAsset,
amountTokenA: params.closeAmount,
megaRoutes: params.megaRoutes,
receiver: address(this),
deadline: block.timestamp
}),
params.oracleTolerableLimit,
vars.dexAdapter,
address(params.priceOracle),
params.needOracleTolerableLimitCheck,
params.positionSoldAssetOracleData
);
posEventData.paymentAsset = decodeFeeTokenAddress(position.extraParams);
if (reason == CloseReason.CLOSE_BY_TRADER) {
posEventData.feeRateType = params.borrowedAmountIsNotZero
? IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByTrader
: IPrimexDNSStorageV3.FeeRateType.SpotPositionClosedByTrader;
vars.gasSpent = 0;
} else {
posEventData.feeRateType = params.borrowedAmountIsNotZero
? IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByKeeper
: IPrimexDNSStorageV3.FeeRateType.SpotPositionClosedByKeeper;
vars.gasSpent = params.initialGasLeft - gasleft();
}
(posEventData.feeInPaymentAsset, posEventData.feeInPmx) = PrimexPricingLibrary.payProtocolFee(
PrimexPricingLibrary.ProtocolFeeParams({
feeToken: posEventData.paymentAsset,
trader: position.trader,
priceOracle: address(params.priceOracle),
feeRateType: posEventData.feeRateType,
traderBalanceVault: params.traderBalanceVault,
swapManager: address(0),
keeperRewardDistributor: params.keeperRewardDistributor,
primexDNS: params.primexDNS,
paymentAsset: position.soldAsset,
paymentAmount: posEventData.amountOut,
gasSpent: vars.gasSpent,
isFeeProhibitedInPmx: reason == CloseReason.RISKY_POSITION,
pmxPaymentAssetOracleData: params.pmxSoldAssetOracleData,
nativePaymentAssetOracleData: params.nativeSoldAssetOracleData
})
);
posEventData.amountOutAfterFee = posEventData.amountOut - posEventData.feeInPaymentAsset;
TokenTransfersLibrary.doTransferOut({
token: position.soldAsset,
to: params.borrowedAmountIsNotZero ? address(position.bucket) : address(params.traderBalanceVault),
amount: posEventData.amountOutAfterFee
});
_require(
posEventData.amountOut >= params.amountOutMin && posEventData.amountOut > 0,
Errors.SLIPPAGE_TOLERANCE_EXCEEDED.selector
);
bool canBeClosed;
if (reason == CloseReason.CLOSE_BY_TRADER) {
canBeClosed = position.trader == msg.sender;
} else if (reason == CloseReason.RISKY_POSITION) {
canBeClosed =
health(
position,
params.priceOracle,
params.pairPriceDrop,
params.securityBuffer,
params.oracleTolerableLimit,
posEventData.feeInPaymentAsset,
params.positionSoldAssetOracleData
) <
WadRayMath.WAD;
posEventData.actionType = IKeeperRewardDistributorStorage.KeeperActionType.Liquidation;
} else if (reason == CloseReason.LIMIT_CONDITION) {
address cm = params.primexDNS.cmTypeToAddress(params.closeCondition.managerType);
_require(cm != address(0), Errors.INCORRECT_CM_TYPE.selector);
canBeClosed = IConditionalClosingManager(cm).canBeClosedAfterSwap(
position,
params.closeCondition.params,
params.ccmAdditionalParams,
params.closeAmount,
posEventData.amountOut,
params.positionSoldAssetOracleData
);
posEventData.actionType = IKeeperRewardDistributorStorage.KeeperActionType.StopLoss;
} else if (reason == CloseReason.BUCKET_DELISTED) {
canBeClosed = position.bucket != IBucketV3(address(0)) && position.bucket.isDelisted();
posEventData.actionType = IKeeperRewardDistributorStorage.KeeperActionType.BucketDelisted;
}
_require(canBeClosed, Errors.POSITION_CANNOT_BE_CLOSED_FOR_THIS_REASON.selector);
if (posEventData.amountOutAfterFee > posEventData.debtAmount) {
unchecked {
vars.amountToReturn = posEventData.amountOutAfterFee - posEventData.debtAmount;
}
} else {
unchecked {
vars.permanentLoss = posEventData.debtAmount - posEventData.amountOutAfterFee;
}
}
posEventData.profit = -int256(params.depositDecrease);
if (reason != CloseReason.RISKY_POSITION) {
if (vars.amountToReturn > 0) {
posEventData.profit += int256(vars.amountToReturn);
params.traderBalanceVault.topUpAvailableBalance(
reason == CloseReason.CLOSE_BY_TRADER ? params.depositReceiver : position.trader,
position.soldAsset,
vars.amountToReturn
);
}
}
if (params.borrowedAmountIsNotZero) {
position.bucket.decreaseTraderDebt(
position.trader,
posEventData.debtAmount,
reason == CloseReason.RISKY_POSITION ? params.primexDNS.treasury() : address(params.traderBalanceVault),
vars.amountToReturn,
vars.permanentLoss
);
}
// to avoid stack to deep
CloseReason _reason = reason;
if (params.closeAmount == position.positionAmount) {
emit ClosePosition({
positionId: position.id,
trader: position.trader,
closedBy: msg.sender,
bucketAddress: address(position.bucket),
soldAsset: position.soldAsset,
positionAsset: position.positionAsset,
decreasePositionAmount: position.positionAmount,
profit: posEventData.profit,
positionDebt: posEventData.debtAmount,
amountOut: posEventData.amountOutAfterFee,
reason: _reason
});
}
posEventData.trader = position.trader;
return posEventData;
}
/**
* @dev Sets the maximum position size between two tokens.
* @param maxPositionSize The storage mapping for maximum position sizes.
* @param token0 The address of token0.
* @param token1 The address of token1.
* @param amountInToken0 The maximum position size in token0.
* @param amountInToken1 The maximum position size in token1.
*/
function setMaxPositionSize(
mapping(address => mapping(address => uint256)) storage maxPositionSize,
address token0,
address token1,
uint256 amountInToken0,
uint256 amountInToken1
) public {
_require(token0 != address(0) && token1 != address(0), Errors.TOKEN_ADDRESS_IS_ZERO.selector);
_require(token0 != token1, Errors.IDENTICAL_ASSET_ADDRESSES.selector);
maxPositionSize[token1][token0] = amountInToken0;
maxPositionSize[token0][token1] = amountInToken1;
}
/**
* @dev Sets the tolerable limit for an oracle between two assets.
* @param oracleTolerableLimits The mapping to store oracle tolerable limits.
* @param assetA The address of the first asset.
* @param assetB The address of the second asset.
* @param percent The percentage tolerable limit for the oracle in WAD format (1 WAD = 100%).
*/
function setOracleTolerableLimit(
mapping(address => mapping(address => uint256)) storage oracleTolerableLimits,
address assetA,
address assetB,
uint256 percent
) public {
_require(assetA != address(0) && assetB != address(0), Errors.ASSET_ADDRESS_NOT_SUPPORTED.selector);
_require(assetA != assetB, Errors.IDENTICAL_ASSET_ADDRESSES.selector);
_require(percent <= WadRayMath.WAD && percent > 0, Errors.INVALID_PERCENT_NUMBER.selector);
oracleTolerableLimits[assetA][assetB] = percent;
oracleTolerableLimits[assetB][assetA] = percent;
}
/**
* @dev Sets the close conditions for a given position.
* @param position The position for which to set the close conditions.
* @param closeConditionsMap The storage mapping of close conditions for each position ID.
* @param closeConditions The array of close conditions to be set.
* @param primexDNS The address of the IPrimexDNS contract.
*/
function setCloseConditions(
Position memory position,
mapping(uint256 => LimitOrderLibrary.Condition[]) storage closeConditionsMap,
LimitOrderLibrary.Condition[] memory closeConditions,
IPrimexDNSV3 primexDNS
) public {
_require(
LimitOrderLibrary.hasNoConditionManagerTypeDuplicates(closeConditions),
Errors.SHOULD_NOT_HAVE_DUPLICATES.selector
);
if (closeConditionsMap[position.id].length > 0) {
delete closeConditionsMap[position.id];
}
LimitOrderLibrary.Condition memory condition;
for (uint256 i; i < closeConditions.length; i++) {
condition = closeConditions[i];
_require(
IERC165Upgradeable(primexDNS.cmTypeToAddress(condition.managerType)).supportsInterface(
type(IConditionalClosingManager).interfaceId
),
Errors.SHOULD_BE_CCM.selector
);
closeConditionsMap[position.id].push(condition);
}
}
/**
* @notice Opens a position by depositing assets and borrowing funds (except when the position is spot)
* @param _position The position to be opened
* @param _vars Variables related to the position opening
* @param _pmParams Parameters for the PositionManager contract
* @return The updated position and event data
*/
function openPosition(
Position memory _position,
OpenPositionVars memory _vars,
PositionManagerParams memory _pmParams
) public returns (Position memory, OpenPositionEventData memory) {
OpenPositionLocalData memory data;
if (_vars.isSpot) {
data.tradingOrderType = _vars.byOrder
? IPrimexDNSStorageV3.TradingOrderType.SpotLimitOrder
: IPrimexDNSStorageV3.TradingOrderType.SpotMarketOrder;
} else {
if (_vars.byOrder) {
data.tradingOrderType = _vars.isThirdAsset
? IPrimexDNSStorageV3.TradingOrderType.MarginLimitOrderDepositInThirdAsset
: IPrimexDNSStorageV3.TradingOrderType.MarginLimitOrder;
} else {
data.tradingOrderType = IPrimexDNSStorageV3.TradingOrderType.MarginMarketOrder;
}
}
PrimexPricingLibrary.validateMinPositionSize(
_vars.borrowedAmount + _position.depositAmountInSoldAsset,
_position.soldAsset,
address(_pmParams.priceOracle),
IKeeperRewardDistributorV3(_pmParams.keeperRewardDistributor),
_pmParams.primexDNS,
data.tradingOrderType,
_vars.nativeSoldAssetOracleData
);
data.amountToTransfer = _vars.borrowedAmount;
data.dexAdapter = payable(_pmParams.primexDNS.dexAdapter());
data.depositReceiver = data.dexAdapter;
if (_vars.depositData.depositAsset == _position.positionAsset) {
_position.positionAmount = _vars.depositData.depositAmount;
data.depositInPositionAsset = _vars.depositData.depositAmount;
data.depositReceiver = address(this);
} else if (_vars.depositData.depositAsset == _position.soldAsset) {
data.amountToTransfer += _vars.depositData.depositAmount;
}
data.isSpot = _vars.borrowedAmount == 0;
if (data.isSpot) _vars.depositData.depositAsset = _position.soldAsset;
if (_vars.takeDepositFromWallet) {
TokenTransfersLibrary.doTransferFromTo(
_vars.depositData.depositAsset,
msg.sender,
data.depositReceiver,
_vars.depositData.depositAmount
);
} else {
_pmParams.traderBalanceVault.useTraderAssets(
ITraderBalanceVault.LockAssetParams({
trader: _position.trader,
depositReceiver: data.depositReceiver,
depositAsset: _vars.depositData.depositAsset,
depositAmount: _vars.depositData.depositAmount,
openType: _vars.byOrder
? ITraderBalanceVault.OpenType.OPEN_BY_ORDER
: ITraderBalanceVault.OpenType.OPEN
})
);
}
if (!data.isSpot) {
_position.bucket.increaseDebt(_position.trader, _vars.borrowedAmount, data.dexAdapter);
// @note You need to write index only after opening a position in bucket.
// Since when opening position in the bucket, index becomes relevant (containing accumulated profit)
_position.openBorrowIndex = _position.bucket.variableBorrowIndex();
_position.scaledDebtAmount = _vars.borrowedAmount.rdiv(_position.openBorrowIndex);
}
if (_vars.isThirdAsset) {
data.depositInPositionAsset = PrimexPricingLibrary.megaSwap(
PrimexPricingLibrary.MegaSwapParams({
tokenA: _vars.depositData.depositAsset,
tokenB: _position.positionAsset,
amountTokenA: _vars.depositData.depositAmount,
megaRoutes: _vars.depositInThirdAssetMegaRoutes,
receiver: address(this),
deadline: _vars.deadline
}),
_pmParams.oracleTolerableLimitForThirdAsset,
data.dexAdapter,
address(_pmParams.priceOracle),
true,
_vars.thirdAssetOracleData
);
_position.positionAmount += data.depositInPositionAsset;
} else {
_require(
_vars.depositInThirdAssetMegaRoutes.length == 0,
Errors.DEPOSIT_IN_THIRD_ASSET_ROUTES_LENGTH_SHOULD_BE_0.selector
);
}
data.borrowedAmountInPositionAsset = PrimexPricingLibrary.megaSwap(
PrimexPricingLibrary.MegaSwapParams({
tokenA: _position.soldAsset,
tokenB: _position.positionAsset,
amountTokenA: data.isSpot ? _vars.depositData.depositAmount : data.amountToTransfer,
megaRoutes: _vars.firstAssetMegaRoutes,
receiver: address(this),
deadline: _vars.deadline
}),
_pmParams.oracleTolerableLimit,
data.dexAdapter,
address(_pmParams.priceOracle),
_vars.needOracleTolerableLimitCheck,
_vars.firstAssetOracleData
);
_position.positionAmount += data.borrowedAmountInPositionAsset;
OpenPositionEventData memory posEventData;
if (_vars.byOrder) {
posEventData.feeRateType = data.isSpot
? IPrimexDNSStorageV3.FeeRateType.SpotLimitOrderExecuted
: IPrimexDNSStorageV3.FeeRateType.MarginLimitOrderExecuted;
(posEventData.feeInPositionAsset, posEventData.feeInPmx) = PrimexPricingLibrary.payProtocolFee(
PrimexPricingLibrary.ProtocolFeeParams({
feeToken: decodeFeeTokenAddress(_position.extraParams),
trader: _position.trader,
priceOracle: address(_pmParams.priceOracle),
feeRateType: posEventData.feeRateType,
traderBalanceVault: _pmParams.traderBalanceVault,
swapManager: address(0),
keeperRewardDistributor: _pmParams.keeperRewardDistributor,
primexDNS: _pmParams.primexDNS,
paymentAsset: _position.positionAsset,
paymentAmount: _position.positionAmount,
gasSpent: _pmParams.initialGasLeft - gasleft(),
isFeeProhibitedInPmx: false,
pmxPaymentAssetOracleData: _vars.pmxPositionAssetOracleData,
nativePaymentAssetOracleData: _vars.nativePositionAssetOracleData
})
);
_position.positionAmount -= posEventData.feeInPositionAsset;
}
_require(_position.positionAmount >= _vars.amountOutMin, Errors.SLIPPAGE_TOLERANCE_EXCEEDED.selector);
data.leverage = WadRayMath.WAD;
if (!data.isSpot) {
_require(_pmParams.maxPositionSize >= _position.positionAmount, Errors.POSITION_SIZE_EXCEEDED.selector);
if (_vars.depositData.depositAsset == _position.soldAsset) {
data.positionAmountAfterFeeInSoldAsset =
(data.amountToTransfer * _position.positionAmount) /
(_position.positionAmount + posEventData.feeInPositionAsset);
_require(
data.positionAmountAfterFeeInSoldAsset > _vars.borrowedAmount,
Errors.INSUFFICIENT_DEPOSIT.selector
);
data.leverage = data.positionAmountAfterFeeInSoldAsset.wdiv(
data.positionAmountAfterFeeInSoldAsset - _vars.borrowedAmount
);
} else {
_require(
data.depositInPositionAsset > posEventData.feeInPositionAsset,
Errors.INSUFFICIENT_DEPOSIT.selector
);
data.leverage = _position.positionAmount.wdiv(
data.depositInPositionAsset - posEventData.feeInPositionAsset
);
}
// to avoid stack to deep
data.positionAsset = _position.positionAsset;
data.positionAmount = _position.positionAmount;
// protocolFee calculated in position Asset
_require(
data.leverage <=
_position.bucket.maxAssetLeverage(
_position.positionAsset,
PrimexPricingLibrary
.calculateFeeInPaymentAsset(
PrimexPricingLibrary.CalculateFeeInPaymentAssetParams({
primexDNS: _pmParams.primexDNS,
priceOracle: address(_pmParams.priceOracle),
feeRateType: IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByKeeper,
paymentAsset: data.positionAsset,
paymentAmount: data.positionAmount,
keeperRewardDistributor: _pmParams.keeperRewardDistributor,
gasSpent: 0,
isFeeProhibitedInPmx: true,
nativePaymentAssetOracleData: _vars.nativePositionAssetOracleData
})
)
.wdiv(data.positionAmount)
),
Errors.INSUFFICIENT_DEPOSIT.selector
);
if (_vars.byOrder) {
uint256 leverageTolerance = _pmParams.primexDNS.leverageTolerance();
_require(
data.leverage <= _vars.orderLeverage.wmul(WadRayMath.WAD + leverageTolerance) &&
data.leverage >= _vars.orderLeverage.wmul(WadRayMath.WAD - leverageTolerance),
Errors.LEVERAGE_TOLERANCE_EXCEEDED.selector
);
}
}
if (!_vars.byOrder) {
_vars.depositData.leverage = data.leverage;
}
data.multiplierBorrowedAsset = 10 ** (18 - IERC20Metadata(_position.soldAsset).decimals());
data.multiplierPositionAsset = 10 ** (18 - IERC20Metadata(_position.positionAsset).decimals());
posEventData.entryPrice =
((_vars.borrowedAmount + _position.depositAmountInSoldAsset) * data.multiplierBorrowedAsset).wdiv(
(_position.positionAmount + posEventData.feeInPositionAsset) * data.multiplierPositionAsset
) /
data.multiplierBorrowedAsset;
posEventData.leverage = _vars.depositData.leverage;
return (_position, posEventData);
}
/**
* @dev Retrieves the debt amount for a given position.
* @param position The Position struct representing the position to get the debt amount for.
* @return The debt amount in debtTokens.
*/
function getDebt(Position memory position) public view returns (uint256) {
if (position.scaledDebtAmount == 0) return 0;
return position.scaledDebtAmount.rmul(position.bucket.getNormalizedVariableDebt());
}
/**
* @dev Calculates the health of a position.
* @dev health = ((1 - securityBuffer) * (1 - oracleTolerableLimit) * (1 - priceDrop) * positionAmountInBorrowedAsset) /
(feeBuffer * debt)
* @param position The position object containing relevant information.
* @param priceOracle The price oracle contract used for obtaining asset prices.
* @param pairPriceDrop The priceDrop in WAD format of the asset pair.
* @param securityBuffer The security buffer in WAD format for the position.
* @param oracleTolerableLimit The tolerable limit in WAD format for the price oracle.
* @return The health value in WAD format of the position.
*/
function health(
Position memory position,
IPriceOracleV2 priceOracle,
uint256 pairPriceDrop,
uint256 securityBuffer,
uint256 oracleTolerableLimit,
uint256 feeInPaymentAsset,
bytes memory positionSoldAssetOracleData
) public returns (uint256) {
if (position.scaledDebtAmount == 0) return WadRayMath.WAD;
return
health(
PrimexPricingLibrary.getOracleAmountsOut(
position.positionAsset,
position.soldAsset,
position.positionAmount,
address(priceOracle),
positionSoldAssetOracleData
) - feeInPaymentAsset,
pairPriceDrop,
securityBuffer,
oracleTolerableLimit,
getDebt(position),
position.bucket.feeBuffer()
);
}
/**
* @dev Creates a new position based on the given parameters.
* @param _params The input parameters for creating the position.
* @param primexDNS The address of the PrimexDNS contract.
* @param priceOracle The address of the PriceOracle contract.
* @return position The created Position struct.
* @return vars The OpenPositionVars struct.
*/
function createPosition(
OpenPositionParams calldata _params,
IPrimexDNSV3 primexDNS,
IPriceOracleV2 priceOracle
) public returns (Position memory, OpenPositionVars memory) {
OpenPositionVars memory vars = OpenPositionVars({
firstAssetMegaRoutes: _params.firstAssetMegaRoutes,
depositInThirdAssetMegaRoutes: _params.marginParams.depositInThirdAssetMegaRoutes,
depositData: PrimexPricingLibrary.DepositData({
depositAsset: address(0),
depositAmount: _params.depositAmount,
leverage: 0
}),
borrowedAmount: _params.marginParams.borrowedAmount,
amountOutMin: _params.amountOutMin,
deadline: _params.deadline,
isSpot: _params.marginParams.borrowedAmount == 0,
isThirdAsset: false,
takeDepositFromWallet: _params.takeDepositFromWallet,
byOrder: false,
orderLeverage: 0,
sender: address(0),
closeConditions: _params.closeConditions,
needOracleTolerableLimitCheck: _params.marginParams.borrowedAmount > 0,
firstAssetOracleData: _params.firstAssetOracleData,
thirdAssetOracleData: _params.thirdAssetOracleData,
positionUsdOracleData: _params.positionUsdOracleData,
nativePositionAssetOracleData: _params.nativePositionAssetOracleData,
pmxPositionAssetOracleData: _params.pmxPositionAssetOracleData,
nativeSoldAssetOracleData: _params.nativeSoldAssetOracleData
});
PositionLibrary.Position memory position = PositionLibrary.Position({
id: 0,
scaledDebtAmount: 0,
bucket: IBucketV3(address(0)),
soldAsset: address(0),
depositAmountInSoldAsset: 0,
positionAsset: _params.positionAsset,
positionAmount: 0,
trader: msg.sender,
openBorrowIndex: 0,
createdAt: block.timestamp,
updatedConditionsAt: block.timestamp,
extraParams: ""
});
if (vars.isSpot) {
_require(_params.depositAsset != _params.positionAsset, Errors.SHOULD_BE_DIFFERENT_ASSETS_IN_SPOT.selector);
_require(bytes(_params.marginParams.bucket).length == 0, Errors.BUCKET_SHOULD_BE_UNDEFINED.selector);
position.soldAsset = _params.depositAsset;
position.depositAmountInSoldAsset = vars.depositData.depositAmount;
vars.depositData.leverage = WadRayMath.WAD;
} else {
position.bucket = IBucketV3(primexDNS.getBucketAddress(_params.marginParams.bucket));
position.soldAsset = address(position.bucket.borrowedAsset());
vars.depositData.depositAsset = _params.depositAsset;
(, bool tokenAllowed) = position.bucket.allowedAssets(_params.positionAsset);
_require(tokenAllowed, Errors.TOKEN_NOT_SUPPORTED.selector);
vars.isThirdAsset =
_params.depositAsset != position.soldAsset &&
_params.depositAsset != _params.positionAsset;
position.depositAmountInSoldAsset = PrimexPricingLibrary.getOracleAmountsOut(
_params.depositAsset,
position.soldAsset,
_params.depositAmount,
address(priceOracle),
_params.depositSoldAssetOracleData
);
}
address feeToken = _params.isProtocolFeeInPmx ? primexDNS.pmx() : position.soldAsset;
position.extraParams = abi.encode(feeToken);
return (position, vars);
}
/**
* @notice Creates a position based on the provided order parameters.
* @dev This function calculates and returns a Position and OpenPositionVars struct.
* @param _params The OpenPositionByOrderParams struct containing the order parameters.
* @param priceOracle The price oracle contract used for retrieving asset prices.
* @return position The Position struct representing the created position.
* @return vars The OpenPositionVars struct containing additional variables related to the position.
*/
function createPositionByOrder(
LimitOrderLibrary.OpenPositionByOrderParams calldata _params,
IPriceOracleV2 priceOracle,
IPrimexDNSV3 primexDNS
) public returns (Position memory, OpenPositionVars memory) {
OpenPositionVars memory vars = OpenPositionVars({
firstAssetMegaRoutes: _params.firstAssetMegaRoutes,
depositInThirdAssetMegaRoutes: _params.depositInThirdAssetMegaRoutes,
depositData: PrimexPricingLibrary.DepositData({
depositAsset: address(0),
depositAmount: _params.order.depositAmount,
leverage: _params.order.leverage
}),
borrowedAmount: _params.borrowedAmount,
amountOutMin: 0,
orderLeverage: _params.order.leverage,
deadline: _params.order.deadline,
isSpot: _params.order.leverage == WadRayMath.WAD,
isThirdAsset: false,
takeDepositFromWallet: false,
byOrder: true,
sender: _params.sender,
closeConditions: _params.closeConditions,
needOracleTolerableLimitCheck: address(_params.order.bucket) != address(0),
firstAssetOracleData: _params.firstAssetOracleData,
thirdAssetOracleData: _params.thirdAssetOracleData,
positionUsdOracleData: _params.positionUsdOracleData,
nativePositionAssetOracleData: _params.nativePositionAssetOracleData,
pmxPositionAssetOracleData: _params.pmxPositionAssetOracleData,
nativeSoldAssetOracleData: _params.nativeSoldAssetOracleData
});
Position memory position = Position({
id: 0,
scaledDebtAmount: 0,
bucket: IBucketV3(address(0)),
soldAsset: address(0),
depositAmountInSoldAsset: 0,
positionAsset: _params.order.positionAsset,
positionAmount: 0,
trader: _params.order.trader,
openBorrowIndex: 0,
createdAt: block.timestamp,
updatedConditionsAt: block.timestamp,
extraParams: ""
});
if (vars.isSpot) {
position.soldAsset = _params.order.depositAsset;
position.depositAmountInSoldAsset = vars.depositData.depositAmount;
} else {
position.bucket = _params.order.bucket;
position.soldAsset = address(position.bucket.borrowedAsset());
vars.depositData.depositAsset = _params.order.depositAsset;
vars.isThirdAsset =
_params.order.depositAsset != position.soldAsset &&
_params.order.depositAsset != _params.order.positionAsset;
position.depositAmountInSoldAsset = PrimexPricingLibrary.getOracleAmountsOut(
_params.order.depositAsset,
position.soldAsset,
_params.order.depositAmount,
address(priceOracle),
_params.depositSoldAssetOracleData
);
if (_params.order.depositAsset == position.soldAsset) {
_require(
vars.borrowedAmount == _params.order.depositAmount.wmul(_params.order.leverage - WadRayMath.WAD),
Errors.INCORRECT_BORROWED_AMOUNT.selector
);
}
}
address feeToken = _params.order.feeToken == primexDNS.pmx() ? primexDNS.pmx() : position.soldAsset;
position.extraParams = abi.encode(feeToken);
return (position, vars);
}
/**
* @notice Decodes a fee token address from the provided encoded data.
* @param data The encoded data containing the fee token address.
* @return The decoded fee token address.
*/
function decodeFeeTokenAddress(bytes memory data) public pure returns (address) {
// Check if there is data in the bytes extraParams
if (data.length == 0) {
// If there is no data, return address(0)
return address(0);
} else {
// Decode the data into an address and return the result
return abi.decode(data, (address));
}
}
/**
* @notice Calculates the health score for a position.
* @param positionAmountInBorrowedAsset The position size in borrow asset.
* @param pairPriceDrop The priceDrop in WAD format of the pair.
* @param securityBuffer The security buffer in WAD format.
* @param oracleTolerableLimit The tolerable limit in WAD format for the oracle.
* @param positionDebt The debt of the position.
* @param feeBuffer The buffer for fees.
* @return The health score of the position.
*/
function health(
uint256 positionAmountInBorrowedAsset,
uint256 pairPriceDrop,
uint256 securityBuffer,
uint256 oracleTolerableLimit,
uint256 positionDebt,
uint256 feeBuffer
) public pure returns (uint256) {
return
(
(WadRayMath.WAD - securityBuffer)
.wmul(WadRayMath.WAD - oracleTolerableLimit)
.wmul(WadRayMath.WAD - pairPriceDrop)
.wmul(positionAmountInBorrowedAsset)
).wdiv(feeBuffer.wmul(positionDebt));
}
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {BytesLib} from "./utils/BytesLib.sol";
import {WadRayMath} from "./utils/WadRayMath.sol";
import {NATIVE_CURRENCY, USD, USD_MULTIPLIER, ARB_NITRO_ORACLE, OVM_GASPRICEORACLE, GAS_FOR_BYTE, TRANSACTION_METADATA_BYTES} from "../Constants.sol";
import {IDexAdapter} from "../interfaces/IDexAdapter.sol";
import {IPriceOracle} from "../PriceOracle/IPriceOracle.sol";
import {IKeeperRewardDistributorStorage, IKeeperRewardDistributorV3} from "../KeeperRewardDistributor/IKeeperRewardDistributor.sol";
import {IPrimexDNSV3, IPrimexDNSStorageV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IBucketV3} from "../Bucket/IBucket.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {TokenTransfersLibrary} from "./TokenTransfersLibrary.sol";
import {IPriceOracleStorageV2} from "../PriceOracle/IPriceOracleStorage.sol";
import {IPriceOracleV2} from "../PriceOracle/IPriceOracle.sol";
import "./Errors.sol";
library PrimexPricingLibrary {
using WadRayMath for uint256;
using BytesLib for bytes;
/**
* @param dexName The name of the DEX.
* @param shares the share that will be allocated from the total amount for the route
* @param payload payload data encoded in bytes
*/
struct Path {
string dexName;
uint256 shares;
bytes payload;
}
/**
* @param to the destination token of the route
* @param paths path array through which the swap will be made up to the destination token this the route
*/
struct Route {
address to;
Path[] paths;
}
/**
* @param shares the share that will be allocated from the total amount for this MegaRoute
* @param routes array of routes through which the swap will be made up to TokenB
*/
struct MegaRoute {
uint256 shares;
Route[] routes;
}
struct MegaSwapParams {
address tokenA;
address tokenB;
uint256 amountTokenA;
MegaRoute[] megaRoutes;
address receiver;
uint256 deadline;
}
struct AmountParams {
address tokenA;
address tokenB;
uint256 amount;
MegaRoute[] megaRoutes;
address dexAdapter;
address primexDNS;
}
struct DepositData {
address depositAsset;
uint256 depositAmount;
uint256 leverage;
}
/**
* @param feeToken An asset in which the fee will be paid.
* @param trader The trader address
* @param priceOracle PriceOracle contract address
* @param orderType Type of possible order in Primex protocol
* @param traderBalanceVault TraderBalanceVault contract address
* @param primexDNS PrimexDNS contract address
*/
struct ProtocolFeeParams {
address feeToken;
address trader;
address priceOracle;
IPrimexDNSStorageV3.FeeRateType feeRateType;
ITraderBalanceVault traderBalanceVault;
address swapManager;
address keeperRewardDistributor;
IPrimexDNSV3 primexDNS;
address paymentAsset;
uint256 paymentAmount;
uint256 gasSpent;
bool isFeeProhibitedInPmx;
bytes pmxPaymentAssetOracleData;
bytes nativePaymentAssetOracleData;
}
struct ProtocolFeeParamsBatchClose {
uint256 numberOfPositions;
address[] feeTokens;
address[] traders;
uint256[] paymentAmounts;
address paymentAsset;
address priceOracle;
IPrimexDNSStorageV3.FeeRateType feeRateType;
ITraderBalanceVault traderBalanceVault;
address keeperRewardDistributor;
IPrimexDNSV3 primexDNS;
uint256 estimatedGasAmount;
bool isFeeProhibitedInPmx;
uint256 estimatedBaseLength;
bytes nativePaymentAssetOracleData;
bytes pmxPaymentAssetOracleData;
}
struct CalculateFeeInPaymentAssetParams {
IPrimexDNSV3 primexDNS;
address priceOracle;
IPrimexDNSStorageV3.FeeRateType feeRateType;
address paymentAsset;
uint256 paymentAmount;
address keeperRewardDistributor;
uint256 gasSpent;
bool isFeeProhibitedInPmx;
bytes nativePaymentAssetOracleData;
}
struct MinProtocolFeeParams {
uint256 restrictedGasSpent;
address paymentAsset;
address priceOracle;
IKeeperRewardDistributorV3 keeperRewardDistributor;
IPrimexDNSV3 primexDNS;
bool isFeeProhibitedInPmx;
IPrimexDNSStorageV3.FeeRateType feeRateType;
bytes nativePaymentAssetOracleData;
}
/**
* The struct for payProtocolFee function
*/
struct ProtocolFeeVars {
address pmx;
address treasury;
uint256 feeInPaymentAssetWithDiscount;
uint256 pmxTraderBalance;
uint256 pmxTraderBalanceInPaymentAsset;
uint256 pmxDiscountMultiplier;
}
/**
* The struct for calculateFeeInPaymentAssetVars function
*/
struct FeeInPaymentAssetVars {
uint256 protocolFeeRate;
uint256 maxProtocolFee;
uint256 feeInPaymentAsset;
uint256 maxProtocolFeeInPaymentAsset;
uint256 minProtocolFeeInPaymentAsset;
}
/**
* The struct for minProtocolFee function
*/
struct MinProtocolFeeVars {
uint256 maxGasAmount;
uint256 restrictedGasPrice;
uint256 l1CostWei;
uint256 liquidationGasAmount;
uint256 protocolFeeCoefficient;
uint256 additionalGasSpent;
uint256 minProtocolFeeInNativeAsset;
uint256 totalGasSpent;
uint256 baseLength;
uint256 optimisticGasCoefficient;
IPrimexDNSStorageV3.CallingMethod callingMethod;
IKeeperRewardDistributorStorage.PaymentModel paymentModel;
}
/**
* The struct for calculateFeeInPaymentAssetBatchClose function
*/
struct CalculateFeeInPaymentAssetBatchCloseVars {
uint256[] feeInPaymentAsset;
uint256 protocolFeeRate;
uint256 maxProtocolFee;
uint256 maxProtocolFeeInPaymentAsset;
uint256 minProtocolFeeInPaymentAsset;
}
/**
* The struct for calculateRestrictedGasPrice function
*/
struct RestrictedGasPriceVars {
int256 oracleGasPrice;
uint256 maxGasPrice;
uint256 defaultMaxGasPrice;
uint256 oracleGasPriceTolerance;
}
/**
* The struct for getLiquidationPrice and getLiquidationPriceByOrder functions
*/
struct LiquidationPriceData {
IBucketV3 bucket;
IPositionManagerV2 positionManager;
IPriceOracleV2 priceOracle;
IERC20Metadata borrowedAsset;
}
event Withdraw(
address indexed withdrawer,
address borrowAssetReceiver,
address borrowedAsset,
uint256 amount,
uint256 timestamp
);
/**
* @notice Encodes the given parameters into a bytes array based on the specified DEX type.
* @param path The token path for the swap.
* @param dexRouter The address of the DEX router.
* @param ancillaryData Additional data required for certain DEX types.
* @param dexAdapter The address of the DEX adapter.
* @param isAmountToBuy A flag indicating whether it is the path for the swap with fixed amountIn or amountOut.
* Swap with fixed amountIn, if true.
* @return The encoded bytes array.
*/
function encodePath(
address[] memory path,
address dexRouter,
bytes32 ancillaryData,
address payable dexAdapter,
bool isAmountToBuy
) external view returns (bytes memory) {
IDexAdapter.DexType type_ = IDexAdapter(dexAdapter).dexType(dexRouter);
if (type_ == IDexAdapter.DexType.UniswapV2 || type_ == IDexAdapter.DexType.Meshswap) {
return abi.encode(path);
}
if (type_ == IDexAdapter.DexType.UniswapV3) {
if (isAmountToBuy)
return bytes.concat(bytes20(path[1]), bytes3(uint24(uint256(ancillaryData))), bytes20(path[0]));
return bytes.concat(bytes20(path[0]), bytes3(uint24(uint256(ancillaryData))), bytes20(path[1]));
}
if (type_ == IDexAdapter.DexType.AlgebraV3) {
if (isAmountToBuy) return bytes.concat(bytes20(path[1]), bytes20(path[0]));
return bytes.concat(bytes20(path[0]), bytes20(path[1]));
}
if (type_ == IDexAdapter.DexType.Curve) {
address[] memory pools = new address[](1);
pools[0] = address(uint160(uint256(ancillaryData)));
return abi.encode(path, pools);
}
if (type_ == IDexAdapter.DexType.Balancer) {
int256[] memory limits = new int256[](2);
limits[0] = type(int256).max;
bytes32[] memory pools = new bytes32[](1);
pools[0] = ancillaryData;
return abi.encode(path, pools, limits);
}
_revert(Errors.UNKNOWN_DEX_TYPE.selector);
}
/**
* @notice Calculates the amount of deposit assets in borrowed assets.
* @param _params The parameters for the calculation.
* @param _isThirdAsset A flag indicating if deposit is in a third asset.
* @param _priceOracle The address of the price oracle.
* @return The amount of deposit assets is measured in borrowed assets.
*/
function getDepositAmountInBorrowed(
IDexAdapter.AmountParams calldata _params,
bool _isThirdAsset,
address payable _dexAdapter,
address _priceOracle,
bytes calldata _oracleData
) public returns (uint256) {
_require(
IERC165(_priceOracle).supportsInterface(type(IPriceOracleV2).interfaceId),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
if (_params.tokenA == _params.tokenB) {
_require(_params.megaRoutes.length == 0, Errors.DEPOSITED_TO_BORROWED_ROUTES_LENGTH_SHOULD_BE_0.selector);
return _params.amount;
}
uint256 depositAmountInBorrowed = IDexAdapter(_dexAdapter).getAmountOutByMegaRoutes(_params);
if (_isThirdAsset) {
uint256 oracleDepositAmountOut = getOracleAmountsOut(
_params.tokenA,
_params.tokenB,
_params.amount,
_priceOracle,
_oracleData
);
if (depositAmountInBorrowed > oracleDepositAmountOut) depositAmountInBorrowed = oracleDepositAmountOut;
}
return depositAmountInBorrowed;
}
/**
* @notice Performs a multi-hop swap transaction using the specified parameters.
* @dev This function executes a series of token swaps on different DEXs based on the provided routes.
* @param _params The struct containing all the necessary parameters for the multi-hop swap.
* @param _maximumOracleTolerableLimit The maximum tolerable limit in WAD format (1 WAD = 100%)
* for the price difference between DEX and the oracle.
* @param _dexAdapter The address of the Dex adapter contract.
* @param _priceOracle The address of the price oracle contract.
* @param _needOracleTolerableLimitCheck Flag indicating whether to perform an oracle tolerable limit check.
* @return The final balance of the _params.tokenB in the receiver's address after the multi-hop swap.
*/
function megaSwap(
MegaSwapParams calldata _params,
uint256 _maximumOracleTolerableLimit,
address payable _dexAdapter,
address _priceOracle,
bool _needOracleTolerableLimitCheck,
bytes calldata _oracleData
) public returns (uint256) {
uint256 balance = IERC20Metadata(_params.tokenB).balanceOf(_params.receiver);
IDexAdapter(_dexAdapter).performMegaRoutesSwap(_params);
balance = IERC20Metadata(_params.tokenB).balanceOf(_params.receiver) - balance;
if (_needOracleTolerableLimitCheck) {
_require(
balance >=
getOracleAmountsOut(_params.tokenA, _params.tokenB, _params.amountTokenA, _priceOracle, _oracleData)
.wmul(WadRayMath.WAD - _maximumOracleTolerableLimit),
Errors.DIFFERENT_PRICE_DEX_AND_ORACLE.selector
);
}
return balance;
}
/**
* @notice Pays the protocol fee.
* @dev This function transfers the protocol fee from the trader to the protocol treasury.
* @param params The parameters for paying the protocol fee.
* @return feeInPaymentAsset The amount of the protocol fee in a payment asset
* (position asset for the limit order execution, sold asset when the position is closed.)
* @return feeInPmx The amount of the protocol fee in pmx asset paid.
*/
function payProtocolFee(
ProtocolFeeParams memory params
) public returns (uint256 feeInPaymentAsset, uint256 feeInPmx) {
// This is done to ensure that after upgrading the contracts, positions that have already been opened
// and had fees paid for them will not incur additional fees upon closure
if (params.feeToken == address(0)) {
return (0, 0);
}
ProtocolFeeVars memory vars;
(vars.pmx, vars.treasury, , , vars.pmxDiscountMultiplier) = params.primexDNS.getPrimexDNSParams(
params.feeRateType
);
feeInPaymentAsset = calculateFeeInPaymentAsset(
CalculateFeeInPaymentAssetParams({
primexDNS: params.primexDNS,
priceOracle: params.priceOracle,
feeRateType: params.feeRateType,
paymentAsset: params.paymentAsset,
paymentAmount: params.paymentAmount,
keeperRewardDistributor: params.keeperRewardDistributor,
gasSpent: params.gasSpent,
isFeeProhibitedInPmx: params.isFeeProhibitedInPmx,
nativePaymentAssetOracleData: params.nativePaymentAssetOracleData
})
);
(vars.pmxTraderBalance, ) = params.traderBalanceVault.balances(params.trader, vars.pmx);
if (params.feeToken == vars.pmx && vars.pmxTraderBalance > 0 && !params.isFeeProhibitedInPmx) {
// pmx => payment asset data
uint256 pmxTraderBalanceInPaymentAsset = getOracleAmountsOut(
vars.pmx,
params.paymentAsset,
vars.pmxTraderBalance,
params.priceOracle,
params.pmxPaymentAssetOracleData
);
uint256 feeInPaymentAssetWithDiscount = feeInPaymentAsset.wmul(vars.pmxDiscountMultiplier);
feeInPmx = (feeInPaymentAssetWithDiscount * vars.pmxTraderBalance) / pmxTraderBalanceInPaymentAsset;
if (pmxTraderBalanceInPaymentAsset >= feeInPaymentAssetWithDiscount) {
feeInPaymentAsset = 0;
params.traderBalanceVault.withdrawFrom(params.trader, vars.treasury, vars.pmx, feeInPmx, false);
} else {
feeInPmx = vars.pmxTraderBalance;
feeInPaymentAsset -= pmxTraderBalanceInPaymentAsset.wdiv(vars.pmxDiscountMultiplier);
params.traderBalanceVault.withdrawFrom(
params.trader,
vars.treasury,
vars.pmx,
vars.pmxTraderBalance,
false
);
TokenTransfersLibrary.doTransferOut(params.paymentAsset, vars.treasury, feeInPaymentAsset);
}
} else {
TokenTransfersLibrary.doTransferOut(params.paymentAsset, vars.treasury, feeInPaymentAsset);
}
}
/**
* @notice Calculate and return protocol fee
* @return The amount of the protocol fee in '_feeToken' which needs to be paid according to the specified deposit parameters.
*/
function calculateFeeInPaymentAsset(CalculateFeeInPaymentAssetParams memory params) public returns (uint256) {
FeeInPaymentAssetVars memory vars;
(, , vars.protocolFeeRate, vars.maxProtocolFee, ) = params.primexDNS.getPrimexDNSParams(params.feeRateType);
// Calculate protocol fee in position asset
vars.feeInPaymentAsset = params.paymentAmount.wmul(vars.protocolFeeRate);
// Calculate max protocol fee in position asset
vars.maxProtocolFeeInPaymentAsset = vars.maxProtocolFee == type(uint256).max
? type(uint256).max
: getOracleAmountsOut(
NATIVE_CURRENCY,
params.paymentAsset,
vars.maxProtocolFee,
params.priceOracle,
params.nativePaymentAssetOracleData
);
// The minProtocolFee is applied only if the order/position is processed by Keepers
if (
params.feeRateType == IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByTrader ||
params.feeRateType == IPrimexDNSStorageV3.FeeRateType.SpotPositionClosedByTrader ||
params.feeRateType == IPrimexDNSStorageV3.FeeRateType.SwapMarketOrder
) {
vars.feeInPaymentAsset = min(vars.feeInPaymentAsset, vars.maxProtocolFeeInPaymentAsset);
} else {
vars.minProtocolFeeInPaymentAsset = minProtocolFee(
MinProtocolFeeParams({
restrictedGasSpent: params.gasSpent,
paymentAsset: params.paymentAsset,
priceOracle: params.priceOracle,
keeperRewardDistributor: IKeeperRewardDistributorV3(params.keeperRewardDistributor),
primexDNS: params.primexDNS,
isFeeProhibitedInPmx: params.isFeeProhibitedInPmx,
feeRateType: params.feeRateType,
nativePaymentAssetOracleData: params.nativePaymentAssetOracleData
})
);
_require(
vars.minProtocolFeeInPaymentAsset < params.paymentAmount,
Errors.MIN_PROTOCOL_FEE_IS_GREATER_THAN_PAYMENT_AMOUNT.selector
);
vars.feeInPaymentAsset = min(
max(vars.feeInPaymentAsset, vars.minProtocolFeeInPaymentAsset),
vars.maxProtocolFeeInPaymentAsset
);
}
return vars.feeInPaymentAsset;
}
function payProtocolFeeBatchClose(
ProtocolFeeParamsBatchClose calldata params
) public returns (uint256[] memory, uint256[] memory) {
ProtocolFeeVars memory vars;
uint256[] memory feeInPaymentAsset = new uint256[](params.numberOfPositions);
uint256[] memory feeInPmx = new uint256[](params.numberOfPositions);
(vars.pmx, vars.treasury, , , vars.pmxDiscountMultiplier) = params.primexDNS.getPrimexDNSParams(
params.feeRateType
);
feeInPaymentAsset = calculateFeeInPaymentAssetBatchClose(
params.numberOfPositions,
params.primexDNS,
params.priceOracle,
params.feeRateType,
params.paymentAsset,
params.paymentAmounts,
params.keeperRewardDistributor,
params.estimatedGasAmount,
params.estimatedBaseLength,
params.nativePaymentAssetOracleData
);
for (uint256 i; i < params.numberOfPositions; i++) {
// This is done to ensure that after upgrading the contracts, positions that have already been opened
// and had fees paid for them will not incur additional fees upon closure
if (params.feeTokens[i] == address(0)) {
feeInPaymentAsset[i] = 0;
feeInPmx[i] = 0;
continue;
}
(vars.pmxTraderBalance, ) = params.traderBalanceVault.balances(params.traders[i], vars.pmx);
if (!params.isFeeProhibitedInPmx && params.feeTokens[i] == vars.pmx && vars.pmxTraderBalance > 0) {
vars.pmxTraderBalanceInPaymentAsset = getOracleAmountsOut(
vars.pmx,
params.paymentAsset,
vars.pmxTraderBalance,
params.priceOracle,
params.pmxPaymentAssetOracleData
);
vars.feeInPaymentAssetWithDiscount = feeInPaymentAsset[i].wmul(vars.pmxDiscountMultiplier);
feeInPmx[i] =
(vars.feeInPaymentAssetWithDiscount * vars.pmxTraderBalance) /
vars.pmxTraderBalanceInPaymentAsset;
if (vars.pmxTraderBalanceInPaymentAsset >= vars.feeInPaymentAssetWithDiscount) {
feeInPaymentAsset[i] = 0;
params.traderBalanceVault.withdrawFrom(
params.traders[i],
vars.treasury,
vars.pmx,
feeInPmx[i],
false
);
} else {
feeInPmx[i] = vars.pmxTraderBalance;
feeInPaymentAsset[i] -= vars.pmxTraderBalanceInPaymentAsset.wdiv(vars.pmxDiscountMultiplier);
params.traderBalanceVault.withdrawFrom(
params.traders[i],
vars.treasury,
vars.pmx,
vars.pmxTraderBalance,
false
);
}
}
}
return (feeInPaymentAsset, feeInPmx);
}
/**
* @notice Calculate and return protocol fee
* @return The amount of the protocol fee in '_feeToken' which needs to be paid according to the specified deposit parameters.
*/
function calculateFeeInPaymentAssetBatchClose(
uint256 numberOfPositions,
IPrimexDNSV3 primexDNS,
address priceOracle,
IPrimexDNSStorageV3.FeeRateType feeRateType,
address paymentAsset,
uint256[] memory paymentAmounts,
address keeperRewardDistributor,
uint256 estimatedGasAmount,
uint256 estimatedBaseLength,
bytes calldata _nativePaymentAssetOracleData
) public returns (uint256[] memory) {
CalculateFeeInPaymentAssetBatchCloseVars memory vars;
(, , vars.protocolFeeRate, vars.maxProtocolFee, ) = primexDNS.getPrimexDNSParams(feeRateType);
// Calculate max protocol fee in payment (sold) asset
vars.maxProtocolFeeInPaymentAsset = vars.maxProtocolFee == type(uint256).max
? type(uint256).max
: getOracleAmountsOut(
NATIVE_CURRENCY,
paymentAsset,
vars.maxProtocolFee,
priceOracle,
_nativePaymentAssetOracleData
);
vars.minProtocolFeeInPaymentAsset = minProtocolFeeCloseBatch(
paymentAsset,
priceOracle,
IKeeperRewardDistributorV3(keeperRewardDistributor),
estimatedGasAmount,
estimatedBaseLength,
primexDNS,
_nativePaymentAssetOracleData
);
vars.feeInPaymentAsset = new uint256[](numberOfPositions);
// Calculate protocol fee in position asset
for (uint256 i; i < numberOfPositions; i++) {
vars.feeInPaymentAsset[i] = paymentAmounts[i].wmul(vars.protocolFeeRate);
_require(
vars.minProtocolFeeInPaymentAsset < paymentAmounts[i],
Errors.MIN_PROTOCOL_FEE_IS_GREATER_THAN_PAYMENT_AMOUNT.selector
);
vars.feeInPaymentAsset[i] = min(
max(vars.feeInPaymentAsset[i], vars.minProtocolFeeInPaymentAsset),
vars.maxProtocolFeeInPaymentAsset
);
}
return vars.feeInPaymentAsset;
}
/**
* @notice Calculate minProtocolFee based on the gas price
*/
function minProtocolFee(MinProtocolFeeParams memory params) public returns (uint256 minProtocolFeeInPositionAsset) {
MinProtocolFeeVars memory vars;
(vars.restrictedGasPrice) = calculateRestrictedGasPrice(params.priceOracle, params.keeperRewardDistributor);
if (
params.feeRateType == IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByKeeper ||
params.feeRateType == IPrimexDNSStorageV3.FeeRateType.SpotPositionClosedByKeeper
) {
vars.callingMethod = IPrimexDNSStorageV3.CallingMethod.ClosePositionByCondition;
} else {
vars.callingMethod = IPrimexDNSStorageV3.CallingMethod.OpenPositionByOrder;
}
(
vars.liquidationGasAmount,
vars.protocolFeeCoefficient,
vars.additionalGasSpent,
vars.maxGasAmount,
vars.baseLength
) = params.primexDNS.getParamsForMinProtocolFee(vars.callingMethod);
vars.l1CostWei = _calculateL1CostWei(vars.baseLength, params.keeperRewardDistributor);
if (params.isFeeProhibitedInPmx) {
vars.minProtocolFeeInNativeAsset =
vars.liquidationGasAmount *
vars.restrictedGasPrice +
vars.l1CostWei +
vars.protocolFeeCoefficient;
} else {
if (vars.callingMethod == IPrimexDNSStorageV3.CallingMethod.ClosePositionByCondition) {
vars.minProtocolFeeInNativeAsset =
vars.maxGasAmount *
vars.restrictedGasPrice +
vars.l1CostWei +
vars.protocolFeeCoefficient;
} else {
vars.totalGasSpent = params.restrictedGasSpent + vars.additionalGasSpent;
vars.totalGasSpent = min(vars.totalGasSpent, vars.maxGasAmount);
vars.minProtocolFeeInNativeAsset =
vars.totalGasSpent *
vars.restrictedGasPrice +
vars.l1CostWei +
vars.protocolFeeCoefficient;
}
}
minProtocolFeeInPositionAsset = getOracleAmountsOut(
NATIVE_CURRENCY,
params.paymentAsset,
vars.minProtocolFeeInNativeAsset,
params.priceOracle,
params.nativePaymentAssetOracleData
);
}
/**
* @notice Calculate minProtocolFee based on the gas price in closeBatchPositions
*/
function minProtocolFeeCloseBatch(
address _paymentAsset,
address _priceOracle,
IKeeperRewardDistributorV3 _keeperRewardDistributor,
uint256 _estimatedGasAmount,
uint256 _estimatedBaseLength,
IPrimexDNSV3 primexDNS,
bytes calldata _nativePaymentAssetOracleData
) public returns (uint256 minProtocolFeeInPositionAsset) {
uint256 restrictedGasPrice = calculateRestrictedGasPrice(_priceOracle, _keeperRewardDistributor);
uint256 l1CostWei = _calculateL1CostWei(_estimatedBaseLength, _keeperRewardDistributor);
uint256 minProtocolFeeInNativeAsset = _estimatedGasAmount *
restrictedGasPrice +
l1CostWei +
primexDNS.protocolFeeCoefficient();
minProtocolFeeInPositionAsset = getOracleAmountsOut(
NATIVE_CURRENCY,
_paymentAsset,
minProtocolFeeInNativeAsset,
_priceOracle,
_nativePaymentAssetOracleData
);
}
/**
* @notice Calculate minPositionSize based on the gas price
*/
function minPositionSize(
address _priceOracle,
IKeeperRewardDistributorV3 _keeperRewardDistributor,
IPrimexDNSV3 _primexDNS,
IPrimexDNSStorageV3.TradingOrderType _tradingOrderType
) public view returns (uint256 minPositionSizeInNativeAsset) {
uint256 restrictedGasPrice = calculateRestrictedGasPrice(_priceOracle, _keeperRewardDistributor);
(
uint256 baseLength,
uint256 averageGasPerAction,
uint256 protocolFeeCoefficient,
uint256 gasPriceBuffer
) = _primexDNS.getParamsForMinPositionSize(_tradingOrderType);
uint256 l1CostWei = _calculateL1CostWei(baseLength, _keeperRewardDistributor);
minPositionSizeInNativeAsset = (averageGasPerAction * restrictedGasPrice + l1CostWei + protocolFeeCoefficient)
.wmul(gasPriceBuffer);
}
function calculateRestrictedGasPrice(
address _priceOracle,
IKeeperRewardDistributorV3 _keeperRewardDistributor
) internal view returns (uint256 restrictedGasPrice) {
RestrictedGasPriceVars memory vars;
restrictedGasPrice = tx.gasprice;
vars.oracleGasPrice = IPriceOracle(_priceOracle).getGasPrice();
(vars.oracleGasPriceTolerance, vars.defaultMaxGasPrice, , ) = _keeperRewardDistributor
.getGasCalculationParams();
vars.maxGasPrice = vars.oracleGasPrice > 0
? uint256(vars.oracleGasPrice).wmul(WadRayMath.WAD + vars.oracleGasPriceTolerance)
: vars.defaultMaxGasPrice;
if (restrictedGasPrice > vars.maxGasPrice || restrictedGasPrice == 0) {
restrictedGasPrice = vars.maxGasPrice;
}
}
function getOracleAmountsOut(
address _tokenA,
address _tokenB,
uint256 _amountAssetA,
address _priceOracle,
bytes memory _oracleData
) public returns (uint256) {
_require(
IERC165(_priceOracle).supportsInterface(type(IPriceOracleV2).interfaceId),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
if (_tokenA == _tokenB) {
return _amountAssetA;
}
uint256 exchangeRate = IPriceOracleV2(_priceOracle).getExchangeRate(_tokenA, _tokenB, _oracleData);
return (_amountAssetA * _getAssetMultiplier(_tokenA)).wmul(exchangeRate) / _getAssetMultiplier(_tokenB);
}
/**
* @param _tokenA asset for sell
* @param _tokenB asset to buy
* @param _amountsAssetA An array of amounts of tokenA to sell
* @param _priceOracle PriceOracle contract address
* @return returns an array of amounts of `tokenB` by the `amountsAssetA` by the price of the oracle
*/
function getBatchOracleAmountsOut(
address _tokenA,
address _tokenB,
uint256[] memory _amountsAssetA,
address _priceOracle,
bytes calldata _oracleData
) public returns (uint256[] memory) {
_require(
IERC165(_priceOracle).supportsInterface(type(IPriceOracleV2).interfaceId),
Errors.ADDRESS_NOT_SUPPORTED.selector
);
if (_tokenA == _tokenB) {
return _amountsAssetA;
}
uint256[] memory amountsAssetB = new uint256[](_amountsAssetA.length);
uint256 exchangeRate = IPriceOracleV2(_priceOracle).getExchangeRate(_tokenA, _tokenB, _oracleData);
uint256 multiplier1 = 10 ** (18 - IERC20Metadata(_tokenA).decimals());
uint256 multiplier2 = 10 ** (18 - IERC20Metadata(_tokenB).decimals());
for (uint256 i; i < _amountsAssetA.length; i++) {
amountsAssetB[i] = (_amountsAssetA[i] * multiplier1).wmul(exchangeRate) / multiplier2;
}
return amountsAssetB;
}
/**
* @notice Calculates the liquidation price for a position.
* @dev liquidationPrice = (feeBuffer * debt) /
* ((1 - securityBuffer) * (1 - oracleTolerableLimit) * (1 - priceDrop) * positionAmount))
* @param _bucket The address of the related bucket.
* @param _positionAsset The address of the position asset.
* @param _positionAmount The size of the opened position.
* @param _positionDebt The debt amount in debtTokens associated with the position.
* @return The calculated liquidation price in borrowed asset.
*/
function getLiquidationPrice(
address _bucket,
address _positionAsset,
uint256 _positionAmount,
uint256 _positionDebt,
address _primexDNS
) public view returns (uint256) {
_require(_positionAsset != address(0), Errors.ADDRESS_NOT_SUPPORTED.selector);
LiquidationPriceData memory data;
data.bucket = IBucketV3(_bucket);
data.positionManager = data.bucket.positionManager();
data.borrowedAsset = data.bucket.borrowedAsset();
data.priceOracle = data.positionManager.priceOracle();
uint256 multiplier1 = 10 ** (18 - data.borrowedAsset.decimals());
uint256 denominator = (WadRayMath.WAD - data.positionManager.securityBuffer())
.wmul(
WadRayMath.WAD -
data.positionManager.getOracleTolerableLimit(_positionAsset, address(data.borrowedAsset))
)
.wmul(WadRayMath.WAD - data.priceOracle.getPairPriceDrop(_positionAsset, address(data.borrowedAsset)))
.wmul(_positionAmount)
.wmul(
WadRayMath.WAD -
IPrimexDNSV3(_primexDNS).protocolFeeRates(
IPrimexDNSStorageV3.FeeRateType.MarginPositionClosedByKeeper
)
) * 10 ** (18 - IERC20Metadata(_positionAsset).decimals());
// numerator = data.bucket.feeBuffer().wmul(_positionDebt) * multiplier1;
return (data.bucket.feeBuffer().wmul(_positionDebt) * multiplier1).wdiv(denominator) / multiplier1;
}
/**
* @notice Validates if a position meets the minimum size requirement.
* @param _amount The amount of the asset in the position.
* @param _asset The asset associated with the position.
* @param _priceOracle The address of the price oracle contract.
* @param _nativeAssetOracleData NativeCurrency => Asset
*/
function validateMinPositionSize(
uint256 _amount,
address _asset,
address _priceOracle,
IKeeperRewardDistributorV3 _keeperRewardDistributor,
IPrimexDNSV3 _primexDNS,
IPrimexDNSStorageV3.TradingOrderType _tradingOrderType,
bytes calldata _nativeAssetOracleData
) public {
_require(
isGreaterThanMinPositionSize(
_asset,
_amount,
_priceOracle,
_keeperRewardDistributor,
_primexDNS,
_tradingOrderType,
_nativeAssetOracleData
),
Errors.INSUFFICIENT_POSITION_SIZE.selector
);
}
/**
* @notice Checks if the given amount of _asset corresponds to the minimum position size _minPositionSize,
* based on the _minPositionAsset and the provided _priceOracle.
* Returns true if the amount corresponds to or exceeds the minimum position size, otherwise returns false.
* @param _asset The address of the asset being checked.
* @param _amount The amount of _asset being checked.
* @param _priceOracle The address of the price oracle contract.
* @return A boolean value indicating whether the amount corresponds to or exceeds the minimum position size.
*/
function isGreaterThanMinPositionSize(
address _asset,
uint256 _amount,
address _priceOracle,
IKeeperRewardDistributorV3 _keeperRewardDistributor,
IPrimexDNSV3 _primexDNS,
IPrimexDNSStorageV3.TradingOrderType _tradingOrderType,
bytes calldata _nativeAssetOracleData
) public returns (bool) {
uint256 minPositionSizeInNativeCurrency = minPositionSize(
_priceOracle,
_keeperRewardDistributor,
_primexDNS,
_tradingOrderType
);
uint256 minPositionSizeInAsset = getOracleAmountsOut(
NATIVE_CURRENCY,
_asset,
minPositionSizeInNativeCurrency,
_priceOracle,
_nativeAssetOracleData
);
return _amount >= minPositionSizeInAsset;
}
/**
* @notice Decodes an encoded path and returns an array of addresses.
* @param encodedPath The encoded path to be decoded.
* @param dexRouter The address of the DEX router.
* @param dexAdapter The address of the DEX adapter.
* @return path An array of addresses representing the decoded path.
*/
function decodePath(
bytes memory encodedPath,
address dexRouter,
address payable dexAdapter
) public view returns (address[] memory path) {
IDexAdapter.DexType type_ = IDexAdapter(dexAdapter).dexType(dexRouter);
if (type_ == IDexAdapter.DexType.UniswapV2 || type_ == IDexAdapter.DexType.Meshswap) {
path = abi.decode(encodedPath, (address[]));
} else if (type_ == IDexAdapter.DexType.UniswapV3) {
uint256 skip;
uint256 offsetSize = 23; // address size(20) + fee size(3)
uint256 pathLength = encodedPath.length / offsetSize + 1;
path = new address[](pathLength);
for (uint256 i; i < pathLength; i++) {
path[i] = encodedPath.toAddress(skip, encodedPath.length);
skip += offsetSize;
}
} else if (type_ == IDexAdapter.DexType.Curve) {
(path, ) = abi.decode(encodedPath, (address[], address[]));
} else if (type_ == IDexAdapter.DexType.Balancer) {
(path, , ) = abi.decode(encodedPath, (address[], bytes32[], int256[]));
} else if (type_ == IDexAdapter.DexType.AlgebraV3) {
uint256 skip;
uint256 offsetSize = 20; // address size(20)
uint256 pathLength = encodedPath.length / offsetSize;
path = new address[](pathLength);
for (uint256 i; i < pathLength; i++) {
path[i] = encodedPath.toAddress(skip, encodedPath.length);
skip += offsetSize;
}
} else {
_revert(Errors.UNKNOWN_DEX_TYPE.selector);
}
}
/**
* @notice Returns the asset multiplier for a given asset.
* @dev If the asset is the native currency, the function returns 1.
* If the asset is USD, the function returns the value stored in the constant USD_MULTIPLIER.
* For any other asset, the function calculates the multiplier based on the number of decimals of the token.
* @param _asset The address of the asset.
* @return The asset multiplier. It is a number with 10 raised to a power of decimals of a given asset.
*/
function _getAssetMultiplier(address _asset) internal view returns (uint256) {
if (_asset == NATIVE_CURRENCY) return 1;
if (_asset == USD) return USD_MULTIPLIER;
return 10 ** (18 - IERC20Metadata(_asset).decimals());
}
function _calculateL1CostWei(
uint256 _baseLength,
IKeeperRewardDistributorV3 _keeperRewardDistributor
) internal view returns (uint256 l1CostWei) {
(
,
,
uint256 optimisticGasCoefficient,
IKeeperRewardDistributorStorage.PaymentModel paymentModel
) = _keeperRewardDistributor.getGasCalculationParams();
if (paymentModel == IKeeperRewardDistributorStorage.PaymentModel.ARBITRUM) {
return
l1CostWei =
ARB_NITRO_ORACLE.getL1BaseFeeEstimate() *
GAS_FOR_BYTE *
(_baseLength + TRANSACTION_METADATA_BYTES);
}
if (paymentModel == IKeeperRewardDistributorStorage.PaymentModel.OPTIMISTIC) {
// Adds 68 bytes of padding to account for the fact that the input does not have a signature.
uint256 l1GasUsed = GAS_FOR_BYTE * (_baseLength + OVM_GASPRICEORACLE.overhead() + 68);
return
l1CostWei =
(OVM_GASPRICEORACLE.l1BaseFee() *
l1GasUsed *
OVM_GASPRICEORACLE.scalar() *
optimisticGasCoefficient) /
10 ** 6;
}
return 0;
}
/**
* @notice Utility function to get the minimum of two values
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @notice Utility function to get the maximum of two values
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
}// Copyright 2020 Compound Labs, Inc.
// (c) 2024 Primex.finance
// SPDX-License-Identifier: BSD-3-Clause
// Modified version of token transfer logic that allows working with non-standart ERC-20 tokens, added method doTransferFromTo,
// modified doTransferIn
pragma solidity 0.8.26;
import "./Errors.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {EIP20NonStandardInterface} from "../interfaces/EIP20NonStandardInterface.sol";
library TokenTransfersLibrary {
function doTransferIn(address token, address from, uint256 amount) public returns (uint256) {
return doTransferFromTo(token, from, address(this), amount);
}
function doTransferFromTo(address token, address from, address to, uint256 amount) public returns (uint256) {
uint256 balanceBefore = IERC20(token).balanceOf(to);
// The returned value is checked in the assembly code below.
// Arbitrary `from` should be checked at a higher level. The library function cannot be called by the user.
// slither-disable-next-line unchecked-transfer arbitrary-send-erc20
EIP20NonStandardInterface(token).transferFrom(from, to, amount);
bool success;
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
switch returndatasize()
case 0 {
// This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 {
// This is a compliant ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of external call
}
default {
// This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
_require(success, Errors.TOKEN_TRANSFER_IN_FAILED.selector);
// Calculate the amount that was *actually* transferred
uint256 balanceAfter = IERC20(token).balanceOf(to);
_require(balanceAfter >= balanceBefore, Errors.TOKEN_TRANSFER_IN_OVERFLOW.selector);
return balanceAfter - balanceBefore; // underflow already checked above, just subtract
}
function doTransferOut(address token, address to, uint256 amount) public {
// The returned value is checked in the assembly code below.
// slither-disable-next-line unchecked-transfer
EIP20NonStandardInterface(token).transfer(to, amount);
bool success;
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
switch returndatasize()
case 0 {
// This is a non-standard ERC-20
success := not(0) // set success to true
}
case 32 {
// This is a complaint ERC-20
returndatacopy(0, 0, 32)
success := mload(0) // Set `success = returndata` of external call
}
default {
// This is an excessively non-compliant ERC-20, revert.
revert(0, 0)
}
}
_require(success, Errors.TOKEN_TRANSFER_OUT_FAILED.selector);
}
function doTransferOutETH(address to, uint256 value) internal {
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = to.call{value: value}(new bytes(0));
_require(success, Errors.NATIVE_TOKEN_TRANSFER_FAILED.selector);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// A modified version of BytesLib
// Origin: https://github.com/1inch/universal-router/blob/b972662f8d3f0ba55ef99411720f613f77c3fab5/contracts/modules/uniswap/v3/BytesLib.sol
// Unused methods and constants were removed
pragma solidity 0.8.26;
library BytesLib {
error ToAddressOverflow();
error ToAddressOutOfBounds();
/// @notice Returns the address starting at byte `_start`
/// @dev _bytesLength must equal _bytes.length for this to function correctly
/// @param _bytes The input bytes string to slice
/// @param _start The starting index of the address
/// @param _bytesLength The length of _bytes
/// @return tempAddress The address starting at _start
function toAddress(
bytes memory _bytes,
uint256 _start,
uint256 _bytesLength
) internal pure returns (address tempAddress) {
unchecked {
if (_start + 20 < _start) revert ToAddressOverflow();
if (_bytesLength < _start + 20) revert ToAddressOutOfBounds();
}
assembly {
tempAddress := mload(add(add(_bytes, 0x14), _start))
}
}
}// SPDX-License-Identifier: GPL-3.0
// A modified version of ds-math library
// Origin: https://github.com/dapphub/ds-math/blob/master/src/math.sol
// Unused methods were removed, errors changed
pragma solidity 0.8.26;
error DS_MATH_ADD_OVERFLOW();
error DS_MATH_MUL_OVERFLOW();
library WadRayMath {
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
if ((z = x + y) < x) revert DS_MATH_ADD_OVERFLOW();
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
if (!(y == 0 || (z = x * y) / y == x)) revert DS_MATH_MUL_OVERFLOW();
}
uint256 internal constant WAD = 10 ** 18;
uint256 internal constant RAY = 10 ** 27;
//rounds to zero if x*y < WAD / 2
function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), WAD / 2) / WAD;
}
//rounds to zero if x*y < RAY / 2
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, y), RAY / 2) / RAY;
}
//rounds to zero if x*y < WAD / 2
function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, WAD), y / 2) / y;
}
//rounds to zero if x*y < RAY / 2
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = add(mul(x, RAY), y / 2) / y;
}
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {ILimitOrderManagerStorage} from "./ILimitOrderManagerStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface ILimitOrderManager is ILimitOrderManagerStorage, IPausable {
enum LimitOrderType {
Margin,
Spot,
Swap
}
struct UpdateOrderConditionsParams {
uint256 orderId;
LimitOrderLibrary.Condition[] openConditions;
LimitOrderLibrary.Condition[] closeConditions;
}
event CreateLimitOrder(
uint256 indexed orderId,
address indexed trader,
LimitOrderLibrary.LimitOrder order,
LimitOrderLibrary.Condition[] openConditions,
LimitOrderLibrary.Condition[] closeConditions
);
event CloseLimitOrder(
uint256 indexed orderId,
address indexed trader,
address indexed closedBy,
LimitOrderLibrary.CloseReason reason,
uint256 positionId,
// TODO: can delete args below when front be ready for it
string bucket,
address borrowedAsset,
address positionAsset,
uint256 leverage,
address depositAsset,
uint256 depositAmount
);
event UpdateOrder(
uint256 indexed orderId,
address indexed trader,
uint256 depositAmount,
uint256 leverage,
address feeToken
);
event UpdateOrderConditions(
uint256 indexed orderId,
address indexed trader,
LimitOrderLibrary.Condition[] openConditions,
LimitOrderLibrary.Condition[] closeConditions
);
/**
* @notice Initializes the LimitOrderManager contract.
* @param _registry The address of the Registry contract.
* @param _primexDNS The address of the PrimexDNS contract.
* @param _pm The address of the PositionManager contract.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _swapManager The address of the SwapManager contract.
* @param _whiteBlackList The address of the WhiteBlacklist contract.
*/
function initialize(
address _registry,
address _primexDNS,
address _pm,
address payable _traderBalanceVault,
address _swapManager,
address _whiteBlackList
) external;
/**
* @notice Creates a limit order.
* @dev This function allows users to create a limit order and locks the deposit asset in the traderBalanceVault
* @param _params The parameters necessary to create limit order
*/
function createLimitOrder(LimitOrderLibrary.CreateLimitOrderParams calldata _params) external payable;
/**
* @notice Cancels the order. Can only be called by the trader
* @param _orderId order id
*/
function cancelLimitOrder(uint256 _orderId) external;
/**
* @notice Removes expired limit orders
* @param _orderIds The array of order IDs to remove.
*/
function cancelExpiredLimitOrders(uint256[] calldata _orderIds) external;
/**
* @notice Opens a position by an existing order.
* @dev This function is called to open a position based on the given order parameters.
* @param _params The OpenPositionParams struct containing the necessary parameters for opening the position.
*/
function openPositionByOrder(LimitOrderLibrary.OpenPositionParams calldata _params) external payable;
/**
* @notice Updates an existing limit order.
* @dev Edits prices on an existing order
* @param _params The parameters for updating the limit order.
*/
function updateOrder(LimitOrderLibrary.UpdateLimitOrderParams calldata _params) external payable;
/**
* @notice Updates the open and close conditions of an order.
* @dev Only the trader of the order can update the conditions.
* @param _params The parameters for updating the order conditions.
*/
function updateOrderConditions(UpdateOrderConditionsParams memory _params) external;
/**
* @notice Function to set new swapManager.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _swapManager Address of the new swapManager.
*/
function setSwapManager(address _swapManager) external;
/**
* @notice Retrieves the details of a limit order based on its ID.
* @param _id The ID of the limit order to retrieve.
* @return The LimitOrder struct representing the limit order.
*/
function getOrder(uint256 _id) external view returns (LimitOrderLibrary.LimitOrder memory);
/**
* @notice Retrieves the limit order at the specified index.
* @param _index The index of the limit order to retrieve.
* @return The limit order at the specified index.
*/
function getOrderByIndex(uint256 _index) external view returns (LimitOrderLibrary.LimitOrder memory);
/**
* @notice Retrieves the close conditions associated with the given order ID.
* @param _orderId The ID of the order.
* @return An array of Condition representing the close conditions.
*/
function getCloseConditions(uint256 _orderId) external view returns (LimitOrderLibrary.Condition[] memory);
/**
* @notice Retrieves the open conditions associated with a given order ID.
* @param _orderId The ID of the order.
* @return An array of Condition structs representing the open conditions.
*/
function getOpenConditions(uint256 _orderId) external view returns (LimitOrderLibrary.Condition[] memory);
/**
* @notice Returns the length of the orders array.
* @return The number of orders in the array.
*/
function getOrdersLength() external view returns (uint256);
/**
* @notice Returns the length of the order array for a specific trader.
* @param _trader The address of the trader.
* @return The length of the order array.
*/
function getTraderOrdersLength(address _trader) external view returns (uint256);
/**
* @notice Returns an array of LimitOrder structures representing the orders placed by a specific trader.
* @param _trader The address of the trader.
* @return traderOrders An array of LimitOrder structures representing the orders placed by the trader.
*/
function getTraderOrders(address _trader) external view returns (LimitOrderLibrary.LimitOrder[] memory);
/**
* @notice Returns the length of orders in a bucket.
* @param _bucket The address of the bucket.
* @return The number of orders in the bucket.
*/
function getBucketOrdersLength(address _bucket) external view returns (uint256);
/**
* @notice Retrieves all limit orders associated with a given bucket.
* @param _bucket The address of the bucket.
* @return An array of LimitOrder structs representing the bucket's orders.
*/
function getBucketOrders(address _bucket) external view returns (LimitOrderLibrary.LimitOrder[] memory);
}
interface ILimitOrderManagerV2 is ILimitOrderManager {
event ChangeSwapManager(address swapManager);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {IPositionManagerV2} from "../PositionManager/IPositionManager.sol";
import {ISwapManager} from "../SwapManager/ISwapManager.sol";
interface ILimitOrderManagerStorage {
function ordersId() external view returns (uint256);
function orderIndexes(uint256) external view returns (uint256);
function traderOrderIndexes(uint256) external view returns (uint256);
function traderOrderIds(address _trader, uint256 _index) external view returns (uint256);
function bucketOrderIndexes(uint256) external view returns (uint256);
function bucketOrderIds(address _bucket, uint256 _index) external view returns (uint256);
function registry() external view returns (IAccessControl);
function traderBalanceVault() external view returns (ITraderBalanceVault);
function primexDNS() external view returns (IPrimexDNSV3);
function pm() external view returns (IPositionManagerV2);
function swapManager() external view returns (ISwapManager);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {IWhiteBlackList} from "../WhiteBlackList/WhiteBlackList/IWhiteBlackList.sol";
import {ILiquidityMiningRewardDistributorStorage} from "./ILiquidityMiningRewardDistributorStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface ILiquidityMiningRewardDistributor is ILiquidityMiningRewardDistributorStorage, IPausable {
struct RewardsInPMX {
uint256 minReward;
uint256 maxReward;
uint256 extraReward;
}
/**
* @notice Emitted when a reward is claimed by a receiver from a specific bucket.
* @param receiver The address of the receiver.
* @param bucket The address of the bucket from which the reward is claimed.
* @param amount The amount of the claimed reward.
*/
event ClaimedReward(address indexed receiver, address indexed bucket, uint256 amount);
/**
* @notice Emitted when PMX tokens are withdrawn by an admin.
* @param amount The amount of PMX tokens withdrawn.
*/
event WithdrawPmxByAdmin(uint256 indexed amount);
/**
* @notice Initializes the contract with the specified parameters.
* @param _primexDNS The address of the IPrimexDNS contract.
* @param _pmx The address of the PMX token contract.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _registry The address of the registry contract.
* @param _treasury The address of the treasury contract.
* @param _reinvestmentRate The rate at which rewards are reinvested.
* @param _reinvestmentDuration The duration for which rewards are reinvested.
* @param _whiteBlackList The address of the WhiteBlackList contract.
*/
function initialize(
IPrimexDNSV3 _primexDNS,
IERC20 _pmx,
ITraderBalanceVault _traderBalanceVault,
address _registry,
address _treasury,
uint256 _reinvestmentRate,
uint256 _reinvestmentDuration,
IWhiteBlackList _whiteBlackList
) external;
/**
* @notice Updates the reward amount for a specific bucket.
* @dev Only callable by the PrimexDNS contract.
* @param _bucketName The name of the bucket.
* @param _pmxRewardsAmount The amount of PMX rewards to be allocated to the bucket.
*/
function updateBucketReward(string memory _bucketName, uint256 _pmxRewardsAmount) external;
/**
* @notice Adds points for a user for future reward distribution.
* @dev Only callable by the Bucket contract.
* @param _bucketName The name of the bucket.
* @param _user The address of the user.
* @param _miningAmount The amount of mining points to be added.
* @param _maxStabilizationPeriodEnd The maximum end timestamp of the stabilization period.
* @param _maxPeriodTime The maximum period time.
* @param _currentTimestamp The current timestamp.
*/
function addPoints(
string memory _bucketName,
address _user,
uint256 _miningAmount,
uint256 _maxStabilizationPeriodEnd,
uint256 _maxPeriodTime,
uint256 _currentTimestamp
) external;
/**
* @notice Removes points for a user.
* @dev Only callable by the Bucket contract.
* @param _name The name of the bucket.
* @param _user The address of the user.
* @param _amount The amount of mining points to be removed.
*/
function removePoints(string memory _name, address _user, uint256 _amount) external;
/**
* @notice Claims the accumulated rewards for a specific bucket.
* @param _bucketName The name of the bucket.
*/
function claimReward(string memory _bucketName) external;
/**
* @notice Moves rewards from one bucket to another.
* @dev Only callable by the Bucket contract.
* @param _bucketFrom The name of the source bucket.
* @param _bucketTo The name of the destination bucket.
* @param _user The address of the user.
* @param _isBucketLaunched A flag indicating if the destination bucket is launched.
* @param _liquidityMiningDeadline The deadline for liquidity mining
*/
function reinvest(
string memory _bucketFrom,
string memory _bucketTo,
address _user,
bool _isBucketLaunched,
uint256 _liquidityMiningDeadline
) external;
/**
* @dev The function to withdraw PMX from a delisted bucket or a bucket where liquidity mining failed (after reinvesting period).
* Emits WithdrawPmxByAdmin event.
* @param _bucketFrom Name of the bucket with failed liquidity mining event.
*/
function withdrawPmxByAdmin(string memory _bucketFrom) external;
/**
* @notice Retrieves information about a lender in a specific bucket.
* @param _bucketName The name of the bucket.
* @param _lender The address of the lender.
* @param _timestamp The timestamp for which the information is queried.
* @return amountInMining The amount of tokens the lender has in mining for the given bucket.
* @return currentPercent The current percentage of rewards the lender is eligible to receive for the given bucket.
* Measured in WAD (1 WAD = 100%).
* @return rewardsInPMX An object containing information about the lender's rewards in PMX for the given bucket.
*/
function getLenderInfo(
string calldata _bucketName,
address _lender,
uint256 _timestamp
) external view returns (uint256 amountInMining, uint256 currentPercent, RewardsInPMX memory rewardsInPMX);
/**
* @notice Retrieves rewards information about a specific bucket.
* @param _bucketName The name of the bucket.
* @return totalPmxReward The total amount of PMX reward in the bucket.
* @return withdrawnRewards The total amount of withdrawn rewards from the bucket.
* @return totalPoints The total number of mining points in the bucket.
*/
function getBucketInfo(
string calldata _bucketName
) external view returns (uint256 totalPmxReward, uint256 withdrawnRewards, uint256 totalPoints);
/**
* @notice Retrieves the amount of tokens a lender has in mining for a specific bucket.
* @param _bucket The name of the bucket.
* @param _lender The address of the lender.
* @return The amount of tokens the lender has in mining for the given bucket.
*/
function getLenderAmountInMining(string calldata _bucket, address _lender) external view returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
interface ILiquidityMiningRewardDistributorStorage {
struct LenderInfo {
uint256 points;
uint256 depositedAmount;
}
struct BucketInfo {
uint256 totalPoints;
uint256 totalPmxReward;
uint256 withdrawnRewards;
mapping(address => LenderInfo) lendersInfo;
}
function primexDNS() external view returns (IPrimexDNSV3);
function pmx() external view returns (IERC20);
function traderBalanceVault() external view returns (ITraderBalanceVault);
function registry() external view returns (address);
function reinvestmentRate() external view returns (uint256);
function reinvestmentDuration() external view returns (uint256);
function extraRewards(address, string calldata) external view returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
import {IPositionManagerStorage, IPositionManagerStorageV2, IKeeperRewardDistributorV3} from "./IPositionManagerStorage.sol";
import {IPositionManagerEvents} from "./IPositionManagerEvents.sol";
import {IPrimexDNSStorageV3} from "../PrimexDNS/IPrimexDNSStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface IPositionManagerV2 is IPositionManagerStorageV2, IPositionManagerStorage, IPositionManagerEvents, IPausable {
struct ClosePositionVars {
PositionLibrary.Position position;
bool borrowedAmountIsNotZero;
uint256 oracleTolerableLimit;
bool needOracleTolerableLimitCheck;
}
event ChangePositionManagerExtension(address indexed newPositionManagerExtension);
event IncreaseDeposit(
uint256 indexed positionId,
address indexed trader,
uint256 depositDelta,
uint256 scaledDebtAmount
);
struct ClosePositionByConditionParams {
uint256 id;
address keeper;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
uint256 conditionIndex;
bytes ccmAdditionalParams;
PositionLibrary.CloseReason closeReason;
bytes positionSoldAssetOracleData;
bytes nativePmxOracleData;
bytes positionNativeAssetOracleData;
bytes pmxSoldAssetOracleData;
bytes nativeSoldAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
/**
* @notice Initializes the contract with the specified addresses and initializes inherited contracts.
* @param _registry The address of the Registry contract.
* @param _primexDNS The address of the PrimexDNS contract.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _priceOracle The address of the PriceOracle contract.
* @param _keeperRewardDistributor The address of the KeeperRewardDistributor contract.
* @param _whiteBlackList The address of the WhiteBlacklist contract.
* @param _positionManagerExtension The address of the PositionManagerExtension contract.
*/
function initialize(
address _registry,
address _primexDNS,
address payable _traderBalanceVault,
address _priceOracle,
address _keeperRewardDistributor,
address _whiteBlackList,
address _positionManagerExtension
) external;
/**
* @notice Sets the positionManagerExtension.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _newPositionManagerExtension The address of PositionManagerExtension contract.
*/
function setPositionManagerExtension(address _newPositionManagerExtension) external;
/**
* @notice Sets protocol parameters through an administrative delegatecall.
* @dev This function allows an admin to update protocol parameters using a delegatecall to the PositionManagerExtension contract.
* @param _data The data containing the encoded function call to be executed by the delegatecall.
*/
function setProtocolParamsByAdmin(bytes calldata _data) external;
/**
* @notice Opens a position based on the provided order parameters.
* @dev Only callable by the LOM_ROLE role.
* @param _params The parameters for opening a position.
* @return The total borrowed amount, position amount, position ID, and entry price of the new position.
*/
function openPositionByOrder(
LimitOrderLibrary.OpenPositionByOrderParams calldata _params
) external returns (uint256, uint256, uint256, uint256, uint256);
/**
* @notice Opens margin position.
* @dev Locks trader's collateral in TraderBalanceVault. Takes loan from bucket for deal.
* Makes swap bucket borrowedAsset amount on '_dex'. Updates rates and indexes in the '_bucket'.
* Mints debtToken for trader (msg.sender)
* @param _params The parameters required to open a position.
*/
function openPosition(PositionLibrary.OpenPositionParams calldata _params) external payable;
/**
* @notice Close trader's active position or liquidate risky position.
* @dev Protocol will fall down (revert) if two conditions occur both:
* 1. (token1Price + position.depositedAmount).wdiv(positionDebt) will become lower than 1,
* so position will make loss for Protocol.
* 2. Not enough liquidity in bucket to pay that loss.
* @param _id Position id for `msg.sender`.
* @param _dealReceiver The receiver of the rest of trader's deposit.
* @param _megaRoutes swap routes on dexes
* @param _amountOutMin minimum allowed amount out for position
*/
function closePosition(
uint256 _id,
address _dealReceiver,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin,
bytes calldata _positionSoldAssetOracleData,
bytes calldata _pmxSoldAssetOracleData,
bytes calldata _nativeSoldAssetOracleData,
bytes[][] calldata _pullOracleData,
uint256[] calldata _pullOracleTypes
) external payable;
// /**
// * @notice Closes trader's active position by closing condition
// * @param _id Position id.
// * @param _keeper The address of the keeper or the recipient of the reward.
// * @param _megaRoutes An array of routes for executing trades, swap routes on dexes.
// * @param _conditionIndex The index of the condition to be used for closing the position.
// * @param _ccmAdditionalParams Additional params needed for canBeClosedAfterSwap of the ConditionalClosingManager.
// * @param _closeReason The reason for closing the position.
// */
function closePositionByCondition(ClosePositionByConditionParams calldata _params) external payable;
/**
* @notice Updates the position with the given position ID by setting new close conditions.
* @param _positionId The ID of the position to update.
* @param _closeConditions An array of close conditions for the position.
* @dev The caller of this function must be the trader who owns the position.
* @dev Emits an `UpdatePositionConditions` event upon successful update.
*/
function updatePositionConditions(
uint256 _positionId,
LimitOrderLibrary.Condition[] calldata _closeConditions
) external;
/**
* @notice Increases the deposit amount for a given position.
* @param _positionId The ID of the position to increase the deposit for.
* @param _amount The amount to increase the deposit by.
* @param _asset The address of the asset to deposit.
* @param _takeDepositFromWallet A flag indicating whether to make the deposit immediately.
* @param _megaRoutes An array of routes to use for trading.
* @param _amountOutMin The minimum amount of the output asset to receive from trading.
*/
function increaseDeposit(
uint256 _positionId,
uint256 _amount,
address _asset,
bool _takeDepositFromWallet,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin
) external;
/**
* @notice Decreases the deposit amount for a given position.
* @param _positionId The ID of the position.
* @param _amount The amount to decrease the deposit by.
*/
function decreaseDeposit(
uint256 _positionId,
uint256 _amount,
bytes calldata _positionSoldAssetOracleData,
bytes calldata _nativeSoldAssetOracleData,
bytes[][] calldata _pullOracleData,
uint256[] calldata _pullOracleTypes
) external payable;
/**
* @notice Deletes a positions by their IDs from a specific bucket for a given traders.
* @param _ids The IDs of the positions to be deleted.
* @param _traders The addresses of the traders who owns the position.
* @param _length The length of the traders array.
* @param _bucket The address of the bucket from which the position is to be deleted.
*/
function deletePositions(
uint256[] calldata _ids,
address[] calldata _traders,
uint256 _length,
address _bucket
) external;
/**
* @notice Allows the trader to partially close a position.
* @param _positionId The ID of the position to be partially closed.
* @param _amount The amount of the position asset to be closed from the position.
* @param _depositReceiver The address where the remaining deposit will be sent.
* @param _megaRoutes The routing information for swapping assets.
* @param _amountOutMin The minimum amount to be received after swapping, measured in the same decimal format as the position's asset.
*/
function partiallyClosePosition(
uint256 _positionId,
uint256 _amount,
address _depositReceiver,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin,
bytes calldata _positionSoldAssetOracleData,
bytes calldata _nativePositionAssetOracleData,
bytes calldata _nativeSoldAssetOracleData,
bytes calldata _pmxSoldAssetOracleData,
bytes[][] calldata _pullOracleData,
uint256[] calldata _pullOracleTypes
) external payable;
/**
* @notice Transfers a specified amount of tokens from the contract to a specified address.
* @dev Only callable by the BATCH_MANAGER_ROLE role.
* @param _token The address of the token to be transferred.
* @param _to The address to which the tokens will be transferred.
* @param _amount The amount of tokens to be transferred.
*/
function doTransferOut(address _token, address _to, uint256 _amount) external;
/**
* @notice Returns the oracle tolerable limit for the given asset pair.
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @return The oracle tolerable limit in WAD format (1 WAD = 100%) for the asset pair.
*/
function getOracleTolerableLimit(address assetA, address assetB) external view returns (uint256);
/**
* @notice Retrieves the position information for a given ID.
* @param _id The ID of the position to retrieve.
* @return position The position information associated with the given ID.
*/
function getPosition(uint256 _id) external view returns (PositionLibrary.Position memory);
/**
* @notice Retrieves the position at the specified index.
* @param _index The index of the position to retrieve.
* @return The Position struct at the specified index.
*/
function getPositionByIndex(uint256 _index) external view returns (PositionLibrary.Position memory);
/**
* @notice Returns the length of the positions array.
* @return The length of the positions array.
*/
function getAllPositionsLength() external view returns (uint256);
/**
* @notice Returns the length of the array containing the positions of a specific trader.
* @param _trader The address of the trader.
* @return The number of positions the trader has.
*/
function getTraderPositionsLength(address _trader) external view returns (uint256);
/**
* @notice Returns the length of the array containing the positions of a specific bucket.
* @param _bucket The address of the bucket.
* @return The number of positions the bucket has.
*/
function getBucketPositionsLength(address _bucket) external view returns (uint256);
/**
* @notice Returns the debt of a position with the given ID.
* @param _id The ID of the position.
* @return The debt of the position, measured in the same decimal format as debtTokens.
*/
function getPositionDebt(uint256 _id) external view returns (uint256);
/**
* @notice Retrieves the close conditions for a specific position.
* @param _positionId The ID of the position.
* @return An array of close conditions associated with the position.
*/
function getCloseConditions(uint256 _positionId) external view returns (LimitOrderLibrary.Condition[] memory);
/**
* @notice Retrieves the close condition for a given position and index.
* @param _positionId The identifier of the position.
* @param _index The index of the close condition.
* @return The close condition at the specified position and index.
*/
function getCloseCondition(
uint256 _positionId,
uint256 _index
) external view returns (LimitOrderLibrary.Condition memory);
/**
* @notice Checks if a position with the given ID is delisted.
* @param _id The ID of the position.
* @return A boolean indicating whether the position is delisted or not.
*/
function isDelistedPosition(uint256 _id) external view returns (bool);
}
interface IPositionManager is IPositionManagerStorage, IPausable {
struct ClosePositionVars {
PositionLibrary.Position position;
bool borrowedAmountIsNotZero;
uint256 oracleTolerableLimit;
bool needOracleTolerableLimitCheck;
}
event SetMaxPositionSize(address token0, address token1, uint256 amountInToken0, uint256 amountInToken1);
event SetDefaultOracleTolerableLimit(uint256 indexed oracleTolerableLimit);
event SecurityBufferChanged(uint256 indexed securityBuffer);
event MaintenanceBufferChanged(uint256 indexed maintenanceBuffer);
event SetOracleTolerableLimit(address indexed assetA, address indexed assetB, uint256 oracleTolerableLimit);
event KeeperRewardDistributorChanged(address indexed _keeperRewardDistributor);
event MinPositionSizeAndAssetChanged(uint256 indexed _minPositionSize, address indexed _minPositionAsset);
event OracleTolerableLimitMultiplierChanged(uint256 indexed newMultiplier);
event OpenPosition(
uint256 indexed positionId,
address indexed trader,
address indexed openedBy,
PositionLibrary.Position position,
address feeToken,
uint256 protocolFee,
uint256 entryPrice,
uint256 leverage,
LimitOrderLibrary.Condition[] closeConditions
);
event PartialClosePosition(
uint256 indexed positionId,
address indexed trader,
address bucketAddress,
address soldAsset,
address positionAsset,
uint256 decreasePositionAmount,
uint256 depositedAmount,
uint256 scaledDebtAmount,
int256 profit,
uint256 positionDebt,
uint256 amountOut
);
event IncreaseDeposit(
uint256 indexed positionId,
address indexed trader,
uint256 depositDelta,
uint256 scaledDebtAmount
);
event DecreaseDeposit(
uint256 indexed positionId,
address indexed trader,
uint256 depositDelta,
uint256 scaledDebtAmount
);
event UpdatePositionConditions(
uint256 indexed positionId,
address indexed trader,
LimitOrderLibrary.Condition[] closeConditions
);
/**
* @notice Initializes the contract with the specified addresses and initializes inherited contracts.
* @param _registry The address of the Registry contract.
* @param _primexDNS The address of the PrimexDNS contract.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _priceOracle The address of the PriceOracle contract.
* @param _keeperRewardDistributor The address of the KeeperRewardDistributor contract.
* @param _whiteBlackList The address of the WhiteBlacklist contract.
*/
function initialize(
address _registry,
address _primexDNS,
address payable _traderBalanceVault,
address _priceOracle,
address _keeperRewardDistributor,
address _whiteBlackList
) external;
/**
* @notice Sets the maximum position size for a pair of tokens.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _token0 The address of the first token in the pair.
* @param _token1 The address of the second token in the pair.
* @param _amountInToken0 The maximum amount of token0 allowed in the position.
* @param _amountInToken1 The maximum amount of token1 allowed in the position.
*/
function setMaxPositionSize(
address _token0,
address _token1,
uint256 _amountInToken0,
uint256 _amountInToken1
) external;
/**
* @notice Sets the default oracle tolerable limit for the protocol.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _percent The new value for the default oracle tolerable limit. Measured in WAD (1 WAD = 100%).
*/
function setDefaultOracleTolerableLimit(uint256 _percent) external;
/**
* @notice Sets the oracle tolerable limit between two assets.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _assetA The address of the first asset.
* @param _assetB The address of the second asset.
* @param _percent The new value for the oracle tolerable limit between two assets. Measured in WAD (1 WAD = 100%).
*/
function setOracleTolerableLimit(address _assetA, address _assetB, uint256 _percent) external;
/**
* @notice Function to set oracleTolerableLimitMultiplier.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param newMultiplier New multiplier in WAD format.
*/
function setOracleTolerableLimitMultiplier(uint256 newMultiplier) external;
/**
* @notice Sets the security buffer value.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* 0 <= newSecurityBuffer < 1.
* Buffer security parameter is used in calculating the liquidation conditions
* https://docs.google.com/document/d/1kR8eaqV4289MAbLKgIfKsZ2NgjFpeC0vpVL7jVUTvho/edit#bookmark=id.i9v508hvrv42
* @param newSecurityBuffer The new value of the security buffer in WAD format.
*/
function setSecurityBuffer(uint256 newSecurityBuffer) external;
/**
* @notice Sets the maintenance buffer value.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* The new maintenance buffer value should be greater than zero and less than one.
* Maintenance buffer is used in calculating the maximum leverage
* https://docs.google.com/document/d/1kR8eaqV4289MAbLKgIfKsZ2NgjFpeC0vpVL7jVUTvho/edit#bookmark=id.87oc1j1s9z21
* @param newMaintenanceBuffer The new value of the maintenance buffer in WAD format.
*/
function setMaintenanceBuffer(uint256 newMaintenanceBuffer) external;
/**
* @notice Sets the address of the SpotTradingRewardDistributor contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _spotTradingRewardDistributor The address of the SpotTradingRewardDistributor contract.
*/
function setSpotTradingRewardDistributor(address _spotTradingRewardDistributor) external;
/**
* @notice Sets the KeeperRewardDistributor contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _keeperRewardDistributor The address of the KeeperRewardDistributor contract.
*/
function setKeeperRewardDistributor(IKeeperRewardDistributorV3 _keeperRewardDistributor) external;
/**
* @notice Opens a position based on the provided order parameters.
* @dev Only callable by the LOM_ROLE role.
* @param _params The parameters for opening a position.
* @return The total borrowed amount, position amount, position ID, and entry price of the new position.
*/
function openPositionByOrder(
LimitOrderLibrary.OpenPositionByOrderParams calldata _params
) external returns (uint256, uint256, uint256, uint256);
/**
* @notice Opens margin position.
* @dev Locks trader's collateral in TraderBalanceVault. Takes loan from bucket for deal.
* Makes swap bucket borrowedAsset amount on '_dex'. Updates rates and indexes in the '_bucket'.
* Mints debtToken for trader (msg.sender)
* @param _params The parameters required to open a position.
*/
function openPosition(PositionLibrary.OpenPositionParams calldata _params) external payable;
/**
* @notice Close trader's active position or liquidate risky position.
* @dev Protocol will fall down (revert) if two conditions occur both:
* 1. (token1Price + position.depositedAmount).wdiv(positionDebt) will become lower than 1,
* so position will make loss for Protocol.
* 2. Not enough liquidity in bucket to pay that loss.
* @param _id Position id for `msg.sender`.
* @param _dealReceiver The receiver of the rest of trader's deposit.
* @param _megaRoutes swap routes on dexes
* @param _amountOutMin minimum allowed amount out for position
*/
function closePosition(
uint256 _id,
address _dealReceiver,
PrimexPricingLibrary.MegaRoute[] memory _megaRoutes,
uint256 _amountOutMin
) external;
/**
* @notice Closes trader's active position by closing condition
* @param _id Position id.
* @param _keeper The address of the keeper or the recipient of the reward.
* @param _megaRoutes An array of routes for executing trades, swap routes on dexes.
* @param _conditionIndex The index of the condition to be used for closing the position.
* @param _ccmAdditionalParams Additional params needed for canBeClosedAfterSwap of the ConditionalClosingManager.
* @param _closeReason The reason for closing the position.
*/
function closePositionByCondition(
uint256 _id,
address _keeper,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _conditionIndex,
bytes calldata _ccmAdditionalParams,
PositionLibrary.CloseReason _closeReason
) external;
/**
* @notice Allows the trader to partially close a position.
* @param _positionId The ID of the position to be partially closed.
* @param _amount The amount of the position asset to be closed from the position.
* @param _depositReceiver The address where the remaining deposit will be sent.
* @param _megaRoutes The routing information for swapping assets.
* @param _amountOutMin The minimum amount to be received after swapping, measured in the same decimal format as the position's asset.
*/
function partiallyClosePosition(
uint256 _positionId,
uint256 _amount,
address _depositReceiver,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin
) external;
/**
* @notice Updates the position with the given position ID by setting new close conditions.
* @param _positionId The ID of the position to update.
* @param _closeConditions An array of close conditions for the position.
* @dev The caller of this function must be the trader who owns the position.
* @dev Emits an `UpdatePositionConditions` event upon successful update.
*/
function updatePositionConditions(
uint256 _positionId,
LimitOrderLibrary.Condition[] calldata _closeConditions
) external;
/**
* @notice Increases the deposit amount for a given position.
* @param _positionId The ID of the position to increase the deposit for.
* @param _amount The amount to increase the deposit by.
* @param _asset The address of the asset to deposit.
* @param _takeDepositFromWallet A flag indicating whether to make the deposit immediately.
* @param _megaRoutes An array of routes to use for trading.
* @param _amountOutMin The minimum amount of the output asset to receive from trading.
*/
function increaseDeposit(
uint256 _positionId,
uint256 _amount,
address _asset,
bool _takeDepositFromWallet,
PrimexPricingLibrary.MegaRoute[] calldata _megaRoutes,
uint256 _amountOutMin
) external;
/**
* @notice Decreases the deposit amount for a given position.
* @param _positionId The ID of the position.
* @param _amount The amount to decrease the deposit by.
*/
function decreaseDeposit(uint256 _positionId, uint256 _amount) external;
/**
* @notice Sets the minimum position size and the corresponding asset for positions.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _minPositionSize The new minimum position size.
* @param _minPositionAsset The address of the asset associated with the minimum position size.
*/
function setMinPositionSize(uint256 _minPositionSize, address _minPositionAsset) external;
/**
* @notice Deletes a positions by their IDs from a specific bucket for a given traders.
* @param _ids The IDs of the positions to be deleted.
* @param _traders The addresses of the traders who owns the position.
* @param _length The length of the traders array.
* @param _bucket The address of the bucket from which the position is to be deleted.
*/
function deletePositions(
uint256[] calldata _ids,
address[] calldata _traders,
uint256 _length,
address _bucket
) external;
/**
* @notice Transfers a specified amount of tokens from the contract to a specified address.
* @dev Only callable by the BATCH_MANAGER_ROLE role.
* @param _token The address of the token to be transferred.
* @param _to The address to which the tokens will be transferred.
* @param _amount The amount of tokens to be transferred.
*/
function doTransferOut(address _token, address _to, uint256 _amount) external;
/**
* @notice Returns the oracle tolerable limit for the given asset pair.
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @return The oracle tolerable limit in WAD format (1 WAD = 100%) for the asset pair.
*/
function getOracleTolerableLimit(address assetA, address assetB) external view returns (uint256);
/**
* @notice Retrieves the position information for a given ID.
* @param _id The ID of the position to retrieve.
* @return position The position information associated with the given ID.
*/
function getPosition(uint256 _id) external view returns (PositionLibrary.Position memory);
/**
* @notice Retrieves the position at the specified index.
* @param _index The index of the position to retrieve.
* @return The Position struct at the specified index.
*/
function getPositionByIndex(uint256 _index) external view returns (PositionLibrary.Position memory);
/**
* @notice Returns the length of the positions array.
* @return The length of the positions array.
*/
function getAllPositionsLength() external view returns (uint256);
/**
* @notice Returns the length of the array containing the positions of a specific trader.
* @param _trader The address of the trader.
* @return The number of positions the trader has.
*/
function getTraderPositionsLength(address _trader) external view returns (uint256);
/**
* @notice Returns the length of the array containing the positions of a specific bucket.
* @param _bucket The address of the bucket.
* @return The number of positions the bucket has.
*/
function getBucketPositionsLength(address _bucket) external view returns (uint256);
/**
* @notice Returns the debt of a position with the given ID.
* @param _id The ID of the position.
* @return The debt of the position, measured in the same decimal format as debtTokens.
*/
function getPositionDebt(uint256 _id) external view returns (uint256);
/**
* @notice Retrieves the close conditions for a specific position.
* @param _positionId The ID of the position.
* @return An array of close conditions associated with the position.
*/
function getCloseConditions(uint256 _positionId) external view returns (LimitOrderLibrary.Condition[] memory);
/**
* @notice Retrieves the close condition for a given position and index.
* @param _positionId The identifier of the position.
* @param _index The index of the close condition.
* @return The close condition at the specified position and index.
*/
function getCloseCondition(
uint256 _positionId,
uint256 _index
) external view returns (LimitOrderLibrary.Condition memory);
/**
* @notice Checks if a position with the given ID is delisted.
* @param _id The ID of the position.
* @return A boolean indicating whether the position is delisted or not.
*/
function isDelistedPosition(uint256 _id) external view returns (bool);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
interface IPositionManagerEvents {
event SetMaxPositionSize(address token0, address token1, uint256 amountInToken0, uint256 amountInToken1);
event SetDefaultOracleTolerableLimit(uint256 indexed oracleTolerableLimit);
event SecurityBufferChanged(uint256 indexed securityBuffer);
event MaintenanceBufferChanged(uint256 indexed maintenanceBuffer);
event SetOracleTolerableLimit(address indexed assetA, address indexed assetB, uint256 oracleTolerableLimit);
event KeeperRewardDistributorChanged(address indexed _keeperRewardDistributor);
event OracleTolerableLimitMultiplierChanged(uint256 indexed newMultiplier);
event OpenPosition(
uint256 indexed positionId,
address indexed trader,
address indexed openedBy,
PositionLibrary.Position position,
uint256 entryPrice,
uint256 leverage,
LimitOrderLibrary.Condition[] closeConditions
);
event PartialClosePosition(
uint256 indexed positionId,
address indexed trader,
address bucketAddress,
address soldAsset,
address positionAsset,
uint256 decreasePositionAmount,
uint256 depositedAmount,
uint256 scaledDebtAmount,
int256 profit,
uint256 positionDebt,
uint256 amountOut
);
event DecreaseDeposit(
uint256 indexed positionId,
address indexed trader,
uint256 depositDelta,
uint256 scaledDebtAmount
);
event UpdatePositionConditions(
uint256 indexed positionId,
address indexed trader,
LimitOrderLibrary.Condition[] closeConditions
);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {PositionLibrary} from "../libraries/PositionLibrary.sol";
import {LimitOrderLibrary} from "../libraries/LimitOrderLibrary.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IPriceOracleV2} from "../PriceOracle/IPriceOracle.sol";
import {ITraderBalanceVault} from "../TraderBalanceVault/ITraderBalanceVault.sol";
import {IKeeperRewardDistributorV3} from "../KeeperRewardDistributor/IKeeperRewardDistributor.sol";
import {ISpotTradingRewardDistributorV2} from "../SpotTradingRewardDistributor/ISpotTradingRewardDistributor.sol";
interface IPositionManagerStorage {
function maxPositionSize(address, address) external returns (uint256);
function defaultOracleTolerableLimit() external returns (uint256);
function securityBuffer() external view returns (uint256);
function maintenanceBuffer() external view returns (uint256);
function positionsId() external view returns (uint256);
function traderPositionIds(address _trader, uint256 _index) external view returns (uint256);
function bucketPositionIds(address _bucket, uint256 _index) external view returns (uint256);
function registry() external view returns (IAccessControl);
function traderBalanceVault() external view returns (ITraderBalanceVault);
function primexDNS() external view returns (IPrimexDNSV3);
function priceOracle() external view returns (IPriceOracleV2);
function keeperRewardDistributor() external view returns (IKeeperRewardDistributorV3);
function spotTradingRewardDistributor() external view returns (ISpotTradingRewardDistributorV2);
function minPositionSize() external view returns (uint256);
function minPositionAsset() external view returns (address);
}
interface IPositionManagerStorageV2 {
function positionManagerExtension() external view returns (address);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IPriceOracleStorage, IPriceOracleStorageV3} from "./IPriceOracleStorage.sol";
interface IPriceOracleV2 is IPriceOracleStorageV3 {
event ChainlinkPriceFeedUpdated(address indexed token, address indexed priceFeed);
event PairPriceDropChanged(address indexed assetA, address indexed assetB, uint256 pairPriceDrop);
event PriceFeedUpdated(address indexed assetA, address indexed assetB, address indexed priceFeed);
event PriceDropFeedUpdated(address indexed assetA, address indexed assetB, address indexed priceDropFeed);
event GasPriceFeedChanged(address priceFeed);
event PythPairIdUpdated(address indexed token, bytes32 indexed priceFeedId);
event Univ3OracleUpdated(uint256 indexed oracleType, address indexed oracle);
event TimeToleranceUpdated(uint256 timeTolerance);
event SupraDataFeedUpdated(address indexed tokenA, address indexed tokenB, uint256 id);
event Univ3TrustedPairUpdated(
uint256 indexed oracleType,
address indexed tokenA,
address indexed tokenB,
bool isTrusted
);
struct UpdateUniv3TrustedPairParams {
uint256 oracleType;
address tokenA;
address tokenB;
bool isTrusted;
}
enum UpdatePullOracle {
Pyth,
Supra
}
struct UpdateSupraDataFeedParams {
address tokenA;
address tokenB;
SupraDataFeedId feedData;
}
/**
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @param priceDropFeed The chain link priceDrop feed address for the pair assetA/assetB
*/
struct UpdatePriceDropFeedsParams {
address assetA;
address assetB;
address priceDropFeed;
}
/**
* @param _registry The address of PrimexRegistry contract
* @param _eth Weth address if eth isn't native token of network. Otherwise set to zero address.
* @param _usdt Address of the USDT token
* @param _treasury Address of the Treasury
*/
function initialize(address _registry, address _eth, address _usdt, address _treasury) external;
/**
* @notice Function to set (change) the pair priceDrop of the trading assets
* @dev Only callable by the SMALL_TIMELOCK_ADMIN.
* @param _assetA The address of position asset
* @param _assetB The address of borrowed asset
* @param _pairPriceDrop The pair priceDrop (in wad)
*/
function setPairPriceDrop(address _assetA, address _assetB, uint256 _pairPriceDrop) external;
/**
* @notice Increases the priceDrop of a pair of assets in the system.
* @dev Only callable by the EMERGENCY_ADMIN role.
* The _pairPriceDrop value must be greater than the current priceDrop value for the pair
* and less than the maximum allowed priceDrop (WadRayMath.WAD / 2).
* @param _assetA The address of position asset
* @param _assetB The address of borrowed asset
* @param _pairPriceDrop The new priceDrop value for the pair (in wad)
*/
function increasePairPriceDrop(address _assetA, address _assetB, uint256 _pairPriceDrop) external;
/**
* @notice Sets the gas price feed contract address.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param priceFeed The address of the gas price feed contract.
*/
function setGasPriceFeed(address priceFeed) external;
/**
* @notice Updates the priceDrop feed for a specific pair of assets.
* @dev Add or update priceDrop feed for assets pair.
* Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _updateParams The array of the UpdatePriceDropFeedsParams structs
*/
function updatePriceDropFeeds(UpdatePriceDropFeedsParams[] calldata _updateParams) external;
/**
* @notice Updates the priceDrop feed for a specific pair of assets.
* @dev Add or update priceDrop feed for assets pair.
* Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @param priceDropFeed The chain link priceDrop feed address for the pair assetA/assetB
*/
function updatePriceDropFeed(address assetA, address assetB, address priceDropFeed) external;
/**
* @notice Retrieves the current gas price from the specified gas price feed.
* @return The current gas price.
*/
function getGasPrice() external view returns (int256);
/**
* @notice For a given asset pair retrieves the priceDrop rate which is the higher
* of the oracle pair priceDrop and the historical pair priceDrop.
* @param _assetA The address of asset A.
* @param _assetB The address of asset B.
* @return The priceDrop rate.
*/
function getPairPriceDrop(address _assetA, address _assetB) external view returns (uint256);
/**
* @notice Retrieves the priceDrop rate between two assets based on the oracle pair priceDrop.
* @param assetA The address of the first asset.
* @param assetB The address of the second asset.
* @return The priceDrop rate as a uint256 value.
*/
function getOraclePriceDrop(address assetA, address assetB) external view returns (uint256);
/**
* @notice Retreives a priceDrop feed address from the oraclePriceDropFeeds mapping
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @return priceDropFeed The address of the priceDrop feed associated with the asset pair.
*/
function getOraclePriceDropFeed(address assetA, address assetB) external view returns (address);
/**
* @notice Calculates exchange rate of one token to another according to the specific oracle route
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @param oracleData The list of oracles to use for price calculations
* @return exchangeRate for assetA/assetB in 10**18 decimality
*/
function getExchangeRate(
address assetA,
address assetB,
bytes calldata oracleData
) external payable returns (uint256);
/**
* @notice Sets or updates the Chainlink price feed for the list of tokens to usd.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _tokens Array of token addresses.
* @param _feeds Array of price feeds.
*/
function updateChainlinkPriceFeedsUsd(address[] calldata _tokens, address[] calldata _feeds) external;
/**
* @notice Sets or updates the Pyth pair ids for the list of tokens.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _tokens Array of token addresses.
* @param _priceFeedIds Array of pair ids.
*/
function updatePythPairId(address[] calldata _tokens, bytes32[] calldata _priceFeedIds) external;
/**
* @notice Sets or updates the Supra price feeds for the list of tokens.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _params Array of token pairs and Supra ids.
*/
function updateSupraDataFeed(UpdateSupraDataFeedParams[] calldata _params) external;
/**
* @notice Sets Uni v3-based TWAP price oracle contracts.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _oracleTypes Array of ids of TWAP contracts.
* @param _oracles Array of TWAP contract addresses.
*/
function updateUniv3TypeOracle(uint256[] calldata _oracleTypes, address[] calldata _oracles) external;
/**
* @notice Sets or updates the Supra price feeds for the list of tokens.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _updateParams Array of token pairs, their DEXs and new trusted status.
*/
function updateUniv3TrustedPair(UpdateUniv3TrustedPairParams[] calldata _updateParams) external;
/**
* @notice Sets the Pyth address
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _pyth the address of the Pyth oracle
*/
function setPyth(address _pyth) external;
/**
* @notice Sets the Supra pull oracle address
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _supraPullOracle the address of the Supra pull oracle
*/
function setSupraPullOracle(address _supraPullOracle) external;
/**
* @notice Sets the Supra storage address
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _supraStorageOracle the address of the Supra storage
*/
function setSupraStorageOracle(address _supraStorageOracle) external;
/**
* @notice Updates pull oracle data for passed oracle types
* @param _data An array of update data for passed oracles
* @param _pullOracleTypes An array of oracle types (Must conform to the UpdatePullOracle struct)
*/
function updatePullOracle(bytes[][] calldata _data, uint256[] calldata _pullOracleTypes) external payable;
/**
* @notice Sets the time tolerance
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _timeTolerance Time tolerance in seconds
*/
function setTimeTolerance(uint256 _timeTolerance) external;
/**
* @notice Sets the usdt address
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _usdt the address of the USDT
*/
function setUSDT(address _usdt) external;
/**
* @notice Sets the treasury address
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _treasury the address of the treasury
*/
function setTreasury(address _treasury) external;
}
interface IPriceOracle is IPriceOracleStorage {
event PairPriceDropChanged(address indexed assetA, address indexed assetB, uint256 pairPriceDrop);
event PriceFeedUpdated(address indexed assetA, address indexed assetB, address indexed priceFeed);
event PriceDropFeedUpdated(address indexed assetA, address indexed assetB, address indexed priceDropFeed);
event GasPriceFeedChanged(address priceFeed);
/**
* @param _registry The address of PrimexRegistry contract
* @param _eth Weth address if eth isn't native token of network. Otherwise set to zero address.
*/
function initialize(address _registry, address _eth) external;
/**
* @notice Function to set (change) the pair priceDrop of the trading assets
* @dev Only callable by the SMALL_TIMELOCK_ADMIN.
* @param _assetA The address of position asset
* @param _assetB The address of borrowed asset
* @param _pairPriceDrop The pair priceDrop (in wad)
*/
function setPairPriceDrop(address _assetA, address _assetB, uint256 _pairPriceDrop) external;
/**
* @notice Increases the priceDrop of a pair of assets in the system.
* @dev Only callable by the EMERGENCY_ADMIN role.
* The _pairPriceDrop value must be greater than the current priceDrop value for the pair
* and less than the maximum allowed priceDrop (WadRayMath.WAD / 2).
* @param _assetA The address of position asset
* @param _assetB The address of borrowed asset
* @param _pairPriceDrop The new priceDrop value for the pair (in wad)
*/
function increasePairPriceDrop(address _assetA, address _assetB, uint256 _pairPriceDrop) external;
/**
* @notice Add or update price feed for assets pair. For only the admin role.
* @param assetA The first currency within the currency pair quotation (the base currency).
* @param assetB The second currency within the currency pair quotation (the quote currency).
* @param priceFeed The chain link price feed address for the pair assetA/assetB
*/
function updatePriceFeed(address assetA, address assetB, address priceFeed) external;
/**
* @notice Sets the gas price feed contract address.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param priceFeed The address of the gas price feed contract.
*/
function setGasPriceFeed(address priceFeed) external;
/**
* @notice Updates the priceDrop feed for a specific pair of assets.
* @dev Add or update priceDrop feed for assets pair.
* Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @param priceDropFeed The chain link priceDrop feed address for the pair assetA/assetB
*/
function updatePriceDropFeed(address assetA, address assetB, address priceDropFeed) external;
/**
* @notice Requests two priceFeeds - assetA/ETH and assetB/ETH (or assetA/USD and assetB/USD).
* @dev If there is no price feed found, the code will return a message that no price feed found.
* @param baseAsset The first currency within the currency pair quotation (the base currency).
* @param quoteAsset The second currency within the currency pair quotation (the quote currency).
* @return A tuple of basePriceFeed and quotePriceFeed. The addresses of the price feed for the base asset and quote asset respectively.
*/
function getPriceFeedsPair(address baseAsset, address quoteAsset) external view returns (address, address);
/**
* @notice Requests priceFeed for the actual exchange rate for an assetA/assetB pair.
* @dev If no price feed for the pair found, USD and ETH are used as intermediate tokens.
* A price for assetA/assetB can be derived if two data feeds exist:
* assetA/ETH and assetB/ETH (or assetA/USD and assetB/USD).
* If there is no price feed found, the code will return a message that no price feed found.
* @param assetA The first currency within the currency pair quotation (the base currency).
* @param assetB The second currency within the currency pair quotation (the quote currency).
* @return exchangeRate for assetA/assetB in 10**18 decimality which will be recalucaled in PrimexPricingLibrary.
* @return direction of a pair as it stored in chainLinkPriceFeeds (i.e. returns 'true' for assetA/assetB, and 'false' for assetB/assetA).
* Throws if priceFeed wasn't found or priceFeed hasn't answer is 0.
*/
function getExchangeRate(address assetA, address assetB) external view returns (uint256, bool);
/**
* @notice Retrieves the direct price feed for the given asset pair.
* @param assetA The address of the first asset.
* @param assetB The address of the second asset.
* @return priceFeed The address of the direct price feed.
*/
function getDirectPriceFeed(address assetA, address assetB) external view returns (address);
/**
* @notice Retrieves the current gas price from the specified gas price feed.
* @return The current gas price.
*/
function getGasPrice() external view returns (int256);
/**
* @notice For a given asset pair retrieves the priceDrop rate which is the higher
* of the oracle pair priceDrop and the historical pair priceDrop.
* @param _assetA The address of asset A.
* @param _assetB The address of asset B.
* @return The priceDrop rate.
*/
function getPairPriceDrop(address _assetA, address _assetB) external view returns (uint256);
/**
* @notice Retrieves the priceDrop rate between two assets based on the oracle pair priceDrop.
* @param assetA The address of the first asset.
* @param assetB The address of the second asset.
* @return The priceDrop rate as a uint256 value.
*/
function getOraclePriceDrop(address assetA, address assetB) external view returns (uint256);
/**
* @notice Retreives a priceDrop feed address from the oraclePriceDropFeeds mapping
* @param assetA The address of the first asset in the pair.
* @param assetB The address of the second asset in the pair.
* @return priceDropFeed The address of the priceDrop feed associated with the asset pair.
*/
function getOraclePriceDropFeed(address assetA, address assetB) external view returns (address);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IPyth} from "@pythnetwork/pyth-sdk-solidity/IPyth.sol";
import {ISupraOraclePull} from "../interfaces/ISupraOraclePull.sol";
import {ISupraSValueFeed} from "../interfaces/ISupraSValueFeed.sol";
interface IPriceOracleStorage {
function registry() external view returns (address);
function eth() external view returns (address);
function gasPriceFeed() external view returns (address);
function pairPriceDrops(address, address) external view returns (uint256);
}
interface IPriceOracleStorageV2 is IPriceOracleStorage {
enum OracleType {
Pyth,
Chainlink,
Uniswapv3,
Supra
}
struct OracleRoute {
address tokenTo;
OracleType oracleType;
bytes oracleData;
}
function pyth() external view returns (IPyth);
function timeTolerance() external view returns (uint256);
function chainlinkPriceFeedsUsd(address) external view returns (address);
function pythPairIds(address) external view returns (bytes32);
function univ3TypeOracles(uint256) external view returns (address);
function univ3TrustedPairs(uint256, address, address) external view returns (bool);
}
interface IPriceOracleStorageV3 is IPriceOracleStorageV2 {
struct SupraDataFeedId {
uint256 id;
bool initialize;
}
function supraPullOracle() external view returns (ISupraOraclePull);
function supraStorageOracle() external view returns (ISupraSValueFeed);
function supraDataFeedID(address, address) external view returns (uint256, bool);
function usdt() external view returns (address);
function treasury() external view returns (address);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IPrimexDNSStorage, IPrimexDNSStorageV3} from "./IPrimexDNSStorage.sol";
interface IPrimexDNSV3 is IPrimexDNSStorageV3 {
event AddNewBucket(BucketData newBucketData);
event BucketDeprecated(address bucketAddress, uint256 delistingTime);
event AddNewDex(DexData newDexData);
event ConditionalManagerChanged(uint256 indexed cmType, address indexed cmAddress);
event PMXchanged(address indexed pmx);
event AavePoolChanged(address indexed aavePool);
event BucketActivated(address indexed bucketAddress);
event BucketFrozen(address indexed bucketAddress);
event DexAdapterChanged(address indexed newAdapterAddress);
event DexActivated(address indexed routerAddress);
event DexFrozen(address indexed routerAddress);
event ChangeProtocolFeeRate(FeeRateType indexed feeRateType, uint256 indexed feeRate);
event ChangeAverageGasPerAction(TradingOrderType indexed tradingOrderType, uint256 indexed averageGasPerAction);
event ChangeMaxProtocolFee(uint256 indexed maxProtocolFee);
event ChangeProtocolFeeCoefficient(uint256 indexed protocolFeeCoefficient);
event ChangeLiquidationGasAmount(uint256 indexed liquidationGasAmount);
event ChangePmxDiscountMultiplier(uint256 indexed pmxDiscountMultiplier);
event ChangeAdditionalGasSpent(uint256 indexed additionalGasSpent);
event ChangeGasPriceBuffer(uint256 indexed gasPriceBuffer);
event ChangeMinFeeRestrictions(CallingMethod indexed callingMethod, MinFeeRestrictions minFeeRestrictions);
event ChangeLeverageTolerance(uint256 leverageTolerance);
/**
* @param feeRateType The order type for which the rate is set
* @param feeRate Setting rate in WAD format (1 WAD = 100%)
*/
struct FeeRateParams {
FeeRateType feeRateType;
uint256 feeRate;
}
struct AverageGasPerActionParams {
TradingOrderType tradingOrderType;
uint256 averageGasPerAction;
}
/**
* @dev Params for initialize() function
* @param registry The address of the PrimexRegistry contract.
* @param pmx The address of the PMX token contract.
* @param treasury The address of the Treasury contract.
* @param delistingDelay The time (in seconds) between deprecation and delisting of a bucket.
* @param adminWithdrawalDelay The time (in seconds) between delisting of a bucket and an adminDeadline.
* @param feeRateParams An array of structs to set protocol fee rate on the corresponding
* @param averageGasPerActionParams An array of structs to set average amount of gas spent by Keeper on the corresponding action
* @param maxProtocolFee MaxProtocolFee that can be charged. Measured in NATIVE_CURRENCY
* @param liquidationGasAmount Average gas amount spent for a single liquidation, measured in wei.
* @param protocolFeeCoefficient Additional coefficient to calculate minProtocolFee, measured in wei.
* @param additionalGasSpent Gas that will be additionally spend after gasSpent calculation.
* @param pmxDiscountMultiplier Multiplier for PMX discount calculation
* @param gasPriceBuffer Multiplier which protects position from immediate liquidation after gas price changed
*/
struct InitParams {
address registry;
address pmx;
address treasury;
uint256 delistingDelay;
uint256 adminWithdrawalDelay;
FeeRateParams[] feeRateParams;
AverageGasPerActionParams[] averageGasPerActionParams;
uint256 maxProtocolFee;
uint256 liquidationGasAmount;
uint256 protocolFeeCoefficient;
uint256 additionalGasSpent;
uint256 pmxDiscountMultiplier;
uint256 gasPriceBuffer;
uint256 leverageTolerance;
}
/**
* @notice Initializes the contract with the specified parameters.
*/
function initialize(InitParams calldata _params) external;
/**
* @notice Deprecates a bucket.
* @dev This function is used to deprecate a bucket by changing its current status to "Deprecated".
* Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _bucket The name of the bucket to deprecate.
* Emits a BucketDeprecated event with the bucket address and the delisting time.
*/
function deprecateBucket(string memory _bucket) external;
/**
* @notice This function is used to set the address of the Aave pool contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _aavePool The address of the Aave pool contract to be set.
*/
function setAavePool(address _aavePool) external;
/**
* @notice Sets the address of the PMX token contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _pmx The address of the PMX token contract.
*/
function setPMX(address _pmx) external;
/**
* @notice Activates a bucket by changing its status from inactive to active.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _bucket The bucket to activate.
*/
function activateBucket(string memory _bucket) external;
/**
* @notice Freezes a bucket, preventing further operations on it,
* by changing its status from active to inactive.
* @dev Only callable by the EMERGENCY_ADMIN role.
* @param _bucket The bucket to be frozen.
*/
function freezeBucket(string memory _bucket) external;
/**
* @notice Adds a new bucket.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _newBucket The address of the new bucket to be added.
* @param _pmxRewardAmount The amount of PMX tokens to be rewarded from the bucket.
* Emits a AddNewBucket event with the struct BucketData of the newly added bucket.
*/
function addBucket(address _newBucket, uint256 _pmxRewardAmount) external;
/**
* @notice Activates a DEX by changing flag isActive on to true.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _dex The name of the DEX to activate.
*/
function activateDEX(string memory _dex) external;
/**
* @notice Freezes a DEX by changing flag isActive to false.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _dex The name of the DEX to be frozen.
*/
function freezeDEX(string memory _dex) external;
/**
* @notice Adds a new DEX to the protocol.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _name The name of the DEX.
* @param _routerAddress The address of the DEX router.
*/
function addDEX(string memory _name, address _routerAddress) external;
/**
* @notice Sets the address of the DEX adapter.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param newAdapterAddress The address of the new DEX adapter.
*/
function setDexAdapter(address newAdapterAddress) external;
/**
* @notice Set min protocol fee restrictions for different calling method.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setMinFeeRestrictions(
CallingMethod _callingMethod,
MinFeeRestrictions calldata _minFeeRestrictions
) external;
/**
* @dev The function to specify the address of conditional manager of some type
* 1 => LimitPriceCOM
* 2 => TakeProfitStopLossCCM
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _address Address to be set for a conditional manager
* @param _cmType The type of a conditional manager
*/
function setConditionalManager(uint256 _cmType, address _address) external;
/**
* @notice Retrieves the address of a bucket by its name.
* @param _name The name of the bucket.
* @return The address of the bucket.
*/
function getBucketAddress(string memory _name) external view returns (address);
/**
* @notice Retrieves the address of the DEX router based on the given DEX name.
* @param _name The name of the DEX.
* @return The address of the DEX router.
*/
function getDexAddress(string memory _name) external view returns (address);
/**
* @notice Retrieves the names of Dexes registered in the protocol.
* @return An array of strings containing the names of all Dexes.
*/
function getAllDexes() external view returns (string[] memory);
/**
* @notice Set the protocol fee rate for one type of order.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
*/
function setProtocolFeeRate(FeeRateParams calldata _feeRateType) external;
/**
* @notice Set average gas amount of gas spent by Keeper on the corresponding action.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setAverageGasPerAction(AverageGasPerActionParams calldata _averageGasPerActionParams) external;
/**
* @notice Set the max protocol fee.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _maxProtocolFee The new max protocol fee.
*/
function setMaxProtocolFee(uint256 _maxProtocolFee) external;
/**
* @notice Set protocol fee coefficient. Used to calculate the minProtocol fee
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
*/
function setProtocolFeeCoefficient(uint256 _maxProtocolFee) external;
/**
* @notice Set liquidation gas amount (average gas amount spent for a single liquidation).
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setLiquidationGasAmount(uint256 _maxProtocolFee) external;
/**
* @notice Set pmxDiscountMultiplier.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
*/
function setPmxDiscountMultiplier(uint256 _pmxDiscountMultiplier) external;
/**
* @notice Set new additionalGas. Used to calculate the minProtocol fee
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setAdditionalGasSpent(uint256 _additionalGasSpent) external;
/**
* @notice Set new gasPriceBuffer.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setGasPriceBuffer(uint256 _gasPriceBuffer) external;
/**
* @notice Set new leverageTolerance.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
*/
function setLeverageTolerance(uint256 _leverageTolerance) external;
/**
* @notice Retrieves pmx, treasury, feeRateType, maxProtocolFee, pmxDiscountMultiplier
*/
function getPrimexDNSParams(
FeeRateType _feeRateType
) external view returns (address, address, uint256, uint256, uint256);
/**
* @notice Retrieves liquidationGasAmount, protocolFeeCoefficient, additionalGasSpent, maxGasAmount and baseLength
*/
function getParamsForMinProtocolFee(
CallingMethod _callingMethod
) external view returns (uint256, uint256, uint256, uint256, uint256);
/**
* @notice Retrieves baseLength, averageGasPerAction, protocolFeeCoefficient and gasPriceBuffer
*/
function getParamsForMinPositionSize(
TradingOrderType _tradingOrderType
) external view returns (uint256, uint256, uint256, uint256);
/**
* @notice Retrieves baseLength for L2 chain payment model depending from tradingOrderType
*/
function getL1BaseLengthForTradingOrderType(TradingOrderType _tradingOrderType) external view returns (uint256);
}
interface IPrimexDNS is IPrimexDNSStorage {
event AddNewBucket(BucketData newBucketData);
event BucketDeprecated(address bucketAddress, uint256 delistingTime);
event AddNewDex(DexData newDexData);
event ChangeFeeRate(OrderType orderType, address token, uint256 rate);
event ConditionalManagerChanged(uint256 indexed cmType, address indexed cmAddress);
event PMXchanged(address indexed pmx);
event AavePoolChanged(address indexed aavePool);
event BucketActivated(address indexed bucketAddress);
event BucketFrozen(address indexed bucketAddress);
event DexAdapterChanged(address indexed newAdapterAddress);
event DexActivated(address indexed routerAddress);
event DexFrozen(address indexed routerAddress);
/**
* @param orderType The order type for which the rate is set
* @param feeToken The token address for which the rate is set
* @param rate Setting rate in WAD format (1 WAD = 100%)
*/
struct FeeRateParams {
OrderType orderType;
address feeToken;
uint256 rate;
}
/**
* @notice Initializes the contract with the specified parameters.
* @param _registry The address of the PrimexRegistry contract.
* @param _pmx The address of the PMX token contract.
* @param _treasury The address of the Treasury contract.
* @param _delistingDelay The time (in seconds) between deprecation and delisting of a bucket.
* @param _adminWithdrawalDelay The time (in seconds) between delisting of a bucket and an adminDeadline.
* @param _feeRateParams Initial fee params
*/
function initialize(
address _registry,
address _pmx,
address _treasury,
uint256 _delistingDelay,
uint256 _adminWithdrawalDelay,
FeeRateParams[] calldata _feeRateParams
) external;
/**
* @notice Deprecates a bucket.
* @dev This function is used to deprecate a bucket by changing its current status to "Deprecated".
* Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _bucket The name of the bucket to deprecate.
* Emits a BucketDeprecated event with the bucket address and the delisting time.
*/
function deprecateBucket(string memory _bucket) external;
/**
* @notice This function is used to set the address of the Aave pool contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _aavePool The address of the Aave pool contract to be set.
*/
function setAavePool(address _aavePool) external;
/**
* @notice Sets the protocol rate in PMX.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
*/
function setFeeRate(FeeRateParams calldata _feeRateParams) external;
/**
* @notice Sets the address of the PMX token contract.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _pmx The address of the PMX token contract.
*/
function setPMX(address _pmx) external;
/**
* @notice Activates a bucket by changing its status from inactive to active.
* @dev Only callable by the SMALL_TIMELOCK_ADMIN role.
* @param _bucket The bucket to activate.
*/
function activateBucket(string memory _bucket) external;
/**
* @notice Freezes a bucket, preventing further operations on it,
* by changing its status from active to inactive.
* @dev Only callable by the EMERGENCY_ADMIN role.
* @param _bucket The bucket to be frozen.
*/
function freezeBucket(string memory _bucket) external;
/**
* @notice Adds a new bucket.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param _newBucket The address of the new bucket to be added.
* @param _pmxRewardAmount The amount of PMX tokens to be rewarded from the bucket.
* Emits a AddNewBucket event with the struct BucketData of the newly added bucket.
*/
function addBucket(address _newBucket, uint256 _pmxRewardAmount) external;
/**
* @notice Activates a DEX by changing flag isActive on to true.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _dex The name of the DEX to activate.
*/
function activateDEX(string memory _dex) external;
/**
* @notice Freezes a DEX by changing flag isActive to false.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _dex The name of the DEX to be frozen.
*/
function freezeDEX(string memory _dex) external;
/**
* @notice Adds a new DEX to the protocol.
* @dev Only callable by the MEDIUM_TIMELOCK_ADMIN role.
* @param _name The name of the DEX.
* @param _routerAddress The address of the DEX router.
*/
function addDEX(string memory _name, address _routerAddress) external;
/**
* @notice Sets the address of the DEX adapter.
* @dev Only callable by the BIG_TIMELOCK_ADMIN role.
* @param newAdapterAddress The address of the new DEX adapter.
*/
function setDexAdapter(address newAdapterAddress) external;
/**
* @dev The function to specify the address of conditional manager of some type
* 1 => LimitPriceCOM
* 2 => TakeProfitStopLossCCM
* @param _address Address to be set for a conditional manager
* @param _cmType The type of a conditional manager
*/
function setConditionalManager(uint256 _cmType, address _address) external;
/**
* @notice Retrieves the address of a bucket by its name.
* @param _name The name of the bucket.
* @return The address of the bucket.
*/
function getBucketAddress(string memory _name) external view returns (address);
/**
* @notice Retrieves the address of the DEX router based on the given DEX name.
* @param _name The name of the DEX.
* @return The address of the DEX router.
*/
function getDexAddress(string memory _name) external view returns (address);
/**
* @notice Retrieves the names of Dexes registered in the protocol.
* @return An array of strings containing the names of all Dexes.
*/
function getAllDexes() external view returns (string[] memory);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IPrimexDNSStorage {
enum Status {
Inactive,
Active,
Deprecated
}
enum OrderType {
MARKET_ORDER,
LIMIT_ORDER,
SWAP_MARKET_ORDER,
SWAP_LIMIT_ORDER
}
struct BucketData {
address bucketAddress;
Status currentStatus;
uint256 delistingDeadline;
// The deadline is for the admin to call Bucket.withdrawAfterDelisting().
uint256 adminDeadline;
}
struct DexData {
address routerAddress;
bool isActive;
}
struct AdapterData {
string[] dexes;
bool isAdded;
}
function registry() external view returns (address);
function delistingDelay() external view returns (uint256);
function adminWithdrawalDelay() external view returns (uint256);
function buckets(string memory) external view returns (address, Status, uint256, uint256);
function dexes(string memory) external view returns (address, bool);
function cmTypeToAddress(uint256 cmType) external view returns (address);
function dexAdapter() external view returns (address);
function pmx() external view returns (address);
function treasury() external view returns (address);
function aavePool() external view returns (address);
function feeRates(OrderType _orderType, address _token) external view returns (uint256);
}
interface IPrimexDNSStorageV2 is IPrimexDNSStorage {
struct FeeRestrictions {
uint256 minProtocolFee;
uint256 maxProtocolFee;
}
function feeRestrictions(
OrderType _orderType
) external view returns (uint256 minProtocolFee, uint256 maxProtocolFee);
}
interface IPrimexDNSStorageV3 is IPrimexDNSStorageV2 {
enum FeeRateType {
MarginPositionClosedByTrader,
SpotPositionClosedByTrader,
MarginPositionClosedByKeeper,
SpotPositionClosedByKeeper,
MarginLimitOrderExecuted,
SpotLimitOrderExecuted,
SwapLimitOrderExecuted,
SwapMarketOrder
}
enum TradingOrderType {
MarginMarketOrder,
SpotMarketOrder,
MarginLimitOrder,
MarginLimitOrderDepositInThirdAsset,
SpotLimitOrder,
SwapLimitOrder
}
enum CallingMethod {
OpenPositionByOrder,
ClosePositionByCondition
}
struct MinFeeRestrictions {
uint256 maxGasAmount;
uint256 baseLength;
}
function protocolFeeRates(FeeRateType _feeRateType) external view returns (uint256);
function averageGasPerAction(TradingOrderType _tradingOrderType) external view returns (uint256);
function minFeeRestrictions(
CallingMethod _callingMethod
) external view returns (uint256 maxGasAmount, uint256 baseLength);
function maxProtocolFee() external view returns (uint256);
function protocolFeeCoefficient() external view returns (uint256);
function liquidationGasAmount() external view returns (uint256);
function additionalGasSpent() external view returns (uint256);
function pmxDiscountMultiplier() external view returns (uint256);
function gasPriceBuffer() external view returns (uint256);
function leverageTolerance() external view returns (uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
import {IPTokenStorage, IBucket, IBucketV3, IFeeExecutor, IERC20MetadataUpgradeable, IActivityRewardDistributor} from "./IPTokenStorage.sol";
interface IPToken is IPTokenStorage {
/**
* @dev Emitted after the mint action
* @param from The address performing the mint
* @param value The amount being
*/
event Mint(address indexed from, uint256 value);
/**
* @dev Emitted after pTokens are burned
* @param from The owner of the aTokens, getting them burned
* @param value The amount being burned
*/
event Burn(address indexed from, uint256 value);
/**
* @dev Emitted during the transfer action
* @param from The user whose tokens are being transferred
* @param to The recipient
* @param amount The amount being transferred
* @param index The new liquidity index of the reserve
*/
event BalanceTransfer(address indexed from, address indexed to, uint256 amount, uint256 index);
event LockDeposit(address indexed user, uint256 indexed id, uint256 deadline, uint256 amount);
event UnlockDeposit(address indexed user, uint256 indexed id);
/**
* @dev contract initializer
* @param _name The name of the ERC20 token.
* @param _symbol The symbol of the ERC20 token.
* @param _decimals The number of decimals for the ERC20 token.
* @param _bucketsFactory Address of the buckets factory that will call the setBucket fucntion
*/
function initialize(string memory _name, string memory _symbol, uint8 _decimals, address _bucketsFactory) external;
/**
* @dev Sets the bucket for the contract.
* @param _bucket The address of the bucket to set.
*/
function setBucket(IBucket _bucket) external;
/**
* @dev Sets the InterestIncreaser for current PToken.
* @param _interestIncreaser The interest increaser address.
*/
function setInterestIncreaser(IFeeExecutor _interestIncreaser) external;
/**
* @dev Sets the lender reward distributor contract address.
* @param _lenderRewardDistributor The address of the lender reward distributor contract.
*/
function setLenderRewardDistributor(IActivityRewardDistributor _lenderRewardDistributor) external;
/**
* @notice Locks a deposit for a specified user.
* @param _user The address of the user for whom the deposit is being locked.
* @param _amount The amount to be locked as a deposit.
* @param _duration The duration for which the deposit will be locked.
* @dev This function can only be called externally and overrides the corresponding function in the parent contract.
* @dev The user must not be blacklisted.
*/
function lockDeposit(address _user, uint256 _amount, uint256 _duration) external;
/**
* @dev Unlocks a specific deposit.
* @param _depositId The ID of the deposit to be unlocked.
*/
function unlockDeposit(uint256 _depositId) external;
/**
* @dev Mints `amount` pTokens to `user`
* @param _user The address receiving the minted tokens
* @param _amount The amount of tokens getting minted
* @param _index The current liquidityIndex
* @return Minted amount of PTokens
*/
function mint(address _user, uint256 _amount, uint256 _index) external returns (uint256);
/**
* @dev Mints pTokens to the reserve address
* Compared to the normal mint, we don't revert when the amountScaled is equal to the zero. Additional checks were also removed
* Only callable by the Bucket
* @param _reserve The address of the reserve
* @param _amount The amount of tokens getting minted
* @param _index The current liquidityIndex
*/
function mintToReserve(address _reserve, uint256 _amount, uint256 _index) external;
/**
* @dev Burns pTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @param _user The owner of the pTokens, getting them burned
* @param _amount The amount of underlying token being returned to receiver
* @param _index The current liquidityIndex
* @return Burned amount of PTokens
*/
function burn(address _user, uint256 _amount, uint256 _index) external returns (uint256);
/**
* @dev Returns the scaled balance of the user.
* @param _user The owner of pToken
* @return The scaled balances of the user
*/
function scaledBalanceOf(address _user) external view returns (uint256);
/**
* @dev Returns available balance of the user.
* @param _user The owner of pToken
* @return The available balance of the user
*/
function availableBalanceOf(address _user) external view returns (uint256);
/**
* @dev Returns locked deposits and balance of user
* @param _user The owner of locked deposits
* @return Structure with deposits and total locked balance of user
*/
function getUserLockedBalance(address _user) external view returns (LockedBalance memory);
/**
* @dev Returns the scaled total supply of pToken.
* @return The scaled total supply of the pToken.
*/
function scaledTotalSupply() external view returns (uint256);
/**
* @dev Function to get a deposit index in user's deposit array.
* @param id Deposit id.
* @return index Deposit index in user's 'deposit' array.
*/
function getDepositIndexById(uint256 id) external returns (uint256 index);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import {IBucket, IBucketV3} from "../Bucket/IBucket.sol";
import {IFeeExecutor} from "../BonusExecutor/IFeeExecutor.sol";
import {IActivityRewardDistributor} from "../ActivityRewardDistributor/IActivityRewardDistributor.sol";
interface IPTokenStorage is IERC20MetadataUpgradeable {
struct Deposit {
uint256 lockedBalance;
uint256 deadline;
uint256 id;
}
struct LockedBalance {
uint256 totalLockedBalance;
Deposit[] deposits;
}
function bucket() external view returns (IBucketV3);
function interestIncreaser() external view returns (IFeeExecutor);
function lenderRewardDistributor() external view returns (IActivityRewardDistributor);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {IBucketV3} from "../Bucket/IBucket.sol";
import {IPrimexDNSV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IReserveStorage} from "./IReserveStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface IReserve is IReserveStorage, IPausable {
event BurnAmountCalculated(uint256 burnAmount);
event TransferRestrictionsChanged(address indexed pToken, TransferRestrictions newTransferRestrictions);
/**
* @dev contract initializer
* @param dns The address of PrimexDNS contract
* @param registry The address of Registry contract
*/
function initialize(IPrimexDNSV3 dns, address registry) external;
/**
* @dev Burns the permanent loss amount (presented in pTokens) from the Reserve for a particular bucket
* @param bucket The address of a bucket
* Emits BurnAmountCalculated(burnAmount) event
*/
function paybackPermanentLoss(IBucketV3 bucket) external;
/**
* @dev Transfers some bonus in pTokens to receiver from Reserve
* Can be called by executor only
* @param _bucketName The bucket where the msg.sender should be a fee decreaser (for debtToken) or
* interest increaser (for pToken)
* @param _to The receiver of bonus pTokens
* @param _amount The amount of bonus pTokens to transfer
*/
function payBonus(string memory _bucketName, address _to, uint256 _amount) external;
/**
* @dev Function to transfer tokens to the Treasury. Only MEDIUM_TIMELOCK_ADMIN can call it.
* @param bucket The bucket from which to transfer pTokens
* @param amount The amount of pTokens to transfer
*/
function transferToTreasury(address bucket, uint256 amount) external;
/**
* @dev Function to set transfer restrictions for a token.
* @notice Only MEDIUM_TIMELOCK_ADMIN can call it.
* @param pToken pToken to set restrictions for
* @param transferRestrictions Min amount to be left in the Reserve
*/
function setTransferRestrictions(address pToken, TransferRestrictions calldata transferRestrictions) external;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IReserveStorage {
struct TransferRestrictions {
uint256 minAmountToBeLeft;
uint256 minPercentOfTotalSupplyToBeLeft;
}
event TransferFromReserve(address pToken, address to, uint256 amount);
function transferRestrictions(address pToken) external view returns (uint256, uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {ISpotTradingRewardDistributorStorage} from "./ISpotTradingRewardDistributorStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface ISpotTradingRewardDistributorV2 is ISpotTradingRewardDistributorStorage, IPausable {
event SpotTradingClaimReward(address indexed trader, uint256 amount);
event RewardPerPeriodDecreased(uint256 indexed rewardPerPeriod);
event TopUpUndistributedPmxBalance(uint256 indexed amount);
event RewardPerPeriodChanged(uint256 indexed rewardPerPeriod);
event PmxWithdrawn(uint256 indexed amount);
/**
* @dev contract initializer
* @param registry The address of Registry contract
* @param periodDuration The duration of a reward period
* @param priceOracle The address of PriceOracle contract
* @param pmx The address of PMX token
* @param traderBalanceVault The address of TraderBalanceVault contract
* @param treasury The address of Treasury contract
*/
function initialize(
address registry,
uint256 periodDuration,
address priceOracle,
address pmx,
address payable traderBalanceVault,
address treasury
) external;
/**
* @dev Function to update spot trader activity. Only PM_ROLE can call it.
* @param trader Address of a trader
* @param positionAsset Address of a position asset
* @param positionAmount Amount of a position asset
*/
function updateTraderActivity(
address trader,
address positionAsset,
uint256 positionAmount,
bytes calldata positionUsdOracleDataoracleData
) external;
/**
* @dev Function to claim reward for spot trading activity.
* Transfer rewards on the balance in traderBalanceVault
* Emits SpotTradingClaimReward(address trader, uint256 amount)
*/
function claimReward() external;
/**
* @dev Function to set new reward per period. Only MEDIUM_TIMELOCK_ADMIN can call it.
* @param rewardPerPeriod New value for reward per period
*/
function setRewardPerPeriod(uint256 rewardPerPeriod) external;
/**
* @dev Function to decrease reward per period. Only EMERGENCY_ADMIN can call it.
* @param _rewardPerPeriod New value for reward per period, must be less than the current value
*/
function decreaseRewardPerPeriod(uint256 _rewardPerPeriod) external;
/**
* @dev Function to topUp the contract PMX balance
* @param amount PMX amount to add to the contract balance
*/
function topUpUndistributedPmxBalance(uint256 amount) external;
/**
* @dev Function to withdraw PMX from the contract to treasury
* @dev Only BIG_TIMELOCK_ADMIN can call it.
* @param amount Amount of PMX to withdraw from the contract
*/
function withdrawPmx(uint256 amount) external;
/**
* @dev Function to get SpotTraderActivity
* @param periodNumber Period number
* @param traderAddress Address of a trader
* @return A struct with activity and hasClaimed members
*/
function getSpotTraderActivity(uint256 periodNumber, address traderAddress) external view returns (uint256);
/**
* @dev Get information for the period corresponding to the given timestamp
* @param timestamp The timestamp to get information about
* @return totalReward Total reward for the corresponding period
* @return totalActivity Total activity for the corresponding period
*/
function getPeriodInfo(uint256 timestamp) external view returns (uint256, uint256);
/**
* @dev Function to get an array of period numbers when trader had any activity
* @param trader Address of a trader
* @return An array of period numbers with trader activity
*/
function getPeriodsWithTraderActivity(address trader) external view returns (uint256[] memory);
/**
* @dev Function to calculate trader's reward for her activities during periods
* @param trader Address of a trader
* @return reward Amount of reward
* @return currentPeriod The current period
*/
function calculateReward(address trader) external view returns (uint256 reward, uint256 currentPeriod);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface ISpotTradingRewardDistributorStorage {
struct PeriodInfo {
uint256 totalReward;
// map trader address to her activity
mapping(address => uint256) traderActivity;
uint256 totalActivity;
}
function registry() external view returns (address);
function dns() external view returns (address);
function periodDuration() external view returns (uint256);
function initialPeriodTimestamp() external view returns (uint256);
function rewardPerPeriod() external view returns (uint256);
function pmx() external view returns (address);
function priceOracle() external view returns (address);
function treasury() external view returns (address);
function traderBalanceVault() external view returns (address payable);
function undistributedPMX() external view returns (uint256);
function periods(uint256 periodNumber) external view returns (uint256, uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {PrimexPricingLibrary} from "../libraries/PrimexPricingLibrary.sol";
import {IPrimexDNSV3, IPrimexDNSStorageV3} from "../PrimexDNS/IPrimexDNS.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface ISwapManager is IPausable {
event SpotSwap(
address indexed trader,
address indexed receiver,
address tokenA,
address tokenB,
uint256 amountSold,
uint256 amountBought
);
event PaidProtocolFee(
address indexed trader,
address indexed boughtAsset,
IPrimexDNSStorageV3.FeeRateType indexed feeRateType,
uint256 feeInPositionAsset,
uint256 feeInPmx
);
/**
* @param tokenA The address of the asset to be swapped from.
* @param tokenB The address of the asset to be received in the swap.
* @param amountTokenA The amount of tokenA to be swapped.
* @param amountOutMin The minimum amount of tokenB expected to receive.
* @param routes An array of PrimexPricingLibrary.Route structs representing the routes for the swap.
* @param receiver The address where the swapped tokens will be received.
* @param deadline The deadline for the swap transaction.
* @param isSwapFromWallet A flag indicating whether the swap is perfomed from a wallet or a protocol balance.
* @param isSwapToWallet A flag indicating whether the swapped tokens will be sent to a wallet or a protocol balance.
* @param isSwapFeeInPmx A flag indicating whether the swap fee is paid in PMX or in native token.
*/
struct SwapParams {
address tokenA;
address tokenB;
uint256 amountTokenA;
uint256 amountOutMin;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
address receiver;
uint256 deadline;
bool isSwapFromWallet;
bool isSwapToWallet;
bool isSwapFeeInPmx;
bytes tokenAtokenBOracleData;
bytes pmxPositionAssetOracleData;
bytes nativePositionAssetOracleData;
bytes[][] pullOracleData;
uint256[] pullOracleTypes;
}
/**
* @param depositAsset The address of the deposited asset.
* @param positionAsset The address of the position asset.
* @param depositAmount Amount of tokens in a deposit asset.
* @param megaRoutes An array of PrimexPricingLibrary.Route structs representing the routes for the swap.
* @param trader The trader address, who has created the order.
* @param deadline The deadline for the swap transaction.
* @param feeToken An asset in which the fee will be paid. At this point it could be the pmx, the epmx or a positionAsset
* @param keeperRewardDistributor The address of KeeperRewardDistributor contract.
* @param gasSpent Gas spent on executing transaction.
*/
struct SwapInLimitOrderParams {
address depositAsset;
address positionAsset;
uint256 depositAmount;
PrimexPricingLibrary.MegaRoute[] megaRoutes;
address trader;
uint256 deadline;
address feeToken;
address keeperRewardDistributor;
uint256 gasSpent;
bytes depositPositionAssetOracleData;
bytes pmxPositionAssetOracleData;
bytes nativePositionAssetOracleData;
}
/**
* @notice Initializes the contract with the specified parameters.
* @param _registry The address of the PrimexRegistry contract.
*/
function initialize(address _registry) external;
/**
* @notice Re-initializes the contract with the specified parameters.
* @dev Only BIG_TIMELOCK_ADMIN can call it.
* @param _primexDNS The address of the PrimexDNS contract.
* @param _traderBalanceVault The address of the TraderBalanceVault contract.
* @param _priceOracle The address of the PriceOracle contract.
* @param _whiteBlackList The address of the WhiteBlackList contract.
*/
function initializeAfterUpgrade(
address _primexDNS,
address payable _traderBalanceVault,
address _priceOracle,
address _whiteBlackList
) external;
/**
* @notice Executes a swap on dexes defined in routes
* @param params The SwapParams struct containing the details of the swap transaction.
* @param maximumOracleTolerableLimit The maximum tolerable limit in WAD format (1 WAD = 100%)
* @param needOracleTolerableLimitCheck Flag indicating whether to perform an oracle tolerable limit check.
* @return The resulting amount after the swap.
*/
function swap(
SwapParams calldata params,
uint256 maximumOracleTolerableLimit,
bool needOracleTolerableLimitCheck
) external payable returns (uint256);
/**
* @notice Executes a swap on dexes defined in routes
* @dev Only callable by the LOM_ROLE role.
* @param params The SwapInLimitOrderParams struct containing the details of the swap transaction.
* @param maximumOracleTolerableLimit The maximum tolerable limit in WAD format (1 WAD = 100%)
* @return The resulting amount after the swap and feeInPositionAsset.
*/
function swapInLimitOrder(
SwapInLimitOrderParams calldata params,
uint256 maximumOracleTolerableLimit
) external returns (uint256, uint256);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
import {ITraderBalanceVaultStorage} from "./ITraderBalanceVaultStorage.sol";
import {IPausable} from "../interfaces/IPausable.sol";
interface ITraderBalanceVault is ITraderBalanceVaultStorage, IPausable {
/**
* Types of way to open a position or order
*/
enum OpenType {
OPEN_BY_ORDER,
OPEN,
CREATE_LIMIT_ORDER
}
/**
* @param trader The trader, who opens margin deal
* @param depositReceiver the address to which the deposit is transferred when blocked.
* This happens because the trader's deposit is involved in the position
* @param borrowedAsset The token to lock for deal in a borrowed asset
* @param depositAsset The token is a deposit asset
* (it is blocked when creating a limit order
* For others, the operations is transferred to the account of the receiver of the deposit and is swapped )
* @param depositAmount Amount of tokens in a deposit asset
* @param depositInBorrowedAmount Amount of tokens to lock for deal in a borrowed asset
* @param openType Corresponds to the purpose of locking
*/
struct LockAssetParams {
address trader;
address depositReceiver;
address depositAsset;
uint256 depositAmount;
OpenType openType;
}
/**
* @param trader The trader who opened the position
* @param receiver The receiver of the rest of trader deposit.
* @param asset Borrowed asset of the position being closed (the need for accrual of profit).
* @param unlockAmount The amount of unlocked collateral for deal
* @param returnToTrader The returned to trader amount when position was closed.
*/
struct UnlockAssetParams {
address trader;
address receiver;
address asset;
uint256 amount;
}
/**
* @param traders An array of traders for which available balance should be increased
* @param amounts An array of amounts corresponding to traders' addresses that should be added to their available balances
* @param asset Asset address which amount will be increased
* @param length The amount of traders in an array
*/
struct BatchTopUpAvailableBalanceParams {
address[] traders;
uint256[] amounts;
address asset;
uint256 length;
}
event Deposit(address indexed depositer, address indexed asset, uint256 amount);
event Withdraw(address indexed withdrawer, address asset, uint256 amount);
/**
* @dev contract initializer
* @param _registry The address of Registry contract
* @param _whiteBlackList The address of WhiteBlackList contract
*/
function initialize(address _registry, address _whiteBlackList) external;
receive() external payable;
/**
* @dev Deposits trader collateral for margin deal
* @param _asset The collateral asset for deal
* @param _amount The amount of '_asset' to deposit
*/
function deposit(address _asset, uint256 _amount) external payable;
/**
* @dev Withdraws the rest of trader's deposit after closing deal
* @param _asset The collateral asset for withdraw
* @param _amount The amount of '_asset' to withdraw
*/
function withdraw(address _asset, uint256 _amount) external;
/**
* @dev Traders lock their collateral for the limit order.
* @param _trader The owner of collateral
* @param _asset The collateral asset for deal
* @param _amount The amount of '_asset' to deposit
*/
function increaseLockedBalance(address _trader, address _asset, uint256 _amount) external payable;
/**
* @dev Locks deposited trader's assets as collateral for orders.
* Decreases the available balance when opening position.
* Transfers deposited amount to the deposit receiver.
* @param _params parameters necessary to lock asset
*/
function useTraderAssets(LockAssetParams calldata _params) external;
/**
* @dev Unlocks trader's collateral when open position by order or update deposit.
* @param _params parameters necessary to unlock asset
*/
function unlockAsset(UnlockAssetParams calldata _params) external;
/**
* The function to increase available balance for several traders
* @param _params A struct containing BatchTopUpAvailableBalanceParams
*/
function batchTopUpAvailableBalance(BatchTopUpAvailableBalanceParams calldata _params) external;
/**
* Withdraws an asset amount from an asset holder to a receiver
* @param _from Withdraw from address
* @param _to Withdraw to address
* @param _asset Address of an asset
* @param _amount Amount of an asset
* @param fromLocked True if withdraw from locked balance
*/
function withdrawFrom(address _from, address _to, address _asset, uint256 _amount, bool fromLocked) external;
/**
* Increases available balance of a receiver in the protocol
* @param receiver The address of an asset receiver
* @param asset The asset address for which available balance will be increased
* @param amount The amount of an asset
*/
function topUpAvailableBalance(address receiver, address asset, uint256 amount) external payable;
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface ITraderBalanceVaultStorage {
struct TraderBalance {
uint256 availableBalance;
uint256 lockedBalance;
}
function registry() external view returns (address);
/**
*
* @param trader Trader's address
* @param asset Asset address
* @return availableBalance availableBalance
* @return lockedBalance lockedBalance
*/
function balances(
address trader,
address asset
) external view returns (uint256 availableBalance, uint256 lockedBalance);
}// (c) 2024 Primex.finance
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;
interface IWhiteBlackList {
enum AccessType {
UNLISTED,
WHITELISTED,
BLACKLISTED
}
event WhitelistedAddressAdded(address indexed addr);
event WhitelistedAddressRemoved(address indexed addr);
event BlacklistedAddressAdded(address indexed addr);
event BlacklistedAddressRemoved(address indexed addr);
function addAddressToWhitelist(address _address) external;
function addAddressesToWhitelist(address[] calldata _addresses) external;
function removeAddressFromWhitelist(address _address) external;
function removeAddressesFromWhitelist(address[] calldata _addresses) external;
function addAddressToBlacklist(address _address) external;
function addAddressesToBlacklist(address[] calldata _addresses) external;
function removeAddressFromBlacklist(address _address) external;
function removeAddressesFromBlacklist(address[] calldata _addresses) external;
function getAccessType(address _address) external view returns (AccessType);
function isBlackListed(address _address) external view returns (bool);
function registry() external view returns (address);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"contracts/libraries/PrimexPricingLibrary.sol": {
"PrimexPricingLibrary": "0x99d511a76a84cb71c87b8d8de4a00cfb952af191"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"DS_MATH_ADD_OVERFLOW","type":"error"},{"inputs":[],"name":"DS_MATH_MUL_OVERFLOW","type":"error"},{"inputs":[{"components":[{"internalType":"contract IPositionManagerV2","name":"positionManager","type":"address"},{"internalType":"contract ILimitOrderManager","name":"limitOrderManager","type":"address"},{"internalType":"uint256","name":"orderId","type":"uint256"},{"components":[{"internalType":"uint256","name":"firstAssetShares","type":"uint256"},{"internalType":"uint256","name":"depositInThirdAssetShares","type":"uint256"},{"internalType":"uint256","name":"depositToBorrowedShares","type":"uint256"}],"internalType":"struct IBestDexLens.Shares","name":"shares","type":"tuple"},{"components":[{"internalType":"string","name":"dex","type":"string"},{"internalType":"bytes32","name":"ancillaryData","type":"bytes32"}],"internalType":"struct IBestDexLens.DexWithAncillaryData[]","name":"dexes","type":"tuple[]"},{"internalType":"bytes","name":"depositBorrowedAssetOracleData","type":"bytes"},{"internalType":"bytes[][]","name":"pullOracleData","type":"bytes[][]"},{"internalType":"uint256[]","name":"pullOracleTypes","type":"uint256[]"}],"internalType":"struct IBestDexLens.BestDexByOrderParams","name":"_params","type":"tuple"}],"name":"getBestDexByOrder","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"firstAssetReturnParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"depositInThirdAssetReturnParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"depositToBorrowedReturnParams","type":"tuple"}],"internalType":"struct IBestDexLens.GetBestDexByOrderReturnParams","name":"_returnParams","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IPositionManagerV2","name":"_positionManager","type":"address"},{"internalType":"uint256","name":"_positionId","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"components":[{"internalType":"string","name":"dex","type":"string"},{"internalType":"bytes32","name":"ancillaryData","type":"bytes32"}],"internalType":"struct IBestDexLens.DexWithAncillaryData[]","name":"_dexesWithAncillaryData","type":"tuple[]"}],"name":"getBestDexByPosition","outputs":[{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IPositionManagerV2","name":"positionManager","type":"address"},{"internalType":"address","name":"borrowedAsset","type":"address"},{"internalType":"uint256","name":"borrowedAmount","type":"uint256"},{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"address","name":"positionAsset","type":"address"},{"components":[{"internalType":"uint256","name":"firstAssetShares","type":"uint256"},{"internalType":"uint256","name":"depositInThirdAssetShares","type":"uint256"},{"internalType":"uint256","name":"depositToBorrowedShares","type":"uint256"}],"internalType":"struct IBestDexLens.Shares","name":"shares","type":"tuple"},{"components":[{"internalType":"string","name":"dex","type":"string"},{"internalType":"bytes32","name":"ancillaryData","type":"bytes32"}],"internalType":"struct IBestDexLens.DexWithAncillaryData[]","name":"dexes","type":"tuple[]"}],"internalType":"struct IBestDexLens.BestDexForOpenablePositionParams","name":"_params","type":"tuple"}],"name":"getBestDexForOpenablePosition","outputs":[{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"_firstAssetReturnParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"_depositInThirdAssetReturnParams","type":"tuple"},{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"_depositToBorrowedReturnParams","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IPositionManagerV2","name":"positionManager","type":"address"},{"internalType":"address","name":"assetToBuy","type":"address"},{"internalType":"address","name":"assetToSell","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isAmountToBuy","type":"bool"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"gasPriceInCheckedAsset","type":"uint256"},{"components":[{"internalType":"string","name":"dex","type":"string"},{"internalType":"bytes32","name":"ancillaryData","type":"bytes32"}],"internalType":"struct IBestDexLens.DexWithAncillaryData[]","name":"dexes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesParams","name":"_params","type":"tuple"}],"name":"getBestMultipleDexes","outputs":[{"components":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256","name":"estimateGasAmount","type":"uint256"},{"components":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"string","name":"dexName","type":"string"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct PrimexPricingLibrary.Path[]","name":"paths","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.Route[]","name":"routes","type":"tuple[]"}],"internalType":"struct PrimexPricingLibrary.MegaRoute[]","name":"megaRoutes","type":"tuple[]"}],"internalType":"struct IBestDexLens.GetBestMultipleDexesReturnParams","name":"_returnParams","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608080604052346015576131be908161001b8239f35b600080fdfe6101a080604052600436101561001457600080fd5b600061016052610160513560e01c90816301ffc9a71461161a5750806318cf81b41461128d578063373c00a11461040757806343116daf146101515763d61a1b941461005f57600080fd5b3461014a57602036600319011261014a576004356001600160401b03811161014a57610100600319823603011261014a576040519061009d8261166d565b6100a9816004016116f6565b82526100b7602482016116f6565b60208301526100c8604482016116f6565b6040830152606481013560608301526084810135801515810361014a57608083015260a481013560a083015260c481013560c083015260e4810135916001600160401b03831161014a5761012861013292600461014695369201016117a5565b60e0820152611ce6565b6040519182916020835260208301906118b9565b0390f35b6101605180fd5b3461014a57608036600319011261014a576004356001600160a01b0381169081900361014a576064356001600160401b03811161014a576101969036906004016117a5565b61019e611a2a565b506040516301ffc9a760e01b8152633d79d7fb60e11b6004820152602081602481865afa9081156103ad5761016051916103cd575b50156103bb5760405163eb02c30160e01b815260243560048201526101605181602481865afa9081156103ad576101605191610276575b606082015160a083015160c084015160405161014693610132939192889290916001600160a01b0391821691168a6102418661166d565b855260208501526040840152606083015261016051608083015260443560a08301526101605160c083015260e0820152611ce6565b9290503d8061016051853e61028b81856116d5565b83019260208185031261014a578051906001600160401b03821161014a5701916101808385031261014a5760405161018081018181106001600160401b038211176103935760405283518152602084015160208201526102ed60408501611a9a565b60408201526102fe60608501611a9a565b60608201526080840151608082015261031960a08501611a9a565b60a082015260c084015160c082015261033460e08501611a9a565b60e0820152610100840151610100820152610120840151610120820152610140840151610140820152610160840151936001600160401b03851161014a5761014695610132956103849201611aae565b6101608201529193509161020a565b634e487b7160e01b61016051526041600452602461016051fd5b6040513d61016051823e3d90fd5b60405163044aa57560e41b8152600490fd5b90506020813d6020116103ff575b816103e8602093836116d5565b8101031261014a576103f990611a4b565b836101d3565b3d91506103db565b602036600319011261014a576004356001600160401b03811161014a57610140600319823603011261014a5760405160a05261044460a05161166d565b610450816004016116f6565b60a051526024810135906001600160a01b038216820361014a57602060a05101918252604060a05101916044820135835261048e366064840161170a565b606060a0510160c05260c0515260c48201356001600160401b03811161014a576104be90600436918501016117a5565b608060a051015260e48201356001600160401b03811161014a576104e89060043691850101611a0c565b9160a08051019283526101048101356001600160401b03811161014a578101903660238301121561014a5760048201356105218161173c565b9261052f60405194856116d5565b818452602060048186019360051b830101019036821161014a5760248101925b8284106111e7575050505060c060a05101918252610124810135906001600160401b03821161014a5701903660238301121561014a576004820135916105948361173c565b926105a260405194856116d5565b808452602060048186019260051b840101019136831161014a57602401905b8282106111d75750505060e060a05101918252604051610140526105e76101405161169f565b6105ef611a2a565b61014051526020610140510161010052610607611a2a565b6101005152604061014051016101205261061f611a2a565b610120515260a051516040516301ffc9a760e01b8152633d79d7fb60e11b600482015290602090829060249082906001600160a01b03165afa9081156103ad57610160519161119d575b5080611119575b156103bb5760a05151604051632630c12f60e01b815290602090829060049082906001600160a01b03165afa9081156103ad5761016051916110fa575b5090519151906001600160a01b0316803b1561014a579160405192839163f197ce3560e01b8352604483016040600485015281518091526064840190602060648260051b87010193019161016051905b82821061107d575050505060031983820301602484015260208085519283815201940190610160515b8181106110645750505081806101605194039134905af180156103ad57611051575b5051915160405163d09ef24160e01b81526004810191909152610160519092839060249082906001600160a01b03165afa80156103ad576101605160e052610f17575b60e051610120015160049250670de0b6b3a764000003610e8a5760e051604001516001600160a01b0316905b60a05151604051633f4a2d2760e01b81529360209185919082906001600160a01b03165afa9283156103ad576101605193610e69575b5060e051604001516001600160a01b0390811660808190529083161415908180610e4b575b610dd0575b60018060a01b03604060e05101511690606060e051015191604061012051510151916040519660808801908882106001600160401b038311176103935760409182529288526001600160a01b0387811660208a81019182528a84019790975260608a0195865291516391f03efd60e01b81529195919384916004918391165afa9081156103ad576101605191610d94575b60a05151604051632630c12f60e01b81529350602090849060049082906001600160a01b03165afa9283156103ad576101605193610d63575b505160408051630e6e928f60e41b815260a0600482015289516001600160a01b0390811660a4830152965190961660c4870152979097015160e48501529151608061010485015280516101248501819052610160519497610144600583901b8a018101968a9692959492936020909301929187015b828210610c37575050505085151560248501526001600160a01b039081166044850152166064830152818303600319016084830152602092829161099a9190611894565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af49283156103ad576101605193610bfe575b5060e0516101200151670de0b6b3a763ffff19810193908411610bb05761016051938015908115610bdf575b5015610bca576706f05b59d3b20000840193848111610bb0578410610b9b57608051610aae94670de0b6b3a7640000900492906001600160a01b03851603610b065750610a3c91611a58565b60a051805160e0516020015160c05151516080909301516040519590949290916001600160a01b039081169116610a728761166d565b865260208601526001600160a01b0316604085015260608401526101608051608085015260a08401919091525160c083015260e0820152611ce6565b61014051526040516020815280610146610af0610ada61014051516060602086015260808501906118b9565b6101005151848203601f190160408601526118b9565b6101205151838203601f190160608501526118b9565b905015610a3c57610b9160018060a01b0360a051511660018060a01b03602060e05101511660018060a01b03604060e051015116606060e0510151602060c05151015191608060a05101519360405195610b5f8761166d565b865260208601526040850152606084015261016051608084015260a08301526101605160c083015260e0820152611ce6565b6101005152610a3c565b630a77254f60e01b6101605152600461016051fd5b634e487b7160e01b61016051526011600452602461016051fd5b631550e8b760e01b6101605152600461016051fd5b94505080610bf7610bf08683611c75565b9586611bba565b14856109f0565b9092506020813d602011610c2f575b81610c1a602093836116d5565b81010312610c2a575191836109c4565b600080fd5b3d9150610c0d565b9193949596509196610143198b820301825287519060206040820192805183520151916040602083015282518091526060820190602060608260051b850101940192610160515b828110610ca25750505050506020806001929901920192018a969594939192610956565b9091929394605f1983820301855285516020604083019160018060a01b0381511684520151916040602082015282518092526060810190602060608460051b83010194019261016051915b818310610d0e57505050505060208060019297019501910192919092610c7e565b9091929394602080610d56600193605f198682030189528951906040610d3d8351606084526060840190611894565b9285810151868401520151906040818403910152611894565b9701950193019190610ced565b610d8691935060203d602011610d8d575b610d7e81836116d5565b810190611a7b565b91886108e1565b503d610d74565b90506020823d602011610dc8575b81610daf602093836116d5565b8101031261014a57610dc2600492611a9a565b906108a8565b3d9150610da2565b610e4160018060a01b0360a0515116606060e0510151604060c051510151608060a05101519160405193610e038561166d565b845260018060a01b03881660208501526080516040850152606084015261016051608084015260a08301526101605160c083015260e0820152611ce6565b6101205152610817565b60e051602001516080516001600160a01b0390911614159250610812565b610e8391935060203d602011610d8d57610d7e81836116d5565b91836107ed565b60e0515160405163011ddaef60e71b81529260209184919082906001600160a01b03165afa80156103ad576101605190610ed2575b600492506001600160a01b0316906107b7565b50906020813d602011610f0f575b81610eed602093836116d5565b8101031261014a5751906001600160a01b038216820361014a57600491610ebf565b3d9150610ee0565b3d8061016051843e610f2981846116d5565b82019160208184031261014a578051906001600160401b03821161014a57016101c08184031261014a57604051906101c082018281106001600160401b0382111761039357604052610f7a81611a9a565b8252610f8860208201611a9a565b6020830152610f9960408201611a9a565b604083015260608101516060830152610fb460808201611a9a565b608083015260a081015160a0830152610fcf60c08201611a9a565b60c083015260e081015160e08301526101008101516101008301526101208101516101208301526110036101408201611a4b565b6101408301526101608101516101608301526101808101516101808301526101a0810151936001600160401b03851161014a576004946110439201611aae565b6101a082015260e05261078b565b6101605161105e916116d5565b83610748565b8251865260209586019587955090920191600101610726565b91939092949550606319888203018252845190815180825260208201906020808260051b850101940192610160515b8281106110cf5750505050506020806001929601920192018795949391926106fd565b90919293946020806110ed600193601f198782030189528951611894565b97019501939291016110ac565b611113915060203d602011610d8d57610d7e81836116d5565b866106ad565b5082516040516301ffc9a760e01b815263fabd349d60e01b600482015290602090829060249082906001600160a01b03165afa9081156103ad576101605191611163575b50610670565b90506020813d602011611195575b8161117e602093836116d5565b8101031261014a5761118f90611a4b565b8661115d565b3d9150611171565b90506020813d6020116111cf575b816111b8602093836116d5565b8101031261014a576111c990611a4b565b86610669565b3d91506111ab565b81358152602091820191016105c1565b83356001600160401b03811161014a5760049083010136603f8201121561014a5760208101356112168161173c565b9161122460405193846116d5565b8183526020808085019360051b830101019036821161014a5760408101925b82841061125d57505050908252506020938401930161054f565b83356001600160401b03811161014a5760209161128283928380369288010101611a0c565b815201930192611243565b3461014a57602036600319011261014a576004356001600160401b03811161014a57610140600319823603011261014a576040516112ca8161166d565b6112d6826004016116f6565b81526112e4602483016116f6565b9160208201928352604082019060448101358252611304606482016116f6565b906060840191825260808401946084820135865261132460a483016116f6565b9160a086019283526113393660c4830161170a565b9060c08701918252610124810135906001600160401b03821161014a57600461136592369201016117a5565b60e0870190815290611375611a2a565b5061137e611a2a565b95611387611a2a565b88516040516301ffc9a760e01b8152633d79d7fb60e11b600482015291979190602090829060249082906001600160a01b03165afa9081156103ad5761016051916115e0575b50806115cd575b806115ba575b806115a7575b156103bb578951156115955781511580159061157d575b1561156b57845181516114969b6001600160a01b03918216929091168281149391928415918280611556575b611520575b50506114bd575b5098519551945191519798610146986114a497611481976001600160a01b0391821697908216969095909491169261146e9291156114b2575190611a58565b91515192519360405195610b5f8761166d565b936040519586956060875260608701906118b9565b9085820360208701526118b9565b9083820360408501526118b9565b506101605190611a58565b61014699506114819694926114a49896949261151061146e938e60018060a01b039051169060018060a01b038b51169060018060a01b03905116845160208a510151918b519360405195610b5f8761166d565b9b5092949698509294965061142f565b8d51855189516040908101518c519151969f5061154e9695919490936001600160a01b0316610b5f8761166d565b988d80611428565b8b516001600160a01b03168314159350611423565b6040516396b154ab60e01b8152600490fd5b50845181516001600160a01b039081169116146113f7565b60405163511ff7fb60e11b8152600490fd5b5085516001600160a01b031615156113e0565b5080516001600160a01b031615156113da565b5084516001600160a01b031615156113d4565b90506020813d602011611612575b816115fb602093836116d5565b8101031261014a5761160c90611a4b565b8b6113cd565b3d91506115ee565b3461014a57602036600319011261014a576004359063ffffffff60e01b821680920361014a57602091635d7c7b9760e11b811490811561165c575b5015158152f35b6301ffc9a760e01b14905083611655565b61010081019081106001600160401b0382111761168957604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b0382111761168957604052565b604081019081106001600160401b0382111761168957604052565b90601f801991011681019081106001600160401b0382111761168957604052565b35906001600160a01b0382168203610c2a57565b9190826060910312610c2a576040516117228161169f565b604080829480358452602081013560208501520135910152565b6001600160401b0381116116895760051b60200190565b6001600160401b03811161168957601f01601f191660200190565b92919261177a82611753565b9161178860405193846116d5565b829481845281830111610c2a578281602093846000960137010152565b81601f82011215610c2a578035906117bc8261173c565b926117ca60405194856116d5565b82845260208085019360051b83010191818311610c2a5760208101935b8385106117f657505050505090565b84356001600160401b038111610c2a5782016040818503601f190112610c2a5760405191611823836116ba565b60208201356001600160401b038111610c2a576020908301019285601f85011215610c2a5760406020949361185e888688809835910161176e565b83520135838201528152019401936117e7565b60005b8381106118845750506000910152565b8181015183820152602001611874565b906020916118ad81518092818552858086019101611871565b601f01601f1916010190565b906040606082019280518352602081015160208401520151916060604083015282518091526080820191602060808360051b8301019401926000915b83831061190457505050505090565b9091929394607f1982820301835285519060206040820192805183520151916040602083015282518091526060820190602060608260051b85010194019260005b828110611966575050505050602080600192970193019301919392906118f5565b9091929394605f1983820301855285516020604083019160018060a01b0381511684520151916040602082015282518092526060810190602060608460051b8301019401926000915b8183106119d057505050505060208060019297019501910192919092611945565b90919293946020806119ff600193605f198682030189528951906040610d3d8351606084526060840190611894565b97019501930191906119af565b9080601f83011215610c2a57816020611a279335910161176e565b90565b60405190611a378261169f565b606060408360008152600060208201520152565b51908115158203610c2a57565b91908201809211611a6557565b634e487b7160e01b600052601160045260246000fd5b90816020910312610c2a57516001600160a01b0381168103610c2a5790565b51906001600160a01b0382168203610c2a57565b81601f82011215610c2a578051611ac481611753565b92611ad260405194856116d5565b81845260208284010111610c2a57611a279160208085019101611871565b91908203918211611a6557565b90611b078261173c565b611b1460405191826116d5565b8281528092611b25601f199161173c565b0190602036910137565b60005b828110611b3e57505050565b606082820152602001611b32565b90611b81611b598361173c565b611b6660405191826116d5565b83815260208194611b79601f199161173c565b019101611b2f565b565b805115611b905760200190565b634e487b7160e01b600052603260045260246000fd5b8051821015611b905760209160051b010190565b8115611bc4570490565b634e487b7160e01b600052601260045260246000fd5b90602082820312610c2a5781516001600160401b038111610c2a57611a279201611aae565b929593909594919460a084019660a085528051809852602060c0860191019760005b818110611c565750506001600160a01b0396871660208601526040850191909152941660608301521515608090910152909150565b89516001600160a01b031683526020998a019990920191600101611c21565b81810292918115918404141715611a6557565b81810392916000138015828513169184121617611a6557565b91909160008382019384129112908015821691151617611a6557565b6000198114611a655760010190565b60405190611cd9826116ba565b6060602083600081520152565b611cee611a2a565b60208201519091906001600160a01b0316151580612f95575b15612f8357602081015160408201805190916001600160a01b03918216911614612f715760a0820191825115612f5c576060810151835111612f4a576040519260c084018481106001600160401b03821117611689576040526000845260006020850152606060408501526000606085015260006080850152606060a085015260e08201515190611d978261173c565b91611da560405193846116d5565b808352611db4601f199161173c565b0160005b818110612f25575050518452611dd260e083015151611afd565b60a0850152611de560e083015151611b4c565b95606093611e2060405191611dfa87846116d5565b60028352601f19870136602085013760408801839052516001600160a01b031691611b83565b5260018060a01b036020840151166040860151805160011015611b90576040015260405193611e4e8561169f565b808552600060208601526000604086015260005b60e085015151811015612631578451604051633f4a2d2760e01b815290602090829060049082906001600160a01b03165afa9081156123fc57611ede91602091600091612614575b50611eb98460e08a0151611ba6565b515190604051808095819463657dcce560e01b83528660048401526024830190611894565b03916001600160a01b03165afa600091816125d9575b50611f0457506001905b01611e62565b8551604051633f4a2d2760e01b81529299939593949290602090829060049082906001600160a01b03165afa9081156123fc576004916020916000916125bc575b506040516391f03efd60e01b815292839182906001600160a01b03165afa9081156123fc5760009161257c575b506040516336dd6b3d60e01b81526001600160a01b03808416600483015290929160209184916024918391165afa9182156123fc57600092612549575b50611fc060608801518a5190611bba565b602089015260018060a01b038116604089015260408901519060046020611feb8d60e08c0151611ba6565b5101518951604051633f4a2d2760e01b81529194919260209184919082906001600160a01b03165afa9182156123fc5760049260209160009161252c575b506040516391f03efd60e01b815293849182906001600160a01b03165afa9182156123fc576000926124e9575b5060808a015160405163340f07ad60e11b8152946000948694859461208e941515936001600160a01b03909216929060048701611bff565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af49081156123fc576000916124c8575b5087528551604051633f4a2d2760e01b815290602090829060049082906001600160a01b03165afa9081156123fc576004916020916000916124ab575b506040516391f03efd60e01b815292839182906001600160a01b03165afa80156123fc57600090612471575b608088015161213b92501515906001600160a01b031689613036565b908a6000198314612461576121c96121cf926121a78c670de0b6b3a7640000948f8a61216f8f9260e0612186940151611ba6565b5161217f60608601518093611ba6565b528b611ba6565b5060606121938351611afd565b920151916121a18383611ba6565b52611ba6565b50806121bd8d606060a082015191015190611ba6565b5260c08a015190611c75565b04613121565b608089015260808601511515600014612445576121ee6121f991613121565b608089015190611ca1565b61221061220a60608a01518c611ba6565b51611b83565b5260015b87518110156124255760608601519060018101808211611a655761223d61224591600494611c75565b8a5190611bba565b6020898101919091528751604051633f4a2d2760e01b815293849182906001600160a01b03165afa9182156123fc57600492602091600091612408575b506040516391f03efd60e01b815293849182906001600160a01b03165afa80156123fc57888a91898e9560009261239f575b5060800180516001966123279487946123219492936122e092901515916001600160a01b031690613036565b90516000901561234c5750600019810361232e575060607d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000005b955b015190611ba6565b51611ba6565b5201612214565b61234761233c606092613121565b608088015190611ca1565b612317565b506000198103612381575060607fffff6f1bf04115e2c5b54376aa16b901ce32309909cb1f0000000000000000005b95612319565b61239a61238f606092613121565b608088015190611c88565b61237b565b949550509150506020823d82116123f4575b816123be602093836116d5565b810103126123f157509088612327826123218e8c6122e08d60806123e360019b611a9a565b9650509350509350956122b4565b80fd5b3d91506123b1565b6040513d6000823e3d90fd5b61241f9150823d8111610d8d57610d7e81836116d5565b38612282565b50919660019093919361243b6060890151611cbd565b6060890152611efe565b61245161245c91613121565b608089015190611c88565b6121f9565b5050509196600190939193611efe565b6020823d82116124a3575b81612489602093836116d5565b810103126123f1575061249e61213b91611a9a565b61211f565b3d915061247c565b6124c29150823d8111610d8d57610d7e81836116d5565b386120f3565b6124e3913d8091833e6124db81836116d5565b810190611bda565b386120b6565b90916020823d8211612524575b81612503602093836116d5565b810103126123f157509061208e61251c60009493611a9a565b929350612056565b3d91506124f6565b6125439150823d8111610d8d57610d7e81836116d5565b38612029565b90916020823d8211612574575b81612563602093836116d5565b810103126123f15750519038611faf565b3d9150612556565b906020823d82116125b4575b81612595602093836116d5565b810103126123f157509060206125ac602493611a9a565b919250611f72565b3d9150612588565b6125d39150823d8111610d8d57610d7e81836116d5565b38611f45565b90916020823d821161260c575b816125f3602093836116d5565b810103126123f1575061260590611a9a565b9038611ef4565b3d91506125e6565b61262b9150823d8111610d8d57610d7e81836116d5565b38611eaa565b50959290969350606085015115612f135761264f6060860151611afd565b60009061265f6060880151611b4c565b6101805260608701519761269c6126758a61173c565b996126836040519b8c6116d5565b808b52612692601f199161173c565b0160208b01611b2f565b60005b60608901518110156126fa576001906126b88a51611afd565b6126c58261018051611ba6565b526126d38161018051611ba6565b506126de8a51611afd565b6126e8828d611ba6565b526126f3818c611ba6565b500161269f565b50909192939497959860005b8a8951821015612738579061272081612321600194611b83565b516127318261232161018051611b83565b5201612706565b505095969793949291906001965b60608a01518810156128e75760005b8a518110156128db5788600019810111611a655761277e816123216000198c0161018051611ba6565b5160018201808311611a6557828b8f828f94836127a793612321926121a185612321858c611ba6565b5160808d0151156128d35784811280156128cb575b6128ae575b5050505060005b8281106127ec5750906001916127e5826123218d61018051611ba6565b5201612755565b908a600019810111611a65576128096000198c0161018051611ba6565b51916128158185611af0565b600019810193908411611a65578f8c8f928f968893612848876123218b61284161284f96608098611ba6565b5194611ba6565b5190611ca1565b910151156128a657848112801561289e575b612874575b5050506001919250016127c8565b6001945090612321612891929661288b8684611af0565b94611ba6565b528b9291508c8438612866565b508415612861565b848113612861565b93506000926128c1929161232191611ba6565b528a828b386127c1565b5084156127bc565b8481136127bc565b50600190970196612746565b9297965093909498979283519960005b606086015180821015612f01578c156129b3578161291491611af0565b9b8c600019810111611a655761292e6000198e018b611ba6565b5181600019810111611a6557612991916129798f8c61296e61296261295b61298597600019880190611ba6565b5186611af0565b91600019840190611ba6565b52600019018d611ba6565b51906000190190611ba6565b519c6000190189611ba6565b5161299f575b6001016128f7565b986129ab600191611cbd565b999050612997565b505094919792989399509495505b8115612ef65760409182516129d684826116d5565b60018152601f1984019060005b828110612edf5750848a01528351906129fc85836116d5565b6001825260005b818110612ec85750508351612a3891612a1b826116ba565b600182526020820152848a015190612a3282611b83565b52611b83565b5060208501516001600160a01b031691612a518261173c565b91612a5e855193846116d5565b808352612a6d601f199161173c565b019060005b828110612ea05750505090612aaf91835191612a8d836116ba565b825260208201526020612aa2848a0151611b83565b51015190612a3282611b83565b5060005b6060890151811015612e9657612ac98187611ba6565b5115612e8e57612ad98187611ba6565b5190612ae58187611ba6565b515160408b015186518551633f4a2d2760e01b815291949190602090829060049082906001600160a01b03165afa908115612dc657612b599291602091600091612e71575b50612b35868c611ba6565b5151908851808096819463657dcce560e01b83528660048401526024830190611894565b03916001600160a01b03165afa918215612dc657600092612e36575b506020612b82858b611ba6565b51015188518751633f4a2d2760e01b815291939190602090829060049082906001600160a01b03165afa908115612e0e57600491602091600091612e19575b5089516391f03efd60e01b815292839182906001600160a01b03165afa908115612e0e57600091612dd1575b5060808a018051895163340f07ad60e11b81529198919560009487948594612c28941515936001600160a01b03909216929060048701611bff565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af4918215612dc6576020612c80888e612c9b97968496612c8896600092612dab575b50835198612c6f8a61169f565b895285890152828801520151611b83565b510151611b83565b51015160208d0151916121a18383611ba6565b50612ca960208b0151611cbd565b60208b01528960208901612ccd612cc68460a08451950151611ba6565b5183611a58565b918210612d9a5752612cdf8185611ba6565b51612cea8289611ba6565b51600019810193908411611a655782612d08600195612d2694611ba6565b518d8c51936000908315600014612d2f575050505050600090611a58565b88525b01612ab3565b51159050612d6f57670de0b6b3a76400006121c9612d57612d699560a0612d63950151611ba6565b5160c08d015190611c75565b90611c88565b90611a58565b670de0b6b3a76400006121c9612d57612d959560a0612d8f950151611ba6565b90611ca1565b612d69565b630a77254f60e01b60005260046000fd5b612dbf91923d8091833e6124db81836116d5565b9038612c62565b86513d6000823e3d90fd5b906020823d8211612e06575b81612dea602093836116d5565b810103126123f1575090612dff600092611a9a565b9091612bed565b3d9150612ddd565b88513d6000823e3d90fd5b612e309150823d8111610d8d57610d7e81836116d5565b38612bc1565b90916020823d8211612e69575b81612e50602093836116d5565b810103126123f15750612e6290611a9a565b9038612b75565b3d9150612e43565b612e889150823d8111610d8d57610d7e81836116d5565b38612b2a565b600190612d29565b5050505050509150565b6020908651612eae8161169f565b838152600083820152838882015282828701015201612a72565b602090612ed3611ccc565b82828601015201612a03565b602090612eea611ccc565b828285010152016129e3565b509496505050505050565b505094919792989399509495506129c1565b60405163af16b31b60e01b8152600490fd5b602090604051612f34816116ba565b6060815260008382015282828701015201611db8565b604051631edbd19360e11b8152600490fd5b6040516001622c3a8160e21b03198152600490fd5b604051635c6726db60e11b8152600490fd5b604051632638e39360e11b8152600490fd5b5060408101516001600160a01b03161515611d07565b90606082820312610c2a5780601f83011215610c2a5760405191612fce8361169f565b829060608101928311610c2a57905b828210612fea5750505090565b8151815260209182019101612fdd565b60208152606061301583518260208501526080840190611894565b6020840151604084810191909152909301516001600160a01b031691015290565b6060916000936130ba576130609160405194858094819363eb5251a560e01b835260048301612ffa565b03926001600160a01b03165af160009181613089575b50613082575060001990565b6020015190565b6130ac91925060603d6060116130b3575b6130a481836116d5565b810190612fab565b9038613076565b503d61309a565b6130da91604051948580948193630fafa65f60e11b835260048301612ffa565b03926001600160a01b03165af160009181613100575b506130fc575060001990565b5190565b61311a91925060603d6060116130b3576130a481836116d5565b90386130f0565b6001600160ff1b0381116131325790565b60405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608490fdfea26469706673582212208bc6ece5c0061678c9ef873bc1292314cbd6083e0eb03abe384ecda6f7ead42864736f6c634300081a0033
Deployed Bytecode
0x6101a080604052600436101561001457600080fd5b600061016052610160513560e01c90816301ffc9a71461161a5750806318cf81b41461128d578063373c00a11461040757806343116daf146101515763d61a1b941461005f57600080fd5b3461014a57602036600319011261014a576004356001600160401b03811161014a57610100600319823603011261014a576040519061009d8261166d565b6100a9816004016116f6565b82526100b7602482016116f6565b60208301526100c8604482016116f6565b6040830152606481013560608301526084810135801515810361014a57608083015260a481013560a083015260c481013560c083015260e4810135916001600160401b03831161014a5761012861013292600461014695369201016117a5565b60e0820152611ce6565b6040519182916020835260208301906118b9565b0390f35b6101605180fd5b3461014a57608036600319011261014a576004356001600160a01b0381169081900361014a576064356001600160401b03811161014a576101969036906004016117a5565b61019e611a2a565b506040516301ffc9a760e01b8152633d79d7fb60e11b6004820152602081602481865afa9081156103ad5761016051916103cd575b50156103bb5760405163eb02c30160e01b815260243560048201526101605181602481865afa9081156103ad576101605191610276575b606082015160a083015160c084015160405161014693610132939192889290916001600160a01b0391821691168a6102418661166d565b855260208501526040840152606083015261016051608083015260443560a08301526101605160c083015260e0820152611ce6565b9290503d8061016051853e61028b81856116d5565b83019260208185031261014a578051906001600160401b03821161014a5701916101808385031261014a5760405161018081018181106001600160401b038211176103935760405283518152602084015160208201526102ed60408501611a9a565b60408201526102fe60608501611a9a565b60608201526080840151608082015261031960a08501611a9a565b60a082015260c084015160c082015261033460e08501611a9a565b60e0820152610100840151610100820152610120840151610120820152610140840151610140820152610160840151936001600160401b03851161014a5761014695610132956103849201611aae565b6101608201529193509161020a565b634e487b7160e01b61016051526041600452602461016051fd5b6040513d61016051823e3d90fd5b60405163044aa57560e41b8152600490fd5b90506020813d6020116103ff575b816103e8602093836116d5565b8101031261014a576103f990611a4b565b836101d3565b3d91506103db565b602036600319011261014a576004356001600160401b03811161014a57610140600319823603011261014a5760405160a05261044460a05161166d565b610450816004016116f6565b60a051526024810135906001600160a01b038216820361014a57602060a05101918252604060a05101916044820135835261048e366064840161170a565b606060a0510160c05260c0515260c48201356001600160401b03811161014a576104be90600436918501016117a5565b608060a051015260e48201356001600160401b03811161014a576104e89060043691850101611a0c565b9160a08051019283526101048101356001600160401b03811161014a578101903660238301121561014a5760048201356105218161173c565b9261052f60405194856116d5565b818452602060048186019360051b830101019036821161014a5760248101925b8284106111e7575050505060c060a05101918252610124810135906001600160401b03821161014a5701903660238301121561014a576004820135916105948361173c565b926105a260405194856116d5565b808452602060048186019260051b840101019136831161014a57602401905b8282106111d75750505060e060a05101918252604051610140526105e76101405161169f565b6105ef611a2a565b61014051526020610140510161010052610607611a2a565b6101005152604061014051016101205261061f611a2a565b610120515260a051516040516301ffc9a760e01b8152633d79d7fb60e11b600482015290602090829060249082906001600160a01b03165afa9081156103ad57610160519161119d575b5080611119575b156103bb5760a05151604051632630c12f60e01b815290602090829060049082906001600160a01b03165afa9081156103ad5761016051916110fa575b5090519151906001600160a01b0316803b1561014a579160405192839163f197ce3560e01b8352604483016040600485015281518091526064840190602060648260051b87010193019161016051905b82821061107d575050505060031983820301602484015260208085519283815201940190610160515b8181106110645750505081806101605194039134905af180156103ad57611051575b5051915160405163d09ef24160e01b81526004810191909152610160519092839060249082906001600160a01b03165afa80156103ad576101605160e052610f17575b60e051610120015160049250670de0b6b3a764000003610e8a5760e051604001516001600160a01b0316905b60a05151604051633f4a2d2760e01b81529360209185919082906001600160a01b03165afa9283156103ad576101605193610e69575b5060e051604001516001600160a01b0390811660808190529083161415908180610e4b575b610dd0575b60018060a01b03604060e05101511690606060e051015191604061012051510151916040519660808801908882106001600160401b038311176103935760409182529288526001600160a01b0387811660208a81019182528a84019790975260608a0195865291516391f03efd60e01b81529195919384916004918391165afa9081156103ad576101605191610d94575b60a05151604051632630c12f60e01b81529350602090849060049082906001600160a01b03165afa9283156103ad576101605193610d63575b505160408051630e6e928f60e41b815260a0600482015289516001600160a01b0390811660a4830152965190961660c4870152979097015160e48501529151608061010485015280516101248501819052610160519497610144600583901b8a018101968a9692959492936020909301929187015b828210610c37575050505085151560248501526001600160a01b039081166044850152166064830152818303600319016084830152602092829161099a9190611894565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af49283156103ad576101605193610bfe575b5060e0516101200151670de0b6b3a763ffff19810193908411610bb05761016051938015908115610bdf575b5015610bca576706f05b59d3b20000840193848111610bb0578410610b9b57608051610aae94670de0b6b3a7640000900492906001600160a01b03851603610b065750610a3c91611a58565b60a051805160e0516020015160c05151516080909301516040519590949290916001600160a01b039081169116610a728761166d565b865260208601526001600160a01b0316604085015260608401526101608051608085015260a08401919091525160c083015260e0820152611ce6565b61014051526040516020815280610146610af0610ada61014051516060602086015260808501906118b9565b6101005151848203601f190160408601526118b9565b6101205151838203601f190160608501526118b9565b905015610a3c57610b9160018060a01b0360a051511660018060a01b03602060e05101511660018060a01b03604060e051015116606060e0510151602060c05151015191608060a05101519360405195610b5f8761166d565b865260208601526040850152606084015261016051608084015260a08301526101605160c083015260e0820152611ce6565b6101005152610a3c565b630a77254f60e01b6101605152600461016051fd5b634e487b7160e01b61016051526011600452602461016051fd5b631550e8b760e01b6101605152600461016051fd5b94505080610bf7610bf08683611c75565b9586611bba565b14856109f0565b9092506020813d602011610c2f575b81610c1a602093836116d5565b81010312610c2a575191836109c4565b600080fd5b3d9150610c0d565b9193949596509196610143198b820301825287519060206040820192805183520151916040602083015282518091526060820190602060608260051b850101940192610160515b828110610ca25750505050506020806001929901920192018a969594939192610956565b9091929394605f1983820301855285516020604083019160018060a01b0381511684520151916040602082015282518092526060810190602060608460051b83010194019261016051915b818310610d0e57505050505060208060019297019501910192919092610c7e565b9091929394602080610d56600193605f198682030189528951906040610d3d8351606084526060840190611894565b9285810151868401520151906040818403910152611894565b9701950193019190610ced565b610d8691935060203d602011610d8d575b610d7e81836116d5565b810190611a7b565b91886108e1565b503d610d74565b90506020823d602011610dc8575b81610daf602093836116d5565b8101031261014a57610dc2600492611a9a565b906108a8565b3d9150610da2565b610e4160018060a01b0360a0515116606060e0510151604060c051510151608060a05101519160405193610e038561166d565b845260018060a01b03881660208501526080516040850152606084015261016051608084015260a08301526101605160c083015260e0820152611ce6565b6101205152610817565b60e051602001516080516001600160a01b0390911614159250610812565b610e8391935060203d602011610d8d57610d7e81836116d5565b91836107ed565b60e0515160405163011ddaef60e71b81529260209184919082906001600160a01b03165afa80156103ad576101605190610ed2575b600492506001600160a01b0316906107b7565b50906020813d602011610f0f575b81610eed602093836116d5565b8101031261014a5751906001600160a01b038216820361014a57600491610ebf565b3d9150610ee0565b3d8061016051843e610f2981846116d5565b82019160208184031261014a578051906001600160401b03821161014a57016101c08184031261014a57604051906101c082018281106001600160401b0382111761039357604052610f7a81611a9a565b8252610f8860208201611a9a565b6020830152610f9960408201611a9a565b604083015260608101516060830152610fb460808201611a9a565b608083015260a081015160a0830152610fcf60c08201611a9a565b60c083015260e081015160e08301526101008101516101008301526101208101516101208301526110036101408201611a4b565b6101408301526101608101516101608301526101808101516101808301526101a0810151936001600160401b03851161014a576004946110439201611aae565b6101a082015260e05261078b565b6101605161105e916116d5565b83610748565b8251865260209586019587955090920191600101610726565b91939092949550606319888203018252845190815180825260208201906020808260051b850101940192610160515b8281106110cf5750505050506020806001929601920192018795949391926106fd565b90919293946020806110ed600193601f198782030189528951611894565b97019501939291016110ac565b611113915060203d602011610d8d57610d7e81836116d5565b866106ad565b5082516040516301ffc9a760e01b815263fabd349d60e01b600482015290602090829060249082906001600160a01b03165afa9081156103ad576101605191611163575b50610670565b90506020813d602011611195575b8161117e602093836116d5565b8101031261014a5761118f90611a4b565b8661115d565b3d9150611171565b90506020813d6020116111cf575b816111b8602093836116d5565b8101031261014a576111c990611a4b565b86610669565b3d91506111ab565b81358152602091820191016105c1565b83356001600160401b03811161014a5760049083010136603f8201121561014a5760208101356112168161173c565b9161122460405193846116d5565b8183526020808085019360051b830101019036821161014a5760408101925b82841061125d57505050908252506020938401930161054f565b83356001600160401b03811161014a5760209161128283928380369288010101611a0c565b815201930192611243565b3461014a57602036600319011261014a576004356001600160401b03811161014a57610140600319823603011261014a576040516112ca8161166d565b6112d6826004016116f6565b81526112e4602483016116f6565b9160208201928352604082019060448101358252611304606482016116f6565b906060840191825260808401946084820135865261132460a483016116f6565b9160a086019283526113393660c4830161170a565b9060c08701918252610124810135906001600160401b03821161014a57600461136592369201016117a5565b60e0870190815290611375611a2a565b5061137e611a2a565b95611387611a2a565b88516040516301ffc9a760e01b8152633d79d7fb60e11b600482015291979190602090829060249082906001600160a01b03165afa9081156103ad5761016051916115e0575b50806115cd575b806115ba575b806115a7575b156103bb578951156115955781511580159061157d575b1561156b57845181516114969b6001600160a01b03918216929091168281149391928415918280611556575b611520575b50506114bd575b5098519551945191519798610146986114a497611481976001600160a01b0391821697908216969095909491169261146e9291156114b2575190611a58565b91515192519360405195610b5f8761166d565b936040519586956060875260608701906118b9565b9085820360208701526118b9565b9083820360408501526118b9565b506101605190611a58565b61014699506114819694926114a49896949261151061146e938e60018060a01b039051169060018060a01b038b51169060018060a01b03905116845160208a510151918b519360405195610b5f8761166d565b9b5092949698509294965061142f565b8d51855189516040908101518c519151969f5061154e9695919490936001600160a01b0316610b5f8761166d565b988d80611428565b8b516001600160a01b03168314159350611423565b6040516396b154ab60e01b8152600490fd5b50845181516001600160a01b039081169116146113f7565b60405163511ff7fb60e11b8152600490fd5b5085516001600160a01b031615156113e0565b5080516001600160a01b031615156113da565b5084516001600160a01b031615156113d4565b90506020813d602011611612575b816115fb602093836116d5565b8101031261014a5761160c90611a4b565b8b6113cd565b3d91506115ee565b3461014a57602036600319011261014a576004359063ffffffff60e01b821680920361014a57602091635d7c7b9760e11b811490811561165c575b5015158152f35b6301ffc9a760e01b14905083611655565b61010081019081106001600160401b0382111761168957604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b0382111761168957604052565b604081019081106001600160401b0382111761168957604052565b90601f801991011681019081106001600160401b0382111761168957604052565b35906001600160a01b0382168203610c2a57565b9190826060910312610c2a576040516117228161169f565b604080829480358452602081013560208501520135910152565b6001600160401b0381116116895760051b60200190565b6001600160401b03811161168957601f01601f191660200190565b92919261177a82611753565b9161178860405193846116d5565b829481845281830111610c2a578281602093846000960137010152565b81601f82011215610c2a578035906117bc8261173c565b926117ca60405194856116d5565b82845260208085019360051b83010191818311610c2a5760208101935b8385106117f657505050505090565b84356001600160401b038111610c2a5782016040818503601f190112610c2a5760405191611823836116ba565b60208201356001600160401b038111610c2a576020908301019285601f85011215610c2a5760406020949361185e888688809835910161176e565b83520135838201528152019401936117e7565b60005b8381106118845750506000910152565b8181015183820152602001611874565b906020916118ad81518092818552858086019101611871565b601f01601f1916010190565b906040606082019280518352602081015160208401520151916060604083015282518091526080820191602060808360051b8301019401926000915b83831061190457505050505090565b9091929394607f1982820301835285519060206040820192805183520151916040602083015282518091526060820190602060608260051b85010194019260005b828110611966575050505050602080600192970193019301919392906118f5565b9091929394605f1983820301855285516020604083019160018060a01b0381511684520151916040602082015282518092526060810190602060608460051b8301019401926000915b8183106119d057505050505060208060019297019501910192919092611945565b90919293946020806119ff600193605f198682030189528951906040610d3d8351606084526060840190611894565b97019501930191906119af565b9080601f83011215610c2a57816020611a279335910161176e565b90565b60405190611a378261169f565b606060408360008152600060208201520152565b51908115158203610c2a57565b91908201809211611a6557565b634e487b7160e01b600052601160045260246000fd5b90816020910312610c2a57516001600160a01b0381168103610c2a5790565b51906001600160a01b0382168203610c2a57565b81601f82011215610c2a578051611ac481611753565b92611ad260405194856116d5565b81845260208284010111610c2a57611a279160208085019101611871565b91908203918211611a6557565b90611b078261173c565b611b1460405191826116d5565b8281528092611b25601f199161173c565b0190602036910137565b60005b828110611b3e57505050565b606082820152602001611b32565b90611b81611b598361173c565b611b6660405191826116d5565b83815260208194611b79601f199161173c565b019101611b2f565b565b805115611b905760200190565b634e487b7160e01b600052603260045260246000fd5b8051821015611b905760209160051b010190565b8115611bc4570490565b634e487b7160e01b600052601260045260246000fd5b90602082820312610c2a5781516001600160401b038111610c2a57611a279201611aae565b929593909594919460a084019660a085528051809852602060c0860191019760005b818110611c565750506001600160a01b0396871660208601526040850191909152941660608301521515608090910152909150565b89516001600160a01b031683526020998a019990920191600101611c21565b81810292918115918404141715611a6557565b81810392916000138015828513169184121617611a6557565b91909160008382019384129112908015821691151617611a6557565b6000198114611a655760010190565b60405190611cd9826116ba565b6060602083600081520152565b611cee611a2a565b60208201519091906001600160a01b0316151580612f95575b15612f8357602081015160408201805190916001600160a01b03918216911614612f715760a0820191825115612f5c576060810151835111612f4a576040519260c084018481106001600160401b03821117611689576040526000845260006020850152606060408501526000606085015260006080850152606060a085015260e08201515190611d978261173c565b91611da560405193846116d5565b808352611db4601f199161173c565b0160005b818110612f25575050518452611dd260e083015151611afd565b60a0850152611de560e083015151611b4c565b95606093611e2060405191611dfa87846116d5565b60028352601f19870136602085013760408801839052516001600160a01b031691611b83565b5260018060a01b036020840151166040860151805160011015611b90576040015260405193611e4e8561169f565b808552600060208601526000604086015260005b60e085015151811015612631578451604051633f4a2d2760e01b815290602090829060049082906001600160a01b03165afa9081156123fc57611ede91602091600091612614575b50611eb98460e08a0151611ba6565b515190604051808095819463657dcce560e01b83528660048401526024830190611894565b03916001600160a01b03165afa600091816125d9575b50611f0457506001905b01611e62565b8551604051633f4a2d2760e01b81529299939593949290602090829060049082906001600160a01b03165afa9081156123fc576004916020916000916125bc575b506040516391f03efd60e01b815292839182906001600160a01b03165afa9081156123fc5760009161257c575b506040516336dd6b3d60e01b81526001600160a01b03808416600483015290929160209184916024918391165afa9182156123fc57600092612549575b50611fc060608801518a5190611bba565b602089015260018060a01b038116604089015260408901519060046020611feb8d60e08c0151611ba6565b5101518951604051633f4a2d2760e01b81529194919260209184919082906001600160a01b03165afa9182156123fc5760049260209160009161252c575b506040516391f03efd60e01b815293849182906001600160a01b03165afa9182156123fc576000926124e9575b5060808a015160405163340f07ad60e11b8152946000948694859461208e941515936001600160a01b03909216929060048701611bff565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af49081156123fc576000916124c8575b5087528551604051633f4a2d2760e01b815290602090829060049082906001600160a01b03165afa9081156123fc576004916020916000916124ab575b506040516391f03efd60e01b815292839182906001600160a01b03165afa80156123fc57600090612471575b608088015161213b92501515906001600160a01b031689613036565b908a6000198314612461576121c96121cf926121a78c670de0b6b3a7640000948f8a61216f8f9260e0612186940151611ba6565b5161217f60608601518093611ba6565b528b611ba6565b5060606121938351611afd565b920151916121a18383611ba6565b52611ba6565b50806121bd8d606060a082015191015190611ba6565b5260c08a015190611c75565b04613121565b608089015260808601511515600014612445576121ee6121f991613121565b608089015190611ca1565b61221061220a60608a01518c611ba6565b51611b83565b5260015b87518110156124255760608601519060018101808211611a655761223d61224591600494611c75565b8a5190611bba565b6020898101919091528751604051633f4a2d2760e01b815293849182906001600160a01b03165afa9182156123fc57600492602091600091612408575b506040516391f03efd60e01b815293849182906001600160a01b03165afa80156123fc57888a91898e9560009261239f575b5060800180516001966123279487946123219492936122e092901515916001600160a01b031690613036565b90516000901561234c5750600019810361232e575060607d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000005b955b015190611ba6565b51611ba6565b5201612214565b61234761233c606092613121565b608088015190611ca1565b612317565b506000198103612381575060607fffff6f1bf04115e2c5b54376aa16b901ce32309909cb1f0000000000000000005b95612319565b61239a61238f606092613121565b608088015190611c88565b61237b565b949550509150506020823d82116123f4575b816123be602093836116d5565b810103126123f157509088612327826123218e8c6122e08d60806123e360019b611a9a565b9650509350509350956122b4565b80fd5b3d91506123b1565b6040513d6000823e3d90fd5b61241f9150823d8111610d8d57610d7e81836116d5565b38612282565b50919660019093919361243b6060890151611cbd565b6060890152611efe565b61245161245c91613121565b608089015190611c88565b6121f9565b5050509196600190939193611efe565b6020823d82116124a3575b81612489602093836116d5565b810103126123f1575061249e61213b91611a9a565b61211f565b3d915061247c565b6124c29150823d8111610d8d57610d7e81836116d5565b386120f3565b6124e3913d8091833e6124db81836116d5565b810190611bda565b386120b6565b90916020823d8211612524575b81612503602093836116d5565b810103126123f157509061208e61251c60009493611a9a565b929350612056565b3d91506124f6565b6125439150823d8111610d8d57610d7e81836116d5565b38612029565b90916020823d8211612574575b81612563602093836116d5565b810103126123f15750519038611faf565b3d9150612556565b906020823d82116125b4575b81612595602093836116d5565b810103126123f157509060206125ac602493611a9a565b919250611f72565b3d9150612588565b6125d39150823d8111610d8d57610d7e81836116d5565b38611f45565b90916020823d821161260c575b816125f3602093836116d5565b810103126123f1575061260590611a9a565b9038611ef4565b3d91506125e6565b61262b9150823d8111610d8d57610d7e81836116d5565b38611eaa565b50959290969350606085015115612f135761264f6060860151611afd565b60009061265f6060880151611b4c565b6101805260608701519761269c6126758a61173c565b996126836040519b8c6116d5565b808b52612692601f199161173c565b0160208b01611b2f565b60005b60608901518110156126fa576001906126b88a51611afd565b6126c58261018051611ba6565b526126d38161018051611ba6565b506126de8a51611afd565b6126e8828d611ba6565b526126f3818c611ba6565b500161269f565b50909192939497959860005b8a8951821015612738579061272081612321600194611b83565b516127318261232161018051611b83565b5201612706565b505095969793949291906001965b60608a01518810156128e75760005b8a518110156128db5788600019810111611a655761277e816123216000198c0161018051611ba6565b5160018201808311611a6557828b8f828f94836127a793612321926121a185612321858c611ba6565b5160808d0151156128d35784811280156128cb575b6128ae575b5050505060005b8281106127ec5750906001916127e5826123218d61018051611ba6565b5201612755565b908a600019810111611a65576128096000198c0161018051611ba6565b51916128158185611af0565b600019810193908411611a65578f8c8f928f968893612848876123218b61284161284f96608098611ba6565b5194611ba6565b5190611ca1565b910151156128a657848112801561289e575b612874575b5050506001919250016127c8565b6001945090612321612891929661288b8684611af0565b94611ba6565b528b9291508c8438612866565b508415612861565b848113612861565b93506000926128c1929161232191611ba6565b528a828b386127c1565b5084156127bc565b8481136127bc565b50600190970196612746565b9297965093909498979283519960005b606086015180821015612f01578c156129b3578161291491611af0565b9b8c600019810111611a655761292e6000198e018b611ba6565b5181600019810111611a6557612991916129798f8c61296e61296261295b61298597600019880190611ba6565b5186611af0565b91600019840190611ba6565b52600019018d611ba6565b51906000190190611ba6565b519c6000190189611ba6565b5161299f575b6001016128f7565b986129ab600191611cbd565b999050612997565b505094919792989399509495505b8115612ef65760409182516129d684826116d5565b60018152601f1984019060005b828110612edf5750848a01528351906129fc85836116d5565b6001825260005b818110612ec85750508351612a3891612a1b826116ba565b600182526020820152848a015190612a3282611b83565b52611b83565b5060208501516001600160a01b031691612a518261173c565b91612a5e855193846116d5565b808352612a6d601f199161173c565b019060005b828110612ea05750505090612aaf91835191612a8d836116ba565b825260208201526020612aa2848a0151611b83565b51015190612a3282611b83565b5060005b6060890151811015612e9657612ac98187611ba6565b5115612e8e57612ad98187611ba6565b5190612ae58187611ba6565b515160408b015186518551633f4a2d2760e01b815291949190602090829060049082906001600160a01b03165afa908115612dc657612b599291602091600091612e71575b50612b35868c611ba6565b5151908851808096819463657dcce560e01b83528660048401526024830190611894565b03916001600160a01b03165afa918215612dc657600092612e36575b506020612b82858b611ba6565b51015188518751633f4a2d2760e01b815291939190602090829060049082906001600160a01b03165afa908115612e0e57600491602091600091612e19575b5089516391f03efd60e01b815292839182906001600160a01b03165afa908115612e0e57600091612dd1575b5060808a018051895163340f07ad60e11b81529198919560009487948594612c28941515936001600160a01b03909216929060048701611bff565b03817399d511a76a84cb71c87b8d8de4a00cfb952af1915af4918215612dc6576020612c80888e612c9b97968496612c8896600092612dab575b50835198612c6f8a61169f565b895285890152828801520151611b83565b510151611b83565b51015160208d0151916121a18383611ba6565b50612ca960208b0151611cbd565b60208b01528960208901612ccd612cc68460a08451950151611ba6565b5183611a58565b918210612d9a5752612cdf8185611ba6565b51612cea8289611ba6565b51600019810193908411611a655782612d08600195612d2694611ba6565b518d8c51936000908315600014612d2f575050505050600090611a58565b88525b01612ab3565b51159050612d6f57670de0b6b3a76400006121c9612d57612d699560a0612d63950151611ba6565b5160c08d015190611c75565b90611c88565b90611a58565b670de0b6b3a76400006121c9612d57612d959560a0612d8f950151611ba6565b90611ca1565b612d69565b630a77254f60e01b60005260046000fd5b612dbf91923d8091833e6124db81836116d5565b9038612c62565b86513d6000823e3d90fd5b906020823d8211612e06575b81612dea602093836116d5565b810103126123f1575090612dff600092611a9a565b9091612bed565b3d9150612ddd565b88513d6000823e3d90fd5b612e309150823d8111610d8d57610d7e81836116d5565b38612bc1565b90916020823d8211612e69575b81612e50602093836116d5565b810103126123f15750612e6290611a9a565b9038612b75565b3d9150612e43565b612e889150823d8111610d8d57610d7e81836116d5565b38612b2a565b600190612d29565b5050505050509150565b6020908651612eae8161169f565b838152600083820152838882015282828701015201612a72565b602090612ed3611ccc565b82828601015201612a03565b602090612eea611ccc565b828285010152016129e3565b509496505050505050565b505094919792989399509495506129c1565b60405163af16b31b60e01b8152600490fd5b602090604051612f34816116ba565b6060815260008382015282828701015201611db8565b604051631edbd19360e11b8152600490fd5b6040516001622c3a8160e21b03198152600490fd5b604051635c6726db60e11b8152600490fd5b604051632638e39360e11b8152600490fd5b5060408101516001600160a01b03161515611d07565b90606082820312610c2a5780601f83011215610c2a5760405191612fce8361169f565b829060608101928311610c2a57905b828210612fea5750505090565b8151815260209182019101612fdd565b60208152606061301583518260208501526080840190611894565b6020840151604084810191909152909301516001600160a01b031691015290565b6060916000936130ba576130609160405194858094819363eb5251a560e01b835260048301612ffa565b03926001600160a01b03165af160009181613089575b50613082575060001990565b6020015190565b6130ac91925060603d6060116130b3575b6130a481836116d5565b810190612fab565b9038613076565b503d61309a565b6130da91604051948580948193630fafa65f60e11b835260048301612ffa565b03926001600160a01b03165af160009181613100575b506130fc575060001990565b5190565b61311a91925060603d6060116130b3576130a481836116d5565b90386130f0565b6001600160ff1b0381116131325790565b60405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608490fdfea26469706673582212208bc6ece5c0061678c9ef873bc1292314cbd6083e0eb03abe384ecda6f7ead42864736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.