From e8f931ace705ada9deaba0323eaaddbcea70fef7 Mon Sep 17 00:00:00 2001 From: MrBeaverTail Date: Thu, 9 Nov 2023 15:41:51 +0000 Subject: [PATCH] fix: correct withdrawal fee calculation to take into acc when cashAfter is negative --- contracts/pool/Core.sol | 14 +++- test/helpers/helper.ts | 21 ++++++ test/pool-savax/PoolAvax.arb.ts | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 test/pool-savax/PoolAvax.arb.ts diff --git a/contracts/pool/Core.sol b/contracts/pool/Core.sol index bd4652b..98a550a 100644 --- a/contracts/pool/Core.sol +++ b/contracts/pool/Core.sol @@ -154,17 +154,27 @@ contract Core { } uint256 cashAfter; + // reverse is true when cashAfter is a negative number + bool reverse; // Cover case where cash <= amount if (cash > amount) { cashAfter = cash - amount; } else { - cashAfter = 0; + cashAfter = amount - cash; + reverse = true; } uint256 covAfter = (cashAfter).wdiv(liability - amount); uint256 slippageBefore = _slippageFunc(k, n, c1, xThreshold, covBefore); - uint256 slippageAfter = _slippageFunc(k, n, c1, xThreshold, covAfter); uint256 slippageNeutral = _slippageFunc(k, n, c1, xThreshold, WAD); // slippage on cov = 1 + uint256 slippageAfter; + + // in case cashAfter is a negative number, we use slippageAfter = c1 + covAfter + if (reverse) { + slippageAfter = c1 + covAfter; + } else { + slippageAfter = _slippageFunc(k, n, c1, xThreshold, covAfter); + } // calculate fee // fee = a - b diff --git a/test/helpers/helper.ts b/test/helpers/helper.ts index 3d2c313..aee617a 100644 --- a/test/helpers/helper.ts +++ b/test/helpers/helper.ts @@ -96,6 +96,27 @@ export const setupSAvaxPool = async (owner: Signer): Promise<{ pool: Contract; W return { pool, WETH } } +export const setupSAvaxPoolTestERC20 = async (owner: Signer): Promise<{ pool: Contract; WETH: Contract }> => { + PoolYYAvax = await ethers.getContractFactory('PoolSAvax') + WETHForwarder = await ethers.getContractFactory('WETHForwarder') + + const pool = await PoolYYAvax.connect(owner).deploy() + const WETH = await TestERC20.connect(owner).deploy('WAVAX', 'WAVAX', 18, parseEther('10000000000000000000000')) + + // Wait for contract to be deployed + await pool.deployTransaction.wait() + await WETH.deployTransaction.wait() + + await pool.connect(owner).initialize(WETH.address) + + // Set WETH Forwarder + const forwarder = await WETHForwarder.connect(owner).deploy(WETH.address) + await forwarder.connect(owner).setPool(pool.address) + await pool.connect(owner).setWETHForwarder(forwarder.address) + + return { pool, WETH } +} + export const setupYYAvaxPool = async (owner: Signer): Promise<{ pool: Contract; WETH: Contract }> => { PoolYYAvax = await ethers.getContractFactory('PoolYYAvax') WETHForwarder = await ethers.getContractFactory('WETHForwarder') diff --git a/test/pool-savax/PoolAvax.arb.ts b/test/pool-savax/PoolAvax.arb.ts new file mode 100644 index 0000000..a6d6289 --- /dev/null +++ b/test/pool-savax/PoolAvax.arb.ts @@ -0,0 +1,112 @@ +import { ethers } from 'hardhat' +import { parseEther } from '@ethersproject/units' +import chai from 'chai' +import { solidity } from 'ethereum-waffle' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { BigNumber, constants, ContractFactory } from 'ethers' +import { + createAndInitializeToken, + fundUserAndApprovePool, + expectAssetValues, + setupAggregateAccount, + setupSAvaxPoolTestERC20, + setupSAvaxPriceFeed, +} from '../helpers/helper' + +const { expect } = chai +chai.use(solidity) + +describe('AvaxPool Arb', function () { + let owner: SignerWithAddress + let users: SignerWithAddress[] + let TestERC20: ContractFactory + let Asset: ContractFactory + + before(async () => { + const [first, ...rest] = await ethers.getSigners() + owner = first + users = rest + + TestERC20 = await ethers.getContractFactory('TestERC20') + Asset = await ethers.getContractFactory('Asset') + }) + + beforeEach(async function () { + this.lastBlock = await ethers.provider.getBlock('latest') + this.lastBlockTime = this.lastBlock.timestamp + this.fiveSecondsSince = this.lastBlockTime + 5 * 1000 + this.fiveSecondsAgo = this.lastBlockTime - 5 * 1000 + + // avax pool + const poolSetup = await setupSAvaxPoolTestERC20(owner) + this.pool = poolSetup.pool + this.WETH = poolSetup.WETH + + await setupSAvaxPriceFeed(this.pool) + }) + + describe('Arb pool', function () { + beforeEach(async function () { + const aggregateName = 'Liquid staking AVAX Aggregate' + const aggregateAccount = await setupAggregateAccount(owner, aggregateName, true) + await aggregateAccount.deployTransaction.wait() + + this.assetAVAX = await Asset.connect(owner).deploy() + await this.assetAVAX + .connect(owner) + .initialize(this.WETH.address, 'AVAX Asset', 'LP-AVAX', aggregateAccount.address) + await this.assetAVAX.connect(owner).setPool(this.pool.address) + await this.pool.connect(owner).addAsset(this.WETH.address, this.assetAVAX.address) + + const tokenSetSAvax = await createAndInitializeToken('sAVAX', 18, owner, this.pool, aggregateAccount) + + this.sAVAX = tokenSetSAvax.token + this.assetSAVAX = tokenSetSAvax.asset + + await this.pool.setSAvax(this.sAVAX.address) + + await fundUserAndApprovePool(this.sAVAX, owner, parseEther('100000000000').toString(), this.pool, owner) + await fundUserAndApprovePool(this.WETH, owner, parseEther('100000000000').toString(), this.pool, owner) + + // SAVAX SETUP + const sAvaxCash = parseEther('1478053.383') + const sAvaxLiability = parseEther('747812.6418') + + await this.pool.deposit(this.sAVAX.address, sAvaxLiability, owner.address, this.fiveSecondsSince) + + await this.assetSAVAX.setPool(owner.address) + await this.assetSAVAX.addCash(sAvaxCash.sub(sAvaxLiability)) + await this.sAVAX.transfer(this.assetSAVAX.address, sAvaxCash.sub(sAvaxLiability)) + await this.assetSAVAX.setPool(this.pool.address) + + await expectAssetValues(this.assetSAVAX, 18, { cash: '1478053.383', liability: '747812.6418' }) + + // AVAX SETUP + const avaxCash = parseEther('801521.1967') + const avaxLiability = parseEther('1592988.997') + + await this.pool.deposit(this.WETH.address, avaxLiability, owner.address, this.fiveSecondsSince) + await this.assetAVAX.setPool(owner.address) + await this.assetAVAX.removeCash(avaxLiability.sub(avaxCash)) + await this.assetAVAX.transferUnderlyingToken(owner.address, avaxLiability.sub(avaxCash)) + // await this.WETH.transfer(this.assetAVAX.address, avaxCash.sub(avaxLiability)) + await this.assetAVAX.setPool(this.pool.address) + + await expectAssetValues(this.assetAVAX, 18, { cash: '801521.1967', liability: '1592988.997' }) + }) + + describe('Withdraw Fee test', function () { + it('Withdraw test', async function () { + // this.WETH balance before and after + const avaxBalanceBefore = await this.WETH.balanceOf(owner.address) + + await this.pool.withdraw(this.WETH.address, parseEther('1020000'), 0, owner.address, this.fiveSecondsSince) + const avaxBalanceAfter = await this.WETH.balanceOf(owner.address) + + const delta = avaxBalanceAfter.sub(avaxBalanceBefore) + // console.log('delta', ethers.utils.formatEther(delta)) + expect(delta).to.be.eq(ethers.utils.parseEther('589427.781262942888425645')) + }) + }) + }) +})