Managing Borrow Positions

Moving assets between positions and opening/closing borrow positions is easy with the BorrowPositionRouter. You can find the address on the Smart Contract Addresses page.

Transferring Assets

library AccountBalanceLib {
    /// Checks that either BOTH, FROM, or TO accounts do not have negative balances
    enum BalanceCheckFlag {
        Both,
        From,
        To,
        None
    }
}

/**
 * @param _isolationModeMarketId    The market ID of the isolation mode token
 *                                  (0 if not using isolation mode)
 * @param _fromAccountNumber        The source account number
 * @param _toAccountNumber          The destination account number
 * @param _marketId                 The ID of the market to transfer
 * @param _amount                   The amount to transfer
 * @param _balanceCheckFlag         Flag indicating how to validate account balances
 */
function transferBetweenAccounts(
    uint256 _isolationModeMarketId,
    uint256 _fromAccountNumber,
    uint256 _toAccountNumber,
    uint256 _marketId,
    uint256 _amount,
    AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag
) external;

This function is used to transfer assets between accounts. For non-isolation mode assets, set the isolationModeMarketId to 0 and fill in the rest of the necessary information. For isolation-mode assets, isolationModeMarketId is the market ID of the vault and marketId is the market ID of the asset that will be transferred.

For isolation-mode transfers, we restrict transfers in the following ways:

  • The underlying isolation mode asset can only be transferred between the default account number and a non-default account number. For example, transferring from account number 0 to account number 123 is valid, but transferring from account number 123 to account number 150 would revert.

  • For all other assets within an isolation mode vault position, transfers can go from the owner to the vault or from the vault back to the owner. Transfers cannot be made within the vault. The direction of the transfer is determined by the fromAccountNumber and the toAccountNumber. If the fromAccountNumber is < 100 and the toAccoutNumber is >= 100, funds will go from the user's account to the isolation mode vault. If the fromAccountNumber is >= 100 and the toAccountNumber is < 100, funds will go from the isolation mode vault to the user's account.

Examples

Transferring 100 USDC from user's account number 0 to user's account number 123 while confirming that account number 0 does not go negative:

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));

BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ 0,
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

Transferring 100 GLP from the isolation mode vault default account to account number 123:

address dfsGlp = 0x34DF4E8062A8C8Ae97E3382B452bd7BF60542698;
uint256 marketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(dfsGlp); 
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ marketId,
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ marketId,
    /* _amount = */ 100 ether,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

Transferring 100 USDC from the user's account number 0 to their isolation mode account number 123:

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));
address dfsGlp = 0x34DF4E8062A8C8Ae97E3382B452bd7BF60542698;
uint256 glpMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(dfsGlp);
 
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ glpMarketId,
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.None
);

Transferring 100 USDC from isolation mode account number 123 to the user's account number 0:

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));
address dfsGlp = 0x34DF4E8062A8C8Ae97E3382B452bd7BF60542698;
uint256 glpMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(dfsGlp);
 
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ glpMarketId,
    /* _fromAccountNumber = */ 123,
    /* _toAccountNumber = */ 0,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

Opening a Borrow Position

library AccountBalanceLib {
    /// Checks that either BOTH, FROM, or TO accounts do not have negative balances
    enum BalanceCheckFlag {
        Both,
        From,
        To,
        None
    }
}

/**
 * @param _fromAccountNumber    The account number to transfer assets from
 * @param _toAccountNumber      The account number for the new borrow position
 * @param _marketId             The ID of the market to transfer collateral
 * @param _amount               The amount of collateral to transfer into the borrow
 *                              position
 * @param _balanceCheckFlag     Flag indicating how to validate account balances
 */
function openBorrowPosition(
    uint256 _fromAccountNumber,
    uint256 _toAccountNumber,
    uint256 _marketId,
    uint256 _amount,
    AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag
) external;

Examples

A user has 10 WETH in their default account (account number 0) and they want to open a borrow position with 1 WETH as collateral and then borrow 100 USDC against it.

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));
uint256 wethMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(weth));

// This call to openBorrowPosition will transfer 1 WETH from account number 0
// to account number 123.
BorrowPositionRouter.openBorrowPosition(
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ wethMarketId,
    /* _amount = */ 1 ether,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

// This call to transferBetweenAccounts will transfer 100 USDC from account number
// 123 to account number 0. Account number 123 will now have 1 WETH and -100 USDC
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ 0,
    /* _fromAccountNumber = */ 123,
    /* _toAccountNumber = */ 0,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.To
);

A user has 10 GLP in their default isolation mode account and they want to open a borrow position with 1 GLP as collateral and borrow 100 USDC against it.

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));
address dfsGlp = 0x34DF4E8062A8C8Ae97E3382B452bd7BF60542698;
uint256 glpMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(dfsGlp);

// This call to openBorrowPosition will transfer 1 GLP from account number 0
// to account number 123.
BorrowPositionRouter.openBorrowPosition(
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ glpMarketId,
    /* _amount = */ 1 ether,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

// This call to transferBetweenAccounts will transfer 100 USDC from account number
// 123 of the isolation mode vault to account number 0 for the user. 
// Account number 123 of the isolation mode vault will have 1 GLP and -100 USDC
// Account number 0 for the user will have +100 USDC
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ glpMarketId,
    /* _fromAccountNumber = */ 123,
    /* _toAccountNumber = */ 0,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.To
);

Closing a Borrow Position

library AccountBalanceLib {
    /// Checks that either BOTH, FROM, or TO accounts do not have negative balances
    enum BalanceCheckFlag {
        Both,
        From,
        To,
        None
    }
}

/**
 * @param _isolationModeMarketId    The market ID of the isolation mode token (0 if not using isolation mode)
 * @param _fromAccountNumber        The account number containing repayment funds
 * @param _borrowAccountNumber      The account number containing the borrow position
 * @param _marketId                 The ID of the market to repay
 * @param _balanceCheckFlag         Flag indicating how to validate account balances
 */
function repayAllForBorrowPosition(
    uint256 _isolationModeMarketId,
    uint256 _fromAccountNumber,
    uint256 _borrowAccountNumber,
    uint256 _marketId,
    AccountBalanceLib.BalanceCheckFlag _balanceCheckFlag
) external;

/**
 * @param _isolationModeMarketId  The market ID of the isolation mode token
 *                                (0 if not using isolation mode)
 * @param _borrowAccountNumber    The account number containing the borrow position
 * @param _toAccountNumber        The account number to send remaining collateral to
 * @param _collateralMarketIds    Array of market IDs for collateral to be returned
 */
function closeBorrowPosition(
    uint256 _isolationModeMarketId,
    uint256 _borrowAccountNumber,
    uint256 _toAccountNumber,
    uint256[] calldata _collateralMarketIds
) external;

Examples

Continuing from the example above where a user has 1 WETH collateral in account number 123 and borrowed 100 USDC. The user will now pay back the 100 USDC from account number 0 and close the borrow position.

uint256 usdcMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(usdc));
uint256 wethMarketId = DOLOMITE_MARGIN.getMarketIdByTokenAddress(address(weth));

// This call to openBorrowPosition will transfer 1 WETH from account number 0
// to account number 123.
BorrowPositionRouter.openBorrowPosition(
    /* _fromAccountNumber = */ 0,
    /* _toAccountNumber = */ 123,
    /* _marketId = */ wethMarketId,
    /* _amount = */ 1 ether,
    /* _balanceCheckFlag = */ BalanceCheckFlag.From
);

// This call to transferBetweenAccounts will transfer 100 USDC from account number
// 123 to account number 0. Account number 123 will have 1 WETH and -100 USDC
BorrowPositionRouter.transferBetweenAccounts(
    /* _isolationModeMarketId = */ 0,
    /* _fromAccountNumber = */ 123,
    /* _toAccountNumber = */ 0,
    /* _marketId = */ usdcMarketId,
    /* _amount = */ 100e6,
    /* _balanceCheckFlag = */ BalanceCheckFlag.To
);

// This call will transfer 100 USDC from account number 0 to account number 123
// to pay back the loan. In reality, it would be greater than 100 because interest
BorrowPositionRouter.repayAllForBorrowPosition(
    /* isolationModeMarketId = */ 0,
    /* fromAccountNumber = */ 0,
    /* borrowAccountNumber = */ 123,
    /* marketId = */ usdcMarketId,
    /* balanceCheckFlag = */ BalanceCheckFlag.From
);

// This call will close the borrow position and transfer the 1 WETH of collateral
// back to account number 0
BorrowPositionRouter.closeBorrowPosition(
    /* isolationModeMarketId = */ 0,
    /* borrowAccountNumber = */ 123,
    /* toAccountNumber = */ 0,
    /* collateralMarketIds = */ [wethMarketId],
);

Last updated