Skip to content

Commit

Permalink
fix(FlashMintExtended): reduce contract size (#171)
Browse files Browse the repository at this point in the history
* Fix contract size

* Fix tests

* Optimize tests
  • Loading branch information
ckoopmann authored Apr 22, 2024
1 parent 2278397 commit 488b8a7
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 75 deletions.
14 changes: 7 additions & 7 deletions contracts/exchangeIssuance/FlashMintLeveragedExtended.sol
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ contract FlashMintLeveragedExtended is FlashMintLeveraged, Ownable {
wethBalanceBefore
);
uint256 wethObtained = IERC20(addresses.weth).balanceOf(address(this)).sub(wethBalanceBefore);
require(wethObtained >= _outputTokenAmount, "FlashMintLeveragedExtended: insufficient wethObtained");
require(wethObtained - _outputTokenAmount <= maxGasRebate, "FlashMintLeveragedExtended: maxGasRebate exceeded");
require(wethObtained >= _outputTokenAmount, "IWO");
require(wethObtained - _outputTokenAmount <= maxGasRebate, "MGR");
IWETH(addresses.weth).withdraw(wethObtained);
(payable(msg.sender)).sendValue(wethObtained);
return setBalanceBefore.sub(_setToken.balanceOf(msg.sender));
Expand Down Expand Up @@ -478,7 +478,7 @@ contract FlashMintLeveragedExtended is FlashMintLeveraged, Ownable {
internal
{
uint256 outputTokenObtained = IERC20(_outputToken).balanceOf(address(this)).sub(_outputTokenBalanceBefore);
require(outputTokenObtained >= _outputTokenAmount, "FlashMintLeveragedExtended: insufficient outputTokenObtained");
require(outputTokenObtained >= _outputTokenAmount, "IOTO");
IERC20(_outputToken).transfer(msg.sender, _outputTokenAmount);
_swapTokenForETHAndReturnToUser(_outputToken, outputTokenObtained - _outputTokenAmount, _swapDataOutputTokenForETH);
}
Expand All @@ -498,11 +498,11 @@ contract FlashMintLeveragedExtended is FlashMintLeveraged, Ownable {
internal
returns(uint256)
{
require(_inputTokenAmount > _maxDust, "FlashMintLeveragedExtended: _inputToken must be more than _maxDust");
require(_inputTokenAmount > _maxDust, "MD");

uint256 iterations = 0;
while (_inputTokenAmount > _maxDust) {
require(iterations < maxIterations, "FlashMintLeveragedExtended: exceeded Max Iterations");
require(iterations < maxIterations, "MI");
uint256 inputTokenAmountSpent = _initiateIssuanceAndReturnInputAmountSpent(
_setToken,
_minSetAmount,
Expand Down Expand Up @@ -688,15 +688,15 @@ contract FlashMintLeveragedExtended is FlashMintLeveraged, Ownable {
if(_swapData.path.length == 0) {
return;
}
require(_swapData.path[0] == _inputToken, "FlashMintLeveragedExtended: InputToken not first in path");
require(_swapData.path[0] == _inputToken, "ITNF");
require(_swapData.path[_swapData.path.length - 1] == addresses.weth, "FlashMintLeveragedExtended: WETH not last in path");
ethObtained = addresses.swapExactTokensForTokens(
_inputAmount,
0,
_swapData
);
}
require(ethObtained <= maxGasRebate, "FlashMintLeveragedExtended: maxGasRebate exceeded");
require(ethObtained <= maxGasRebate, "MGR");

IWETH(addresses.weth).withdraw(ethObtained);
msg.sender.transfer(ethObtained);
Expand Down
1 change: 0 additions & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const config: HardhatUserConfig = {
networks: {
hardhat: {
forking: process.env.FORK ? forkingConfig : undefined,
allowUnlimitedContractSize: true,
accounts: getHardhatPrivateKeys(),
// @ts-ignore
timeout: INTEGRATIONTEST_TIMEOUT,
Expand Down
123 changes: 56 additions & 67 deletions test/integration/arbitrum/flashMintLeveragedExtended.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,6 @@ if (process.env.INTEGRATIONTEST) {
await weth.transfer(owner.address, ether(100));
await aweth.transfer(owner.address, ether(100));

// This is done to avoid flaky "Invalid transfer in, results in undercollateralization" error
// See: https://github.com/IndexCoop/index-protocol/blob/1a587d93d273d9004d03f1235c395f6f7cd147dc/test/protocol/modules/v1/debtIssuanceModuleV2.spec.ts#L730
// TODO: Review if we have to do this in production.
await aweth.transfer(setToken.address, ether(0.000001));

await aweth
.connect(owner.wallet)
.approve(addresses.setFork.debtIssuanceModuleV2, ether(10));
Expand Down Expand Up @@ -191,10 +186,10 @@ if (process.env.INTEGRATIONTEST) {
).to.equal(MAX_UINT_256);
});

["collateralToken", "USDC", "ETH"].forEach(inputTokenName => {
["USDC", "ETH"].forEach(inputTokenName => {
describe(`When input/output token is ${inputTokenName}`, () => {
let amountIn: BigNumber;
beforeEach(async () => {
before(async () => {
amountIn = ether(0.4);
if (inputTokenName === "USDC") {
amountIn = utils.parseUnits("2500", 6);
Expand All @@ -220,8 +215,11 @@ if (process.env.INTEGRATIONTEST) {
let subjectSetToken: Address;
let subjectMaxAmountIn: BigNumber;
let subjectInputToken: Address;
let setBalancebefore: BigNumber;
let inputBalanceBefore: BigNumber;
let quotedInputAmount: BigNumber;

beforeEach(async () => {
before(async () => {
subjectSetAmount = ether(1);
swapDataDebtToCollateral = {
path: [addresses.tokens.USDC, addresses.tokens.weth],
Expand Down Expand Up @@ -255,6 +253,13 @@ if (process.env.INTEGRATIONTEST) {
subjectInputToken = inputToken.address;
}
subjectSetToken = setToken.address;
setBalancebefore = await setToken.balanceOf(owner.address);
inputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);
quotedInputAmount = await subjectQuote();
await subject();
});

async function subject() {
Expand Down Expand Up @@ -287,35 +292,22 @@ if (process.env.INTEGRATIONTEST) {
}

it("should issue the correct amount of tokens", async () => {
const setBalancebefore = await setToken.balanceOf(owner.address);
await subject();
const setBalanceAfter = await setToken.balanceOf(owner.address);
const setObtained = setBalanceAfter.sub(setBalancebefore);
expect(setObtained).to.eq(subjectSetAmount);
});

it("should spend less than specified max amount", async () => {
const inputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);
await subject();
const inputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);
const inputSpent = inputBalanceBefore.sub(inputBalanceAfter);
expect(inputSpent.gt(0)).to.be.true;
expect(inputSpent.lte(subjectMaxAmountIn)).to.be.true;
expect(inputSpent).to.be.gt(0);
expect(inputSpent).to.be.lte(subjectMaxAmountIn);
});

it("should quote the correct input amount", async () => {
const quotedInputAmount = await subjectQuote();
const inputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);
await subject();
const inputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
Expand Down Expand Up @@ -344,7 +336,12 @@ if (process.env.INTEGRATIONTEST) {
let subjectPriceEstimateInflater: BigNumber;
let subjectMaxDust: BigNumber;

beforeEach(async () => {
let setBalancebefore: BigNumber;
let ethBalanceBefore: BigNumber;
let gasCosts: BigNumber;
let inputBalanceBefore: BigNumber;

before(async () => {
swapDataDebtToCollateral = {
path: [addresses.tokens.USDC, addresses.tokens.weth],
fees: [500],
Expand Down Expand Up @@ -379,6 +376,15 @@ if (process.env.INTEGRATIONTEST) {
subjectMinSetAmount = ether(1);
subjectSetToken = setToken.address;
swapDataInputTokenToETH = swapDataInputTokenToCollateral; // Assumes Collateral Token is WETH
setBalancebefore = await setToken.balanceOf(owner.address);
ethBalanceBefore = await owner.wallet.getBalance();
inputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);
const tx = await subject();
const receipt = await tx.wait();
gasCosts = receipt.gasUsed.mul(tx.gasPrice);
});

async function subject() {
Expand Down Expand Up @@ -407,34 +413,19 @@ if (process.env.INTEGRATIONTEST) {
}

it("should issue at least minSetAmount of set tokens", async () => {
const setBalancebefore = await setToken.balanceOf(owner.address);
await subject();
const setBalanceAfter = await setToken.balanceOf(owner.address);
const setObtained = setBalanceAfter.sub(setBalancebefore);
expect(setObtained).to.gte(subjectMinSetAmount);
});

if (inputTokenName !== "ETH") {
it("should give gas rebaste", async () => {
const ethBalanceBefore = await owner.wallet.getBalance();
const tx = await subject();
const receipt = await tx.wait();
const gasCosts = receipt.gasUsed.mul(tx.gasPrice);
const ethBalanceAfter = await owner.wallet.getBalance();
expect(ethBalanceBefore.sub(ethBalanceAfter)).to.lt(gasCosts);
});
}

it("should spend exactly inputAmount", async () => {
const inputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await inputToken.balanceOf(owner.address);

const tx = await subject();
const receipt = await tx.wait();
const gasCosts = receipt.gasUsed.mul(tx.gasPrice);

const inputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
Expand Down Expand Up @@ -468,6 +459,10 @@ if (process.env.INTEGRATIONTEST) {
let subjectOutputToken: Address;
let subjectPriceEstimateInflater: BigNumber;
let subjectMaxDust: BigNumber;
let setBalanceBefore: BigNumber;
let ethBalanceBefore: BigNumber;
let outputBalanceBefore: BigNumber;
let gasCosts: BigNumber;

async function subject() {
if (inputTokenName === "ETH") {
Expand Down Expand Up @@ -498,7 +493,7 @@ if (process.env.INTEGRATIONTEST) {
);
}

beforeEach(async () => {
before(async () => {
subjectPriceEstimateInflater = ether(0.9);
subjectMaxSetAmount = ether(1);
subjectAmountOut =
Expand Down Expand Up @@ -547,35 +542,32 @@ if (process.env.INTEGRATIONTEST) {
if (inputTokenName !== "ETH") {
subjectOutputToken = outputToken.address;
}
setBalanceBefore = await setToken.balanceOf(owner.address);
ethBalanceBefore = await owner.wallet.getBalance();
outputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);

const tx = await subject();
const receipt = await tx.wait();
gasCosts = receipt.gasUsed.mul(tx.gasPrice);
});

it("should redeem at most subjectMaxSetAmount", async () => {
const setBalanceBefore = await setToken.balanceOf(owner.address);
await subject();
const setBalanceAfter = await setToken.balanceOf(owner.address);
const setRedeemed = setBalanceBefore.sub(setBalanceAfter);
expect(setRedeemed).to.lte(subjectMaxSetAmount);
});

if (inputTokenName !== "ETH") {
it("should give gas rebaste", async () => {
const ethBalanceBefore = await owner.wallet.getBalance();
const tx = await subject();
const receipt = await tx.wait();
const gasCosts = receipt.gasUsed.mul(tx.gasPrice);
const ethBalanceAfter = await owner.wallet.getBalance();
expect(ethBalanceBefore.sub(ethBalanceAfter)).to.lt(gasCosts);
});
}

it("should return exactly specified of output tokens", async () => {
const outputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);
const tx = await subject();
const receipt = await tx.wait();
const gasCosts = receipt.gasUsed.mul(tx.gasPrice);
const outputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
Expand Down Expand Up @@ -603,6 +595,9 @@ if (process.env.INTEGRATIONTEST) {
let subjectSetAmount: BigNumber;
let subjectMinAmountOut: BigNumber;
let subjectOutputToken: Address;
let setBalanceBefore: BigNumber;
let outputBalanceBefore: BigNumber;
let outputAmountQuote: BigNumber;

async function subject() {
if (inputTokenName === "ETH") {
Expand Down Expand Up @@ -633,7 +628,7 @@ if (process.env.INTEGRATIONTEST) {
);
}

beforeEach(async () => {
before(async () => {
subjectSetAmount = ether(1);
swapDataCollateralToDebt = {
path: [collateralTokenAddress, addresses.tokens.USDC],
Expand Down Expand Up @@ -664,22 +659,22 @@ if (process.env.INTEGRATIONTEST) {
if (inputTokenName !== "ETH") {
subjectOutputToken = outputToken.address;
}
setBalanceBefore = await setToken.balanceOf(owner.address);
outputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);
outputAmountQuote = await subjectQuote();
await subject();
});

it("should redeem the correct amount of tokens", async () => {
const setBalanceBefore = await setToken.balanceOf(owner.address);
await subject();
const setBalanceAfter = await setToken.balanceOf(owner.address);
const setRedeemed = setBalanceBefore.sub(setBalanceAfter);
expect(setRedeemed).to.eq(subjectSetAmount);
});

it("should return at least the specified minimum of output tokens", async () => {
const outputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);
await subject();
const outputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
Expand All @@ -689,18 +684,12 @@ if (process.env.INTEGRATIONTEST) {
});

it("should quote the correct output amount", async () => {
const outputBalanceBefore =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);
await subject();
const outputBalanceAfter =
inputTokenName === "ETH"
? await owner.wallet.getBalance()
: await outputToken.balanceOf(owner.address);
const outputObtained = outputBalanceAfter.sub(outputBalanceBefore);

const outputAmountQuote = await subjectQuote();
expect(outputAmountQuote).to.gt(preciseMul(outputObtained, ether(0.99)));
expect(outputAmountQuote).to.lt(preciseMul(outputObtained, ether(1.01)));
});
Expand Down

0 comments on commit 488b8a7

Please sign in to comment.