Skip to content

Instantly share code, notes, and snippets.

@sunnyRK
Created December 28, 2021 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sunnyRK/11f8179974c16d2f23f54bcaaa6d9331 to your computer and use it in GitHub Desktop.
Save sunnyRK/11f8179974c16d2f23f54bcaaa6d9331 to your computer and use it in GitHub Desktop.
const { ethers } = require("hardhat");
const { expect, use } = require("chai");
const {solidity} = require('ethereum-waffle');
const { utils } = require('ethers');
const { parseEther, parseUnits } = require("ethers/lib/utils")
const { BigNumber } = require("@ethersproject/bignumber")
const { loadPerpLushanInfo, snapshot, revertToSnapshot, fromBigNumber } = require("./utils");
const bn = require("bignumber.js");
bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 })
const ClearingHouseAbi = require('../perp-lushan/artifacts/contracts/test/TestClearingHouse.sol/TestClearingHouse.json')
const OrderBookAbi = require('../perp-lushan/artifacts/contracts/OrderBook.sol/OrderBook.json')
const ClearingHouseConfigAbi = require('../perp-lushan/artifacts/contracts/ClearingHouseConfig.sol/ClearingHouseConfig.json')
const VaultAbi = require('../perp-lushan/artifacts/contracts/Vault.sol/Vault.json')
const ExchangeAbi = require('../perp-lushan/artifacts/contracts/Exchange.sol/Exchange.json')
const MarketRegistryAbi = require('../perp-lushan/artifacts/contracts/MarketRegistry.sol/MarketRegistry.json')
const TestERC20Abi = require('../perp-lushan/artifacts/contracts/test/TestERC20.sol/TestERC20.json')
const BaseTokenAbi = require('../perp-lushan/artifacts/contracts/BaseToken.sol/BaseToken.json')
const BaseToken2Abi = require('../perp-lushan/artifacts/contracts/BaseToken.sol/BaseToken.json')
const QuoteTokenAbi = require('../perp-lushan/artifacts/contracts/QuoteToken.sol/QuoteToken.json')
const AccountBalanceAbi = require('../perp-lushan/artifacts/contracts/AccountBalance.sol/AccountBalance.json')
const MockTestAggregatorV3Abi = require('../perp-lushan/artifacts/contracts/mock/MockTestAggregatorV3.sol/MockTestAggregatorV3.json')
const UniswapV3PoolAbi = require('../perp-lushan/artifacts/@uniswap/v3-core/contracts/UniswapV3Pool.sol/UniswapV3Pool.json')
const UniswapV3Pool2Abi = require('../perp-lushan/artifacts/@uniswap/v3-core/contracts/UniswapV3Pool.sol/UniswapV3Pool.json');
const QuoterAbi = require('../perp-lushan/artifacts/@uniswap/v3-periphery/contracts/lens/Quoter.sol/Quoter.json')
const UniswapV3FactoryAbi = require('../perp-lushan/artifacts/@uniswap/v3-core/contracts/UniswapV3Factory.sol/UniswapV3Factory.json');
use(solidity);
function encodePriceSqrt(reserve1, reserve0) {
return BigNumber.from(
new bn(reserve1.toString())
.div(reserve0.toString())
.sqrt()
.multipliedBy(new bn(2).pow(96))
.integerValue(3)
.toString(),
)
}
function getMinTick(tickSpacing) {
Math.ceil(-887272 / tickSpacing) * tickSpacing
}
function getMaxTick(tickSpacing) {
Math.floor(887272 / tickSpacing) * tickSpacing
}
describe("perpLemma2", async function () {
let defaultSigner, usdLemma, reBalancer, hasWETH, keeperGasReward, signer1, signer2, usdl2;
let perpAddresses;
const ZERO = BigNumber.from("0");
let snapshotId;
let clearingHouse
let marketRegistry
let clearingHouseConfig
let exchange
let orderBook
let accountBalance
let vault
let collateral
let baseToken
let baseToken2
let quoteToken
let univ3factory
let pool
let pool2
let mockedBaseAggregator
let mockedBaseAggregator2
let quoter
let perpLemma
let collateralDecimals
// const lowerTick = 0
// const upperTick = 100000
before(async function () {
[defaultSigner, usdLemma, reBalancer, hasWETH, signer1, signer2, usdl2] = await ethers.getSigners();
perpAddresses = await loadPerpLushanInfo();
clearingHouse = new ethers.Contract(perpAddresses.clearingHouse.address, ClearingHouseAbi.abi, defaultSigner)
orderBook = new ethers.Contract(perpAddresses.orderBook.address, OrderBookAbi.abi, defaultSigner);
clearingHouseConfig = new ethers.Contract(perpAddresses.clearingHouseConfig.address, ClearingHouseConfigAbi.abi, defaultSigner);
vault = new ethers.Contract(perpAddresses.vault.address, VaultAbi.abi, defaultSigner);
exchange = new ethers.Contract(perpAddresses.exchange.address, ExchangeAbi.abi, defaultSigner);
marketRegistry = new ethers.Contract(perpAddresses.marketRegistry.address, MarketRegistryAbi.abi, defaultSigner);
collateral = new ethers.Contract(perpAddresses.collateral.address, TestERC20Abi.abi, defaultSigner);
baseToken = new ethers.Contract(perpAddresses.baseToken.address, BaseTokenAbi.abi, defaultSigner);
baseToken2 = new ethers.Contract(perpAddresses.baseToken2.address, BaseToken2Abi.abi, defaultSigner);
quoteToken = new ethers.Contract(perpAddresses.quoteToken.address, QuoteTokenAbi.abi, defaultSigner);
univ3factory = new ethers.Contract(perpAddresses.univ3factory.address, UniswapV3FactoryAbi.abi, defaultSigner)
accountBalance = new ethers.Contract(perpAddresses.accountBalance.address, AccountBalanceAbi.abi, defaultSigner);
mockedBaseAggregator = new ethers.Contract(perpAddresses.mockedBaseAggregator.address, MockTestAggregatorV3Abi.abi, defaultSigner);
mockedBaseAggregator2 = new ethers.Contract(perpAddresses.mockedBaseAggregator2.address, MockTestAggregatorV3Abi.abi, defaultSigner);
pool = new ethers.Contract(perpAddresses.pool.address, UniswapV3PoolAbi.abi, defaultSigner);
pool2 = new ethers.Contract(perpAddresses.pool2.address, UniswapV3Pool2Abi.abi, defaultSigner);
quoter = new ethers.Contract(perpAddresses.quoter.address, QuoterAbi.abi, defaultSigner)
collateralDecimals = await collateral.decimals()
const maxPosition = ethers.constants.MaxUint256;
const perpLemmaFactory = await ethers.getContractFactory("PerpLemma")
perpLemma = await upgrades.deployProxy(perpLemmaFactory,
[
collateral.address,
quoteToken.address, // vUSD
baseToken.address,
quoteToken.address,
clearingHouse.address,
vault.address,
accountBalance.address,
quoter.address,
usdLemma.address,
maxPosition
], { initializer: 'initialize' });
await perpLemma.connect(signer1).resetApprovals()
await mockedBaseAggregator.setLatestRoundData(0, parseUnits("100", collateralDecimals), 0, 0, 0)
await pool.initialize(encodePriceSqrt("100", "1"))
// the initial number of oracle can be recorded is 1; thus, have to expand it
await pool.increaseObservationCardinalityNext((2 ^ 16) - 1)
// await pool2.initialize(encodePriceSqrt("100", "1")) // tick = 50200 (1.0001^50200 = 151.373306858723226652)
await marketRegistry.addPool(baseToken.address, 10000)
// await marketRegistry.addPool(baseToken2.address, 10000)
await marketRegistry.setFeeRatio(baseToken.address, 10000)
// await marketRegistry.setFeeRatio(baseToken2.address, 10000)
// prepare collateral for maker
const makerCollateralAmount = parseUnits("1000000", collateralDecimals)
await collateral.mint(signer1.address, makerCollateralAmount)
await collateral.mint(signer2.address, makerCollateralAmount)
const parsedAmount = parseUnits("100000", collateralDecimals)
await collateral.connect(signer1).approve(vault.address, ethers.constants.MaxUint256)
await collateral.connect(signer2).approve(vault.address, ethers.constants.MaxUint256)
// Deposit into vault
// await vault.connect(signer1).deposit(collateral.address, parsedAmount)
await vault.connect(signer2).deposit(collateral.address, parsedAmount)
await clearingHouse.connect(signer2).addLiquidity({
baseToken: baseToken.address,
base: parseEther('100'),
quote: parseEther('10000'),
lowerTick: -887200, //50000,
upperTick: 887200, //50400,
minBase: 0,
minQuote: 0,
useTakerBalance: false,
deadline: ethers.constants.MaxUint256,
})
})
beforeEach(async function () {
snapshotId = await snapshot();
});
afterEach(async function () {
await revertToSnapshot(snapshotId);
});
describe("OpenPosition with getCollateralAmountGivenUnderlyingAssetAmount", () => {
let collateralmintAmount, collateralAmount, parsedAmount, leveragedAmount, collateralToGetBack_1e18, collateralToGetBack_1e6
beforeEach(async function () {
collateralmintAmount = parseUnits("1000", collateralDecimals) // 6 decimal
collateralToGetBack_1e18 = await perpLemma.callStatic.getCollateralAmountGivenUnderlyingAssetAmount(parseEther('1'), true)
collateralToGetBack_1e6 = collateralToGetBack_1e18.mul(parseUnits('1', collateralDecimals)).div(parseEther('1'))
console.log('collateralToGetBack_1e18 & collateralToGetBack_1e6: ', collateralToGetBack_1e18.toString(), collateralToGetBack_1e6.toString())
await collateral.mint(usdLemma.address, collateralmintAmount)
const balIntial = await collateral.balanceOf(usdLemma.address)
console.log('\nbalIntial: ', balIntial.toString())
});
it("openPosition => emit event PositionChanged", async () => {
const bal0 = await collateral.balanceOf(usdLemma.address)
console.log('\nbal0: ', bal0.toString())
await collateral.connect(usdLemma).transfer(
perpLemma.address,
collateralToGetBack_1e6
)
const accountValue_Before = await clearingHouse.getAccountValue(perpLemma.address)
console.log('accountValue-Before: ', accountValue_Before.toString())
await perpLemma.connect(usdLemma).open(
parseEther('1'),
collateralToGetBack_1e6
)
const accountValue = await clearingHouse.getAccountValue(perpLemma.address)
const marginRequirementForLiquidation = await accountBalance.getMarginRequirementForLiquidation(perpLemma.address)
console.log('accountValue: ', accountValue.toString())
console.log('marginRequirementForLiquidation: ', marginRequirementForLiquidation.toString())
// const mmRatio = await clearingHouseConfig.getMmRatio()
// const imRatio = await clearingHouseConfig.getImRatio()
// const ratioforMm0 = await vault.getFreeCollateralByRatio(perpLemma.address, 0)
// const ratioforMm = await vault.getFreeCollateralByRatio(perpLemma.address, mmRatio)
// const ratioforIm = await vault.getFreeCollateralByRatio(perpLemma.address, imRatio)
// console.log('\nmmRatio & ratioforMm', mmRatio.toString(), ratioforMm.toString())
// console.log('imRatio & ratioforIm', imRatio.toString(), ratioforIm.toString())
// console.log('ratioforMm0', ratioforMm0.toString())
let getBalance = await vault.getBalance(perpLemma.address)
console.log('\ngetBalance: ', getBalance.toString())
const getPnlAndPendingFee = await accountBalance.getPnlAndPendingFee(perpLemma.address)
console.log('getPnlAndPendingFee: ', getPnlAndPendingFee.toString())
const getBase = await accountBalance.getBase(perpLemma.address, baseToken.address)
console.log('getBase: ', getBase.toString())
const getQuote = await accountBalance.getQuote(perpLemma.address, baseToken.address)
console.log('getQuote: ', getQuote.toString())
const bal1 = await collateral.balanceOf(usdLemma.address)
console.log('\nbal1: ', bal1.toString())
let positionValue = await accountBalance.getTotalPositionValue(perpLemma.address, baseToken.address)
console.log('\npositionValue: ', positionValue.toString())
let positionSize = await accountBalance.getTotalPositionSize(perpLemma.address, baseToken.address)
console.log('\positionSize: ', positionSize.toString())
let collateralToGetBackToClose_1e18 = await perpLemma.callStatic
.getCollateralAmountGivenUnderlyingAssetAmount(getQuote,false)
console.log('\ncollateralToGetBackToClose_1e18: ', collateralToGetBackToClose_1e18.toString()) // get eth by long
const collateralToGetBackToClose_1e6 = collateralToGetBackToClose_1e18.mul(parseUnits('1', collateralDecimals)).div(parseUnits('1', 16))
console.log('collateralToGetBackToClose_1e6: ', collateralToGetBackToClose_1e6.toString())
let collateralToGetBackToClose_1e18_1 = await perpLemma.callStatic
.getCollateralAmountGivenUnderlyingAssetAmount(getBase.mul(-1), true)
console.log('\collateralToGetBackToClose_1e18_1: ', collateralToGetBackToClose_1e18_1.toString()) // get eth by long
let collateralToGetBackToClose_1e6_1 = collateralToGetBackToClose_1e18_1.mul(parseUnits('1', collateralDecimals)).div(parseEther('1'))
console.log('collateralToGetBackToClose_1e6_1: ', collateralToGetBackToClose_1e6_1.toString())
let collateralToGetBackToClose_1e18_getBlance = await perpLemma.callStatic
.getCollateralAmountGivenUnderlyingAssetAmount(
getBalance.mul(parseEther('1')).div(parseUnits('1', collateralDecimals)),
false
)
console.log('\collateralToGetBackToClose_1e18_getBlance: ', collateralToGetBackToClose_1e18_getBlance.toString()) // get eth by long
const collateralToGetBackToClose_1e6_getBlance = collateralToGetBackToClose_1e18_getBlance.mul(parseUnits('1', collateralDecimals)).div(parseEther('1'))
console.log('collateralToGetBackToClose_1e6_getBlance: ', collateralToGetBackToClose_1e6_getBlance.toString())
const [baseBalanceAfter, quoteBalanceAfter] = await clearingHouse.getTokenBalance(
perpLemma.address,
baseToken.address,
)
console.log('baseBalanceAfter: ', baseBalanceAfter.toString())
console.log('quoteBalanceAfter: ', quoteBalanceAfter.toString())
const acc = accountValue.mul(parseUnits('1', 6)).div(parseEther('1'))
console.log('acc: ', acc.toString())
const getPnlAndPendingFee1 = await accountBalance.getPnlAndPendingFee(perpLemma.address)
console.log('getPnlAndPendingFee1: ', getPnlAndPendingFee1.toString())
await expect(perpLemma.connect(usdLemma).close(
getQuote,
collateralToGetBackToClose_1e6
)).to.emit(clearingHouse, 'PositionChanged')
const getPnlAndPendingFee2 = await accountBalance.getPnlAndPendingFee(perpLemma.address)
console.log('getPnlAndPendingFee2: ', getPnlAndPendingFee2.toString())
positionSize = await accountBalance.getTotalPositionSize(perpLemma.address, baseToken.address)
console.log('\positionSize: ', positionSize.toString())
let ratioforMm1 = await vault.getFreeCollateralByRatio(perpLemma.address, 0)
console.log('ratioforMm1', ratioforMm1.toString())
let bal2 = await collateral.balanceOf(usdLemma.address)
console.log('\nbal2: ', bal2.toString())
let positionValue2 = await accountBalance.getTotalPositionValue(perpLemma.address, baseToken.address)
console.log('last positionValue: ', positionValue2.toString())
getBalance = await vault.getBalance(perpLemma.address)
console.log('\ngetBalance: ', getBalance.toString())
collateralToGetBackToClose_1e18_1 = await perpLemma.callStatic
.getCollateralAmountGivenUnderlyingAssetAmount(getBase.mul(-1), true)
console.log('\collateralToGetBackToClose_1e18_1: ', collateralToGetBackToClose_1e18_1.toString()) // get eth by long
collateralToGetBackToClose_1e6_1 = collateralToGetBackToClose_1e18_1.mul(parseUnits('1', collateralDecimals)).div(parseEther('1'))
console.log('collateralToGetBackToClose_1e6_1: ', collateralToGetBackToClose_1e6_1.toString())
// await expect(perpLemma.connect(usdLemma).close(
// parseEther('0.1'),
// BigNumber.from('0')
// )).to.emit(clearingHouse, 'PositionChanged')
// positionSize = await accountBalance.getTotalPositionSize(perpLemma.address, baseToken.address)
// console.log('\positionSize: ', positionSize.toString())
// ratioforMm1 = await vault.getFreeCollateralByRatio(perpLemma.address, 0)
// console.log('ratioforMm1', ratioforMm1.toString())
// bal2 = await collateral.balanceOf(usdLemma.address)
// console.log('\nbal2: ', bal2.toString())
// positionValue2 = await accountBalance.getTotalPositionValue(perpLemma.address, baseToken.address)
// console.log('last positionValue: ', positionValue2.toString())
// getBalance = await vault.getBalance(perpLemma.address)
// console.log('\ngetBalance: ', getBalance.toString())
});
})
})
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.8.3;
// pragma abicoder v2;
import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import { ERC2771ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/metatx/ERC2771ContextUpgradeable.sol";
import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import { IPerpetualDEXWrapper } from "../interfaces/IPerpetualDEXWrapper.sol";
import { Utils } from "../libraries/Utils.sol";
import { SafeMathExt } from "../libraries/SafeMathExt.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "../libraries/TransferHelper.sol";
import "../interfaces/Perpetual/IClearingHouse.sol";
import "../interfaces/Perpetual/IAccountBalance.sol";
import "../interfaces/UniswapV3/IQuoter.sol";
import "hardhat/console.sol";
interface IPerpVault {
function deposit(address token, uint256 amount) external;
function withdraw(address token, uint256 amountX10_D) external;
function _getBalance(address trader, address token) external view returns (int256);
function decimals() external view returns (uint8);
}
interface IUSDLemma {
function lemmaTreasury() external view returns (address);
}
contract PerpLemma is OwnableUpgradeable, ERC2771ContextUpgradeable, IPerpetualDEXWrapper {
using SafeCastUpgradeable for uint256;
using SafeCastUpgradeable for int256;
using Utils for int256;
using SafeMathExt for int256;
bytes32 public HashZero;
uint256 public constant MAX_UINT256 = type(uint256).max;
int256 public constant MAX_INT256 = type(int256).max;
address public usdLemma;
address public reBalancer;
address public baseTokenAddress;
address public quoteTokenAddress;
bytes32 public referrerCode;
IERC20Upgradeable public usd; // ETH
IERC20Upgradeable public collateral; // ETH
uint256 public collateralDecimals;
IClearingHouse public iClearingHouse;
IPerpVault public iPerpVault;
IAccountBalance public iAccountBalance;
IQuoter public iUniV3Router;
uint256 public maxPosition;
//events
event USDLemmaUpdated(address usdlAddress);
event ReferrerUpdated(bytes32 referrerCode);
event RebalancerUpdated(address rebalancerAddress);
event MaxPositionUpdated(uint256 maxPos);
function initialize(
address _collateral,
address _usd,
address _baseToken,
address _quoteToken,
address _iClearingHouse,
address _iPerpVault,
address _iAccountBalance,
address _iUniV3Router,
address _usdLemma,
uint256 _maxPosition
) public initializer {
__Ownable_init();
usdLemma = _usdLemma;
maxPosition = _maxPosition;
baseTokenAddress = _baseToken;
quoteTokenAddress = _quoteToken;
collateral = IERC20Upgradeable(_collateral);
usd = IERC20Upgradeable(_usd);
iClearingHouse = IClearingHouse(_iClearingHouse);
iPerpVault = IPerpVault(_iPerpVault);
iUniV3Router = IQuoter(_iUniV3Router);
iAccountBalance = IAccountBalance(_iAccountBalance);
collateralDecimals = iPerpVault.decimals(); // need to verify
collateral.approve(_iClearingHouse, MAX_UINT256);
}
///@notice sets USDLemma address - only owner can set
///@param _usdlemma USDLemma address to set
function setUSDLemma(address _usdlemma) public onlyOwner {
usdLemma = _usdlemma;
emit USDLemmaUpdated(usdLemma);
}
///@notice sets refferer address - only owner can set
///@param _referrerCode referrerCode of address to set
function setReferrerCode(bytes32 _referrerCode) external onlyOwner {
referrerCode = _referrerCode;
emit ReferrerUpdated(referrerCode);
}
///@notice sets reBalncer address - only owner can set
///@param _reBalancer reBalancer address to set
function setReBalancer(address _reBalancer) public onlyOwner {
reBalancer = _reBalancer;
emit RebalancerUpdated(reBalancer);
}
///@param _maxPosition reBalancer address to set
function setMaxPosition(uint256 _maxPosition) public onlyOwner {
maxPosition = _maxPosition;
emit MaxPositionUpdated(maxPosition);
}
/// @notice reset approvals
function resetApprovals() external {
SafeERC20Upgradeable.safeApprove(collateral, address(iPerpVault), 0);
SafeERC20Upgradeable.safeApprove(collateral, address(iPerpVault), MAX_UINT256);
}
//this needs to be done before the first withdrawal happens
//Keeper gas reward needs to be handled seperately which owner can get back when perpetual has settled
/// @notice Deposit Keeper gas reward for the perpetual - only owner can call
function depositKeeperGasReward() external onlyOwner {
}
//go short to open
/// @notice Open short position on dex and deposit collateral
/// @param amount worth in USD short position which is to be opened
/// @param collateralAmountRequired collateral amount required to open the position
function open(uint256 amount, uint256 collateralAmountRequired) external override {
require(_msgSender() == usdLemma, "only usdLemma is allowed");
// require(
// collateral.balanceOf(address(this)) >= getAmountInCollateralDecimals(collateralAmountRequired, true),
// "not enough collateral"
// );
iPerpVault.deposit(address(collateral), collateralAmountRequired);
int256 positionSize = iAccountBalance.getTotalPositionValue(address(this), baseTokenAddress);
require(positionSize.abs().toUint256() + amount <= maxPosition, "max position reached");
// create short position by giving isBaseToQuote=true
// and amount in eth(baseToken) by giving isExactInput=true
IClearingHouse.OpenPositionParams memory params = IClearingHouse.OpenPositionParams({
baseToken: baseTokenAddress,
isBaseToQuote: true,
isExactInput: true,
amount: amount,
oppositeAmountBound: 0,
deadline: MAX_UINT256,
sqrtPriceLimitX96: 0,
referralCode: bytes32(0)
});
(uint256 base, uint256 quote) = iClearingHouse.openPosition(params);
console.log('base: ', base);
console.log('quote: ', quote);
// needs to updateEntryFunding() call (need to implement)
}
function close(uint256 amount, uint256 collateralAmountToGetBack) external override {
require(_msgSender() == usdLemma, "only usdLemma is allowed");
// int256 positionSize = IAccountBalance(address(iAccountBalance)).getPositionSize(address(this), baseTokenAddress);
// require (positionSize != 0);
int256 accountValue = iClearingHouse.getAccountValue(address(this)); // get Total account value
console.log('accountValue-close-first: ', uint256(accountValue));
// create long position by giving isBaseToQuote=false
// and amount in eth(baseToken) by giving isExactInput=false
IClearingHouse.OpenPositionParams memory params = IClearingHouse.OpenPositionParams({
baseToken: baseTokenAddress,
isBaseToQuote: false,
isExactInput: true,
amount: amount,
oppositeAmountBound: 0,
deadline: MAX_UINT256,
sqrtPriceLimitX96: 0,
referralCode: bytes32(0)
});
(uint256 base, uint256 quote) = iClearingHouse.openPosition(params);
console.log('base-close: ', base);
console.log('quote-close: ', quote);
accountValue = iClearingHouse.getAccountValue(address(this)); // get Total account value
console.log('accountValue-close-before: ', uint256(accountValue));
int256 getTotalPositionValue = iAccountBalance.getTotalPositionValue(address(this), baseTokenAddress); // get current position value
console.log('getTotalPositionValue-close: ', uint256(getTotalPositionValue.abs()));
// get closed account value and convert from 1e18 to 1e6(bcuz collateral in 1e6)
int256 closedAccontValue = ((accountValue - getTotalPositionValue.abs()) * 1e6) / 1e18;
console.log('closedAccontValue-close-after: ', uint256(closedAccontValue));
(int256 a,int256 b,uint256 c) = iAccountBalance.getPnlAndPendingFee(address(this)); // get current position value
console.log('a-close: ', uint256(a));
console.log('b-close: ', uint256(b));
console.log('c-close: ', uint256(c));
console.log('collateralAmountToGetBack-close-before: ', collateralAmountToGetBack);
if (a > 0) {
console.log('Positive');
a = (a*1e6)/1e18;
collateralAmountToGetBack = collateralAmountToGetBack + uint256(a);
} else {
console.log('Negative');
a = a.abs();
a = (a*1e6)/1e18;
console.log('a-abs', uint256(a));
collateralAmountToGetBack = collateralAmountToGetBack - uint256(a);
}
console.log('collateralAmountToGetBack-close-after: ', collateralAmountToGetBack);
iPerpVault.withdraw(
address(collateral),
collateralAmountToGetBack
// uint256(closedAccontValue)
); // withdraw closed position fund
// // needs to updateEntryFunding() call
SafeERC20Upgradeable.safeTransfer(
collateral,
usdLemma,
collateralAmountToGetBack
// uint256(closedAccontValue)
);
// // *** when getCollateralAmountGivenUnderlyingAssetAmount ready we will use collateralAmountToGetBack instead amount i guess
// -> iPerpVault.withdraw(address(collateral), collateralAmountToGetBack);
// // *** needs to updateEntryFunding() call (need to implement)
// -> SafeERC20Upgradeable.safeTransfer(
// collateral,
// usdLemma,
// getAmountInCollateralDecimals(collateralAmountToGetBack, false)
// );
}
function getCollateralAmountGivenUnderlyingAssetAmount(uint256 amount, bool isShorting)
external
override
returns (uint256 collateralAmountRequired)
{
// TODO: K-Aizen Implement
address tokenIn;
address tokenOut;
uint24 fee = 10000;
uint160 sqrtPriceLimitX96 = 0;
if (isShorting) {
tokenIn = address(baseTokenAddress);
tokenOut = address(quoteTokenAddress);
// Need to deposit `collateralAmountRequired` of collateral to mint `amount` USD
collateralAmountRequired = iUniV3Router.quoteExactInputSingle(
tokenIn, // token in
tokenOut, // token out
fee,
amount,
sqrtPriceLimitX96
);
} else {
tokenIn = address(quoteTokenAddress);
tokenOut = address(baseTokenAddress);
// Burning `amount` USD we get `collateralAmountRequired` collateral
collateralAmountRequired = iUniV3Router.quoteExactInputSingle(
tokenIn,
tokenOut,
fee,
amount,
sqrtPriceLimitX96
);
}
}
/// @notice Rebalance position of dex based on accumulated funding, since last rebalancing
/// @param _reBalancer Address of rebalancer who called function on USDL contract
/// @param amount Amount of accumulated funding fees used to rebalance by opening or closing a short position
/// @param data Abi encoded data to call respective perpetual function, contains limitPrice and deadline
/// @return True if successful, False if unsuccessful
function reBalance(
address _reBalancer,
int256 amount,
bytes calldata data
) external override returns (bool) {
require(_msgSender() == usdLemma, "only usdLemma is allowed");
require(_reBalancer == reBalancer, "only rebalancer is allowed");
(uint160 _sqrtPriceLimitX96, uint256 _deadline) = abi.decode(data, (uint160, uint256));
bool _isBaseToQuote;
bool _isExactInput;
if (amount > 0) {
// open long position and amount in usd
_isBaseToQuote = false;
_isExactInput = true;
} else {
// open short position and amount in usd
_isBaseToQuote = true;
_isExactInput = false;
}
IClearingHouse.OpenPositionParams memory params = IClearingHouse.OpenPositionParams({
baseToken: baseTokenAddress,
isBaseToQuote: _isBaseToQuote,
isExactInput: _isExactInput,
amount: uint256(amount.abs()),
oppositeAmountBound: 0,
deadline: _deadline,
sqrtPriceLimitX96: _sqrtPriceLimitX96,
referralCode: referrerCode
});
iClearingHouse.openPosition(params);
return true;
}
/// @notice Get Amount in collateral decimals, provided amount is in 18 decimals
/// @param amount Amount in 18 decimals
/// @param roundUp If needs to round up
/// @return decimal adjusted value
function getAmountInCollateralDecimals(uint256 amount, bool roundUp) public view override returns (uint256) {
if (roundUp && (amount % (uint256(10**(18 - collateralDecimals))) != 0)) {
return amount / uint256(10**(18 - collateralDecimals)) + 1; // need to verify
}
return amount / uint256(10**(18 - collateralDecimals));
}
function _msgSender()
internal
view
virtual
override(ContextUpgradeable, ERC2771ContextUpgradeable)
returns (address sender)
{
//ERC2771ContextUpgradeable._msgSender();
return super._msgSender();
}
function _msgData()
internal
view
virtual
override(ContextUpgradeable, ERC2771ContextUpgradeable)
returns (bytes calldata)
{
//ERC2771ContextUpgradeable._msgData();
return super._msgData();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment