Rebalancer
Inherits: Ownable2Step, ReentrancyGuard, ERC165, IOwnershipCallback, IRebalancer, EIP712
The goal of this contract is to push the imbalance of the USDN protocol back to an healthy level when liquidations reduce long trading exposure. It will manage a single position with sufficient trading exposure to re-balance the protocol after liquidations. The position will be closed and reopened as needed, utilizing new and existing funds, whenever the imbalance reaches a defined threshold.
State Variables
MULTIPLIER_FACTOR
Gets the value of the multiplier at 1x.
Also helps to normalize the result of multiplier calculations.
uint256 public constant MULTIPLIER_FACTOR = 1e38;
MAX_ACTION_COOLDOWN
The maximum cooldown time between actions.
uint256 public constant MAX_ACTION_COOLDOWN = 48 hours;
MAX_CLOSE_DELAY
Gets the maximum amount of seconds to wait to execute a initiateClosePosition since a new rebalancer long position has been created.
uint256 public constant MAX_CLOSE_DELAY = 7 days;
INITIATE_CLOSE_TYPEHASH
The EIP712 initiateClosePosition typehash.
By including this hash into the EIP712 message for this domain, this can be used together with ECDSA-recover to obtain the signer of a message.
bytes32 public constant INITIATE_CLOSE_TYPEHASH = keccak256(
"InitiateClosePositionDelegation(uint88 amount,address to,uint256 userMinPrice,uint256 deadline,address depositOwner,address depositCloser,uint256 nonce)"
);
_asset
The address of the asset used by the USDN protocol.
IERC20Metadata internal immutable _asset;
_assetDecimals
The number of decimals of the asset used by the USDN protocol.
uint256 internal immutable _assetDecimals;
_usdnProtocol
The address of the USDN protocol.
IUsdnProtocol internal immutable _usdnProtocol;
_maxLeverage
The maximum leverage that a position can have.
uint256 internal _maxLeverage = 3 * 10 ** Constants.LEVERAGE_DECIMALS;
_minAssetDeposit
The minimum amount of assets to be deposited by a user.
uint256 internal _minAssetDeposit;
_closeLockedUntil
The timestamp by which a user must wait to perform a initiateClosePosition.
This value will be updated each time a new rebalancer long position is created.
uint256 internal _closeLockedUntil;
_timeLimits
The time limits for the initiate/validate process of deposits and withdrawals.
The user must wait validationDelay
after the initiate action to perform the corresponding validate
action. If the validationDeadline
has passed, the user is blocked from interacting until the cooldown duration
has elapsed (since the moment of the initiate action). After the cooldown, in case of a deposit action, the user
must withdraw their funds with resetDepositAssets
. After the cooldown, in case of a withdrawal action, the user
can initiate a new withdrawal again.
TimeLimits internal _timeLimits = TimeLimits({
validationDelay: 24 seconds,
validationDeadline: 20 minutes,
actionCooldown: 4 hours,
closeDelay: 4 hours
});
_positionVersion
The current position version.
uint128 internal _positionVersion;
_pendingAssetsAmount
The amount of assets waiting to be used in the next version of the position.
uint128 internal _pendingAssetsAmount;
_lastLiquidatedVersion
The version of the last position that got liquidated.
uint128 internal _lastLiquidatedVersion;
_userDeposit
The data about the assets deposited in this contract by users.
mapping(address => UserDeposit) internal _userDeposit;
_positionData
The data for the specific version of the position.
mapping(uint256 => PositionData) internal _positionData;
_nonce
The user EIP712 nonce.
Check getNonce for more information.
mapping(address => uint256) internal _nonce;
Functions
onlyAdmin
Reverts if the caller is not the USDN protocol nor the owner.
modifier onlyAdmin();
onlyProtocol
Reverts if the caller is not the USDN protocol.
modifier onlyProtocol();
constructor
constructor(IUsdnProtocol usdnProtocol) Ownable(msg.sender) EIP712("Rebalancer", "1");
Parameters
Name | Type | Description |
---|---|---|
usdnProtocol | IUsdnProtocol | The address of the USDN protocol. |
receive
Allows this contract to receive ether sent by the USDN protocol.
receive() external payable onlyProtocol;
getAsset
Returns the address of the asset used by the USDN protocol.
function getAsset() external view returns (IERC20Metadata asset_);
Returns
Name | Type | Description |
---|---|---|
asset_ | IERC20Metadata | The address of the asset used by the USDN protocol. |
getUsdnProtocol
Returns the address of the USDN protocol.
function getUsdnProtocol() external view returns (IUsdnProtocol protocol_);
Returns
Name | Type | Description |
---|---|---|
protocol_ | IUsdnProtocol | The address of the USDN protocol. |
getPendingAssetsAmount
Returns the amount of assets deposited and waiting for the next version to be opened.
function getPendingAssetsAmount() external view returns (uint128 pendingAssetsAmount_);
Returns
Name | Type | Description |
---|---|---|
pendingAssetsAmount_ | uint128 | The amount of pending assets. |
getPositionVersion
Returns the version of the current position (0 means no position open).
function getPositionVersion() external view returns (uint128 version_);
Returns
Name | Type | Description |
---|---|---|
version_ | uint128 | The version of the current position. |
getPositionMaxLeverage
Returns the maximum leverage the rebalancer position can have.
In some edge cases during the calculation of the rebalancer position's tick, this value might be exceeded by a slight margin.
function getPositionMaxLeverage() external view returns (uint256 maxLeverage_);
Returns
Name | Type | Description |
---|---|---|
maxLeverage_ | uint256 | The maximum leverage. |
getCurrentStateData
Returns the necessary data for the USDN protocol to update the position.
function getCurrentStateData()
external
view
returns (uint128 pendingAssets_, uint256 maxLeverage_, Types.PositionId memory currentPosId_);
Returns
Name | Type | Description |
---|---|---|
pendingAssets_ | uint128 | The amount of assets that are pending inclusion in the protocol. |
maxLeverage_ | uint256 | The maximum leverage of the rebalancer. |
currentPosId_ | Types.PositionId | The ID of the current position (tick == NO_POSITION_TICK if no position). |
getLastLiquidatedVersion
Returns the version of the last position that got liquidated.
0 means no liquidated version yet.
function getLastLiquidatedVersion() external view returns (uint128 version_);
Returns
Name | Type | Description |
---|---|---|
version_ | uint128 | The version of the last position that got liquidated. |
getMinAssetDeposit
Returns the minimum amount of assets a user can deposit in the rebalancer.
function getMinAssetDeposit() external view returns (uint256 minAssetDeposit_);
Returns
Name | Type | Description |
---|---|---|
minAssetDeposit_ | uint256 | The minimum amount of assets that can be deposited by a user. |
getPositionData
Returns the data of the provided version of the position.
function getPositionData(uint128 version) external view returns (PositionData memory positionData_);
Parameters
Name | Type | Description |
---|---|---|
version | uint128 | The version of the position. |
Returns
Name | Type | Description |
---|---|---|
positionData_ | PositionData | The data for the provided version of the position. |
getTimeLimits
Gets the time limits for the action validation process.
function getTimeLimits() external view returns (TimeLimits memory timeLimits_);
Returns
Name | Type | Description |
---|---|---|
timeLimits_ | TimeLimits | The time limits. |
getUserDepositData
Returns the data regarding the assets deposited by the provided user.
function getUserDepositData(address user) external view returns (UserDeposit memory data_);
Parameters
Name | Type | Description |
---|---|---|
user | address | The address of the user. |
Returns
Name | Type | Description |
---|---|---|
data_ | UserDeposit | The data regarding the assets deposited by the provided user. |
getNonce
Gets the nonce a user can use to generate a delegation signature.
This is to prevent replay attacks when using an EIP712 delegation signature.
function getNonce(address user) external view returns (uint256 nonce_);
Parameters
Name | Type | Description |
---|---|---|
user | address | The user address of the deposited amount in the rebalancer. |
Returns
Name | Type | Description |
---|---|---|
nonce_ | uint256 | The user's nonce. |
domainSeparatorV4
Gets the domain separator v4 used for EIP-712 signatures.
function domainSeparatorV4() external view returns (bytes32 domainSeparator_);
Returns
Name | Type | Description |
---|---|---|
domainSeparator_ | bytes32 | The domain separator v4. |
getCloseLockedUntil
Gets the timestamp by which a user must wait to perform a initiateClosePosition.
function getCloseLockedUntil() external view returns (uint256 timestamp_);
Returns
Name | Type | Description |
---|---|---|
timestamp_ | uint256 | The timestamp until which the position cannot be closed. |
increaseAssetAllowance
Increases the allowance of assets for the USDN protocol spender by addAllowance
.
function increaseAssetAllowance(uint256 addAllowance) external;
Parameters
Name | Type | Description |
---|---|---|
addAllowance | uint256 | Amount to add to the allowance of the USDN Protocol. |
initiateDepositAssets
Deposits assets into this contract to be included in the next position after validation
The user must call validateDepositAssets between _timeLimits.validationDelay
and.
_timeLimits.validationDeadline
seconds after this action.
function initiateDepositAssets(uint88 amount, address to) external nonReentrant;
Parameters
Name | Type | Description |
---|---|---|
amount | uint88 | The amount in assets that will be deposited into the rebalancer. |
to | address | The address which will need to validate and which will own the position. |
validateDepositAssets
Validates a deposit to be included in the next position version.
The to
from the initiateDepositAssets
must call this function between _timeLimits.validationDelay
and
_timeLimits.validationDeadline
seconds after the initiate action. After that, the user must wait until
_timeLimits.actionCooldown
seconds has elapsed, and then can call resetDepositAssets
to retrieve their
assets.
function validateDepositAssets() external nonReentrant;
resetDepositAssets
Retrieves the assets for a failed deposit due to waiting too long before calling validateDepositAssets.
The user must wait _timeLimits.actionCooldown
since the initiateDepositAssets before calling this
function.
function resetDepositAssets() external nonReentrant;
initiateWithdrawAssets
Withdraws assets that were not yet included in a position.
The user must call validateWithdrawAssets between _timeLimits.validationDelay
and
_timeLimits.validationDeadline
seconds after this action.
function initiateWithdrawAssets() external nonReentrant;
validateWithdrawAssets
Validates a withdrawal of assets that were not yet included in a position.
The user must call this function between _timeLimits.validationDelay
and _timeLimits.validationDeadline
seconds after initiateWithdrawAssets. After that, the user must wait until the cooldown has elapsed, and then
can call initiateWithdrawAssets again or wait to be included in the next position.
function validateWithdrawAssets(uint88 amount, address to) external nonReentrant;
Parameters
Name | Type | Description |
---|---|---|
amount | uint88 | The amount of assets to withdraw. |
to | address | The recipient of the assets. |
initiateClosePosition
Closes the provided amount from the current rebalancer's position.
The rebalancer allows partially closing its position to withdraw the user's assets + PnL.
The remaining amount needs to be above _minAssetDeposit
. The validator is always the msg.sender
, which means
the user must call validateClosePosition
on the protocol side after calling this function.
function initiateClosePosition(
uint88 amount,
address to,
address payable validator,
uint256 userMinPrice,
uint256 deadline,
bytes calldata currentPriceData,
Types.PreviousActionsData calldata previousActionsData,
bytes calldata delegationData
) external payable nonReentrant returns (Types.LongActionOutcome outcome_);
Parameters
Name | Type | Description |
---|---|---|
amount | uint88 | The amount to close relative to the amount deposited. |
to | address | The recipient of the assets. |
validator | address payable | The address that should validate the open position. |
userMinPrice | uint256 | The minimum price at which the position can be closed. |
deadline | uint256 | The deadline of the close position to be initiated. |
currentPriceData | bytes | The current price data. |
previousActionsData | Types.PreviousActionsData | The data needed to validate actionable pending actions. |
delegationData | bytes | An optional delegation data that include the depositOwner and an EIP712 signature to provide when closing a position on the owner's behalf. If used, it needs to be encoded with abi.encode(depositOwner, abi.encodePacked(r, s, v)) . |
Returns
Name | Type | Description |
---|---|---|
outcome_ | Types.LongActionOutcome | The outcome of the UsdnProtocol's initiateClosePosition call, check initiateClosePosition for more details. |
_refundEther
Refunds any ether in this contract to the caller.
This contract should not hold any ether so any sent to it belongs to the current caller.
function _refundEther() internal;
updatePosition
Indicates that the previous version of the position was closed and a new one was opened.
If previousPosValue
equals 0, it means the previous version got liquidated.
function updatePosition(Types.PositionId calldata newPosId, uint128 previousPosValue)
external
onlyProtocol
nonReentrant;
Parameters
Name | Type | Description |
---|---|---|
newPosId | Types.PositionId | The position ID of the new position. |
previousPosValue | uint128 | The amount of assets left in the previous position. |
setPositionMaxLeverage
Updates the max leverage a position can have.
newMaxLeverage
must be between the min and max leverage of the USDN protocol.
This function can only be called by the owner of the contract.
function setPositionMaxLeverage(uint256 newMaxLeverage) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
newMaxLeverage | uint256 | The new max leverage. |
setMinAssetDeposit
Sets the minimum amount of assets to be deposited by a user.
The new minimum amount must be greater than or equal to the minimum long position of the USDN protocol. This function can only be called by the owner or the USDN protocol.
function setMinAssetDeposit(uint256 minAssetDeposit) external onlyAdmin;
Parameters
Name | Type | Description |
---|---|---|
minAssetDeposit | uint256 | The new minimum amount of assets to be deposited. |
setTimeLimits
Sets the various time limits in seconds.
This function can only be called by the owner of the contract.
function setTimeLimits(uint64 validationDelay, uint64 validationDeadline, uint64 actionCooldown, uint64 closeDelay)
external
onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
validationDelay | uint64 | The amount of time to wait before an initiate can be validated. |
validationDeadline | uint64 | The amount of time a user has to validate an initiate. |
actionCooldown | uint64 | The amount of time to wait after the deadline has passed before trying again. |
closeDelay | uint64 | The close delay that will be applied to the next long position opening. |
ownershipCallback
Called by the USDN protocol on the new position owner after an ownership transfer occurs.
Implementers can use this callback to perform actions triggered by the ownership change.
function ownershipCallback(address, Types.PositionId calldata) external pure;
Parameters
Name | Type | Description |
---|---|---|
<none> | address | |
<none> | Types.PositionId |
supportsInterface
Query if a contract implements an interface
Interface identification is specified in ERC-165. This function uses less than 30,000 gas.
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC165, IERC165)
returns (bool isSupported_);
Parameters
Name | Type | Description |
---|---|---|
interfaceId | bytes4 |
Returns
Name | Type | Description |
---|---|---|
isSupported_ | bool | true if the contract implements interfaceID and interfaceID is not 0xffffffff, false otherwise |
_checkValidationTime
Checks if the validate action happens between the validation delay and the validation deadline.
If the block timestamp is before initiateTimestamp
+ validationDelay
, the function will revert.
If the block timestamp is after initiateTimestamp
+ validationDeadline
, the function will revert.
function _checkValidationTime(uint40 initiateTimestamp) internal view;
Parameters
Name | Type | Description |
---|---|---|
initiateTimestamp | uint40 | The timestamp of the initiate action. |
_verifyInitiateCloseDelegation
Performs the initiateClosePosition EIP712 delegation signature verification.
Reverts if the function arguments don't match those included in the signature and if the signer isn't the owner of the deposit.
function _verifyInitiateCloseDelegation(
uint88 amount,
address to,
uint256 userMinPrice,
uint256 deadline,
bytes calldata delegationData
) internal returns (address depositOwner_);
Parameters
Name | Type | Description |
---|---|---|
amount | uint88 | The amount to close relative to the amount deposited. |
to | address | The recipient of the assets. |
userMinPrice | uint256 | The minimum price at which the position can be closed, not guaranteed. |
deadline | uint256 | The deadline of the close position to be initiated. |
delegationData | bytes | The delegation data that should include the depositOwner and the delegation signature. |
Returns
Name | Type | Description |
---|---|---|
depositOwner_ | address | The owner of the assets deposited in the rebalancer. |
_initiateClosePosition
Closes a user deposited amount of the current UsdnProtocol rebalancer position.
function _initiateClosePosition(
InitiateCloseData memory data,
bytes calldata currentPriceData,
Types.PreviousActionsData calldata previousActionsData,
bytes calldata delegationData
) internal returns (Types.LongActionOutcome outcome_);
Parameters
Name | Type | Description |
---|---|---|
data | InitiateCloseData | The structure to hold the transient data during initiateClosePosition. |
currentPriceData | bytes | The current price data (used to calculate the temporary leverage and entry price, pending validation). |
previousActionsData | Types.PreviousActionsData | The data needed to validate actionable pending actions. |
delegationData | bytes | An optional delegation data that include the depositOwner and an EIP712 signature to provide when closing a position on the owner's behalf. |
Returns
Name | Type | Description |
---|---|---|
outcome_ | Types.LongActionOutcome | The outcome of the initiateClosePosition call to the USDN protocol. |
Structs
InitiateCloseData
Structure to hold the transient data during initiateClosePosition.
struct InitiateCloseData {
UserDeposit userDepositData;
uint88 remainingAssets;
uint256 positionVersion;
PositionData currentPositionData;
uint256 amountToCloseWithoutBonus;
uint256 amountToClose;
Types.Position protocolPosition;
address user;
uint256 balanceOfAssetBefore;
uint256 balanceOfAssetAfter;
uint88 amount;
address to;
address payable validator;
uint256 userMinPrice;
uint256 deadline;
uint256 closeLockedUntil;
}
Properties
Name | Type | Description |
---|---|---|
userDepositData | UserDeposit | The user deposit data. |
remainingAssets | uint88 | The remaining rebalancer assets. |
positionVersion | uint256 | The current rebalancer position version. |
currentPositionData | PositionData | The current rebalancer position data. |
amountToCloseWithoutBonus | uint256 | The user amount to close without bonus. |
amountToClose | uint256 | The user amount to close including bonus. |
protocolPosition | Types.Position | The protocol rebalancer position. |
user | address | The address of the user that deposited the funds in the rebalancer. |
balanceOfAssetBefore | uint256 | The balance of asset before the USDN protocol's initiateClosePosition. |
balanceOfAssetAfter | uint256 | The balance of asset after the USDN protocol's initiateClosePosition. |
amount | uint88 | The amount to close relative to the amount deposited. |
to | address | The recipient of the assets. |
validator | address payable | The address that should validate the open position. |
userMinPrice | uint256 | The minimum price at which the position can be closed. |
deadline | uint256 | The deadline of the close position to be initiated. |
closeLockedUntil | uint256 | The timestamp by which a user must wait to perform a initiateClosePosition. |