diff --git a/test/e2e/BurnFees.t.sol b/test/e2e/BurnFees.t.sol new file mode 100644 index 00000000..e3ac5c1a --- /dev/null +++ b/test/e2e/BurnFees.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.8; + +import {Vm} from "forge-std/Vm.sol"; + +import {IERC20} from "src/contracts/interfaces/IERC20.sol"; + +import {GPv2Interaction} from "src/contracts/libraries/GPv2Interaction.sol"; +import {GPv2Order} from "src/contracts/libraries/GPv2Order.sol"; +import {GPv2Signing} from "src/contracts/mixins/GPv2Signing.sol"; + +import {SettlementEncoder} from "../libraries/encoders/SettlementEncoder.sol"; +import {Registry, TokenRegistry} from "../libraries/encoders/TokenRegistry.sol"; +import {Helper, IERC20Mintable} from "./Helper.sol"; + +using SettlementEncoder for SettlementEncoder.State; +using TokenRegistry for TokenRegistry.State; +using TokenRegistry for Registry; + +contract BurnFeesTest is Helper(false) { + IERC20Mintable owl; + IERC20Mintable dai; + + function setUp() public override { + super.setUp(); + + owl = deployMintableErc20("owl", "owl"); + dai = deployMintableErc20("dai", "dai"); + } + + function test_uses_post_interaction_to_burn_settlement_fees() external { + Vm.Wallet memory trader1 = vm.createWallet("trader1"); + Vm.Wallet memory trader2 = vm.createWallet("trader2"); + + // mint some owl to trader1 + owl.mint(trader1.addr, 1001 ether); + vm.prank(trader1.addr); + // approve owl for trading on settlement contract + owl.approve(vaultRelayer, type(uint256).max); + // place order to sell 1000 owl for min 1000 dai + encoder.signEncodeTrade( + vm, + trader1, + GPv2Order.Data({ + kind: GPv2Order.KIND_SELL, + partiallyFillable: false, + sellToken: owl, + buyToken: dai, + sellAmount: 1000 ether, + buyAmount: 1000 ether, + feeAmount: 1 ether, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + sellTokenBalance: GPv2Order.BALANCE_ERC20, + buyTokenBalance: GPv2Order.BALANCE_ERC20, + receiver: GPv2Order.RECEIVER_SAME_AS_OWNER + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // mint some dai to trader2 + dai.mint(trader2.addr, 1000 ether); + vm.prank(trader2.addr); + // approve dai for trading on settlement contract + dai.approve(vaultRelayer, type(uint256).max); + // place order to BUY 1000 owl with max 1000 dai + encoder.signEncodeTrade( + vm, + trader2, + GPv2Order.Data({ + kind: GPv2Order.KIND_BUY, + partiallyFillable: false, + sellToken: dai, + buyToken: owl, + sellAmount: 1000 ether, + buyAmount: 1000 ether, + feeAmount: 0, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + sellTokenBalance: GPv2Order.BALANCE_ERC20, + buyTokenBalance: GPv2Order.BALANCE_ERC20, + receiver: GPv2Order.RECEIVER_SAME_AS_OWNER + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // add post interaction to burn owl fees + encoder.addInteraction( + GPv2Interaction.Data({target: address(owl), value: 0, callData: abi.encodeCall(owl.burn, (1 ether))}), + SettlementEncoder.InteractionStage.POST + ); + + // set the token prices + IERC20[] memory tokens = new IERC20[](2); + tokens[0] = owl; + tokens[1] = dai; + uint256[] memory prices = new uint256[](2); + prices[0] = 1; + prices[1] = 1; + encoder.tokenRegistry.tokenRegistry().setPrices(tokens, prices); + + SettlementEncoder.EncodedSettlement memory encodedSettlement = encoder.encode(settlement); + vm.prank(solver); + vm.expectEmit(); + emit IERC20.Transfer(address(settlement), address(0), 1 ether); + settle(encodedSettlement); + + assertEq(dai.balanceOf(address(settlement)), 0, "dai balance of settlement contract not 0"); + } +} diff --git a/test/e2e/burnFees.test.ts b/test/e2e/burnFees.test.ts deleted file mode 100644 index af76b2d0..00000000 --- a/test/e2e/burnFees.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -import ERC20 from "@openzeppelin/contracts/build/contracts/ERC20PresetMinterPauser.json"; -import { expect } from "chai"; -import { Contract, Wallet } from "ethers"; -import { ethers, waffle } from "hardhat"; - -import { - InteractionStage, - OrderKind, - SettlementEncoder, - SigningScheme, - TypedDataDomain, - domain, -} from "../../src/ts"; - -import { deployTestContracts } from "./fixture"; - -describe("E2E: Burn fees", () => { - let deployer: Wallet; - let solver: Wallet; - let traders: Wallet[]; - - let settlement: Contract; - let vaultRelayer: Contract; - let domainSeparator: TypedDataDomain; - - let owl: Contract; - let dai: Contract; - - beforeEach(async () => { - const deployment = await deployTestContracts(); - - ({ - deployer, - settlement, - vaultRelayer, - wallets: [solver, ...traders], - } = deployment); - - const { authenticator, manager } = deployment; - await authenticator.connect(manager).addSolver(solver.address); - - const { chainId } = await ethers.provider.getNetwork(); - domainSeparator = domain(chainId, settlement.address); - - owl = await waffle.deployContract(deployer, ERC20, ["OWL", "Owl token"]); - dai = await waffle.deployContract(deployer, ERC20, ["DAI", "Dai token"]); - }); - - it("uses post-interation to burn settlement fees", async () => { - // Settle a trivial 1:1 trade between DAI and OWL. - - const ONE_USD = ethers.utils.parseEther("1.0"); - - const encoder = new SettlementEncoder(domainSeparator); - - await owl.mint(traders[0].address, ONE_USD.mul(1001)); - await owl - .connect(traders[0]) - .approve(vaultRelayer.address, ethers.constants.MaxUint256); - await encoder.signEncodeTrade( - { - kind: OrderKind.SELL, - partiallyFillable: false, - sellToken: owl.address, - buyToken: dai.address, - sellAmount: ONE_USD.mul(1000), - buyAmount: ONE_USD.mul(1000), - feeAmount: ONE_USD, - validTo: 0xffffffff, - appData: 1, - }, - traders[0], - SigningScheme.EIP712, - ); - - await dai.mint(traders[1].address, ONE_USD.mul(1000)); - await dai - .connect(traders[1]) - .approve(vaultRelayer.address, ethers.constants.MaxUint256); - - await encoder.signEncodeTrade( - { - kind: OrderKind.BUY, - partiallyFillable: false, - buyToken: owl.address, - sellToken: dai.address, - buyAmount: ONE_USD.mul(1000), - sellAmount: ONE_USD.mul(1000), - feeAmount: ethers.constants.Zero, - validTo: 0xffffffff, - appData: 2, - }, - traders[1], - SigningScheme.EIP712, - ); - - encoder.encodeInteraction( - { - target: owl.address, - callData: owl.interface.encodeFunctionData("burn", [ONE_USD]), - }, - InteractionStage.POST, - ); - - const tx = settlement.connect(solver).settle( - ...encoder.encodedSettlement({ - [owl.address]: 1, - [dai.address]: 1, - }), - ); - - await expect(tx) - .to.emit(owl, "Transfer") - .withArgs(settlement.address, ethers.constants.AddressZero, ONE_USD); - expect(await dai.balanceOf(settlement.address)).to.deep.equal( - ethers.constants.Zero, - ); - }); -});