MarginTrading.sol
This contract allows users to manage margin accounts, provide collateral, borrow, and repay tokens.
How to Interact with a Margin Account directly
Below, you will find the functions needed to interact with a margin account. In most cases, you will need to know the margin account ID, which is a unique number assigned to each created margin account. To understand how to obtain this number, please refer to this page.
How To Deposit Collateral (UDSC, WBTC, ETH)
To borrow funds from the liquidity pools, users must provide collateral tokens (USDC, WBTC, or ETH). We use Chainlink price feeds to calculate the value of your collateral in USDC.
function provideERC20(uint marginAccountID, address token, uint amount) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
marginAccount.provideERC20(marginAccountID, msg.sender, token, amount);
emit ProvideERC20(marginAccountID, msg.sender, token, amount);
}
How to Deposit American-style options (Hegic Option Position)
function provideERC721(uint marginAccountID, address token, uint collateralTokenID) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
require(modularSwapRouter.checkValidityERC721(token, BASE_TOKEN, collateralTokenID), "token id is not valid");
marginAccount.provideERC721(marginAccountID, msg.sender, token, collateralTokenID);
emit ProvideERC721(marginAccountID, msg.sender, token, collateralTokenID);
}
How To Withdraw Collateral (USDC, WBTC, ETH)
When withdrawing collateral from a margin account, the following criteria must be met:
portfolioRatio > yellowCoeff
The yellowCoeff
may change, so to get the actual number, please check beginning of this contract
uint public yellowCoeff = 1.10 * 1e5;
function withdrawERC20(uint marginAccountID, address token, uint amount) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
require(marginAccount.checkERC20Amount(marginAccountID, token, amount), "Insufficient token balance for withdrawal");
uint marginAccountValue = calculateMarginAccountValue(marginAccountID);
uint withdrawSizeInBaseToken = modularSwapRouter.calculatePositionValue(token, BASE_TOKEN, amount);
marginAccountValue -= withdrawSizeInBaseToken;
uint debtWithAccruedInterest = calculateDebtWithAccruedInterest(marginAccountID);
uint portfolioRatio = _calculatePortfolioRatio(marginAccountValue, debtWithAccruedInterest);
require(portfolioRatio > yellowCoeff, "portfolioRatio is too low");
marginAccount.withdrawERC20(marginAccountID, token, amount, msg.sender);
emit WithdrawERC20(marginAccountID, msg.sender, token, amount);
}
How to Withdraw American-style option (Hegic Option Position)
function withdrawERC721(uint marginAccountID, address token, uint value) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
require(marginAccount.checkERC721Value(marginAccountID, token, value), "The ERC721 token you are attempting to withdraw is not available for withdrawal");
uint marginAccountValue = calculateMarginAccountValue(marginAccountID);
uint withdrawSizeInBaseToken = modularSwapRouter.calculateAmountOutERC721(token, BASE_TOKEN, value);
marginAccountValue -= withdrawSizeInBaseToken;
uint debtWithAccruedInterest = calculateDebtWithAccruedInterest(marginAccountID);
uint portfolioRatio = _calculatePortfolioRatio(marginAccountValue, debtWithAccruedInterest);
require(portfolioRatio > yellowCoeff, "portfolioRatio is too low");
marginAccount.withdrawERC721(marginAccountID, token, value, msg.sender);
emit WithdrawERC721(marginAccountID, msg.sender, token, value);
}
How to Borrow (USDC, WBTC, ETH)
function borrow(uint marginAccountID, address token, uint amount) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
require(marginAccount.checkLiquidityPool(token), "Token is not supported");
uint amountInBaseToken = modularSwapRouter.calculatePositionValue(token, BASE_TOKEN, amount);
uint marginAccountValue = calculateMarginAccountValue(marginAccountID);
uint debtWithAccruedInterest = calculateDebtWithAccruedInterest(marginAccountID);
uint marginAccountRatio = _calculatePortfolioRatio(marginAccountValue + amountInBaseToken, debtWithAccruedInterest + amountInBaseToken);
require(marginAccountRatio >= yellowCoeff, "Cannot borrow more; margin account ratio is too high");
marginAccount.borrow(marginAccountID, token, amount);
emit Borrow(marginAccountID, msg.sender, token, amount);
}
How to Repay
function repay(uint marginAccountID, address token, uint amount) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
marginAccount.repay(marginAccountID, token, amount);
emit Repay(marginAccountID, msg.sender, token, amount);
}
How to swap tokens
When a trader makes a swap, it is routed through Uniswap v3.
function swap(uint marginAccountID, address tokenIn, address tokenOut, uint amountIn, uint amountOutMinimum) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
uint marginAccountValue = calculateMarginAccountValue(marginAccountID);
uint debtWithAccruedInterest = calculateDebtWithAccruedInterest(marginAccountID);
uint marginAccountRatio = _calculatePortfolioRatio(marginAccountValue, debtWithAccruedInterest);
require(marginAccountRatio >= redCoeff, "Cannot swap");
emit Swap(marginAccountID, swapID, tokenIn, tokenOut, amountIn);
marginAccount.swap(marginAccountID, swapID, tokenIn, tokenOut, amountIn, amountOutMinimum);
swapID++;
}
How to exercise American-style option (Hegic Option Position)
function exercise(uint marginAccountID, address token, uint collateralTokenID) external nonReentrant onlyApprovedOrOwner(marginAccountID) {
require(marginAccount.checkERC721Value(marginAccountID, token, collateralTokenID), "You are not allowed to execute this ERC721 token");
marginAccount.exercise(marginAccountID, token, BASE_TOKEN, collateralTokenID, msg.sender);
emit Exercise(marginAccountID, token, BASE_TOKEN, collateralTokenID);
}
How to get the current margin account value in USDC
function calculateMarginAccountValue(uint marginAccountID) public returns (uint marginAccountValue) {
(
IModularSwapRouter.ERC20PositionInfo[] memory erc20Params,
IModularSwapRouter.ERC721PositionInfo[] memory erc721Params
) = prepareTokensParams(marginAccountID, BASE_TOKEN);
marginAccountValue = modularSwapRouter.calculateTotalPositionValue(erc20Params,erc721Params);
}
How to get the current debt across all liquidity pools in USDC (borrowed amount + interest to be paid)
function calculateDebtWithAccruedInterest(uint marginAccountID) public returns (uint debtSizeInUSDC) {
(
IModularSwapRouter.ERC20PositionInfo[] memory erc20Params,
IModularSwapRouter.ERC721PositionInfo[] memory erc721Params
) = prepareTokensParamsByDebt(marginAccountID, BASE_TOKEN);
debtSizeInUSDC += modularSwapRouter.calculateTotalPositionValue(erc20Params, erc721Params);
}
How to get the current margin ratio
function getMarginAccountRatio(uint marginAccountID) public returns(uint) {
uint marginAccountValue = calculateMarginAccountValue(marginAccountID);
uint debtWithAccruedInterest = calculateDebtWithAccruedInterest(marginAccountID);
return _calculatePortfolioRatio(marginAccountValue, debtWithAccruedInterest);
}
Last updated