Rebalancer

Git Source

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

NameTypeDescription
usdnProtocolIUsdnProtocolThe 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

NameTypeDescription
asset_IERC20MetadataThe 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

NameTypeDescription
protocol_IUsdnProtocolThe 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

NameTypeDescription
pendingAssetsAmount_uint128The 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

NameTypeDescription
version_uint128The 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

NameTypeDescription
maxLeverage_uint256The 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

NameTypeDescription
pendingAssets_uint128The amount of assets that are pending inclusion in the protocol.
maxLeverage_uint256The maximum leverage of the rebalancer.
currentPosId_Types.PositionIdThe 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

NameTypeDescription
version_uint128The 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

NameTypeDescription
minAssetDeposit_uint256The 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

NameTypeDescription
versionuint128The version of the position.

Returns

NameTypeDescription
positionData_PositionDataThe 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

NameTypeDescription
timeLimits_TimeLimitsThe 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

NameTypeDescription
useraddressThe address of the user.

Returns

NameTypeDescription
data_UserDepositThe 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

NameTypeDescription
useraddressThe user address of the deposited amount in the rebalancer.

Returns

NameTypeDescription
nonce_uint256The user's nonce.

domainSeparatorV4

Gets the domain separator v4 used for EIP-712 signatures.

function domainSeparatorV4() external view returns (bytes32 domainSeparator_);

Returns

NameTypeDescription
domainSeparator_bytes32The 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

NameTypeDescription
timestamp_uint256The 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

NameTypeDescription
addAllowanceuint256Amount 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

NameTypeDescription
amountuint88The amount in assets that will be deposited into the rebalancer.
toaddressThe 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

NameTypeDescription
amountuint88The amount of assets to withdraw.
toaddressThe 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

NameTypeDescription
amountuint88The amount to close relative to the amount deposited.
toaddressThe recipient of the assets.
validatoraddress payableThe address that should validate the open position.
userMinPriceuint256The minimum price at which the position can be closed.
deadlineuint256The deadline of the close position to be initiated.
currentPriceDatabytesThe current price data.
previousActionsDataTypes.PreviousActionsDataThe data needed to validate actionable pending actions.
delegationDatabytesAn 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

NameTypeDescription
outcome_Types.LongActionOutcomeThe 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

NameTypeDescription
newPosIdTypes.PositionIdThe position ID of the new position.
previousPosValueuint128The 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

NameTypeDescription
newMaxLeverageuint256The 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

NameTypeDescription
minAssetDeposituint256The 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

NameTypeDescription
validationDelayuint64The amount of time to wait before an initiate can be validated.
validationDeadlineuint64The amount of time a user has to validate an initiate.
actionCooldownuint64The amount of time to wait after the deadline has passed before trying again.
closeDelayuint64The 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

NameTypeDescription
<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

NameTypeDescription
interfaceIdbytes4

Returns

NameTypeDescription
isSupported_booltrue 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

NameTypeDescription
initiateTimestampuint40The 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

NameTypeDescription
amountuint88The amount to close relative to the amount deposited.
toaddressThe recipient of the assets.
userMinPriceuint256The minimum price at which the position can be closed, not guaranteed.
deadlineuint256The deadline of the close position to be initiated.
delegationDatabytesThe delegation data that should include the depositOwner and the delegation signature.

Returns

NameTypeDescription
depositOwner_addressThe 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

NameTypeDescription
dataInitiateCloseDataThe structure to hold the transient data during initiateClosePosition.
currentPriceDatabytesThe current price data (used to calculate the temporary leverage and entry price, pending validation).
previousActionsDataTypes.PreviousActionsDataThe data needed to validate actionable pending actions.
delegationDatabytesAn optional delegation data that include the depositOwner and an EIP712 signature to provide when closing a position on the owner's behalf.

Returns

NameTypeDescription
outcome_Types.LongActionOutcomeThe 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

NameTypeDescription
userDepositDataUserDepositThe user deposit data.
remainingAssetsuint88The remaining rebalancer assets.
positionVersionuint256The current rebalancer position version.
currentPositionDataPositionDataThe current rebalancer position data.
amountToCloseWithoutBonusuint256The user amount to close without bonus.
amountToCloseuint256The user amount to close including bonus.
protocolPositionTypes.PositionThe protocol rebalancer position.
useraddressThe address of the user that deposited the funds in the rebalancer.
balanceOfAssetBeforeuint256The balance of asset before the USDN protocol's initiateClosePosition.
balanceOfAssetAfteruint256The balance of asset after the USDN protocol's initiateClosePosition.
amountuint88The amount to close relative to the amount deposited.
toaddressThe recipient of the assets.
validatoraddress payableThe address that should validate the open position.
userMinPriceuint256The minimum price at which the position can be closed.
deadlineuint256The deadline of the close position to be initiated.
closeLockedUntiluint256The timestamp by which a user must wait to perform a initiateClosePosition.