From 48ecef40d66154af11d7cc4038485fb97a43b802 Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Sun, 8 Sep 2024 21:35:33 +0530 Subject: [PATCH 1/5] chore: migrate E2E internalBalances test to Foundry --- test/e2e/InternalBalances.t.sol | 254 ++++++++++++++++++++++++++++++ test/e2e/internalBalances.test.ts | 213 ------------------------- 2 files changed, 254 insertions(+), 213 deletions(-) create mode 100644 test/e2e/InternalBalances.t.sol delete mode 100644 test/e2e/internalBalances.test.ts diff --git a/test/e2e/InternalBalances.t.sol b/test/e2e/InternalBalances.t.sol new file mode 100644 index 00000000..70b2e777 --- /dev/null +++ b/test/e2e/InternalBalances.t.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.8; + +import {Vm} from "forge-std/Vm.sol"; + +import {StandardERC20} from "../src/NonStandardERC20.sol"; +import {IERC20} from "src/contracts/interfaces/IERC20.sol"; +import {IVault} from "src/contracts/interfaces/IVault.sol"; + +import { + GPv2Interaction, + GPv2Order, + GPv2Signing, + GPv2Trade, + SettlementEncoder +} from "../libraries/encoders/SettlementEncoder.sol"; +import {Registry, TokenRegistry} from "../libraries/encoders/TokenRegistry.sol"; +import {ERC20NoReturn, ERC20ReturningUint} from "../src/NonStandardERC20.sol"; +import {ForkedTest} from "./ForkedTest.t.sol"; + +using SettlementEncoder for SettlementEncoder.State; +using TokenRegistry for TokenRegistry.State; +using TokenRegistry for Registry; + +interface IBalancerVault is IVault { + function setRelayerApproval(address, address, bool) external; + function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory); + function hasApprovedRelayer(address, address) external view returns (bool); +} + +contract InternalBalancesTest is ForkedTest { + IERC20 token1; + IERC20 token2; + + function setUp() public override { + super.setUp(); + + token1 = IERC20(address(new StandardERC20())); + token2 = IERC20(address(new StandardERC20())); + + token1 = IERC20(address(token1)); + token2 = IERC20(address(token2)); + + GPv2Interaction.Data[] memory interactions = new GPv2Interaction.Data[](2); + interactions[0] = GPv2Interaction.Data({ + target: address(token1), + value: 0, + callData: abi.encodeCall(IERC20.approve, (address(vault), type(uint256).max)) + }); + interactions[1] = GPv2Interaction.Data({ + target: address(token2), + value: 0, + callData: abi.encodeCall(IERC20.approve, (address(vault), type(uint256).max)) + }); + SettlementEncoder.EncodedSettlement memory encodedSettlement = encoder.encode(interactions); + vm.prank(solver); + settle(encodedSettlement); + } + + function test_should_settle_orders_buying_and_selling_with_internal_balances() external { + Vm.Wallet memory trader1 = vm.createWallet("trader1"); + Vm.Wallet memory trader2 = vm.createWallet("trader2"); + Vm.Wallet memory trader3 = vm.createWallet("trader3"); + Vm.Wallet memory trader4 = vm.createWallet("trader4"); + vm.label(trader1.addr, "trader1"); + vm.label(trader2.addr, "trader2"); + vm.label(trader3.addr, "trader3"); + vm.label(trader4.addr, "trader4"); + vm.label(address(token1), "token1"); + vm.label(address(token2), "token2"); + vm.label(vaultRelayer, "vaultRelayer"); + vm.label(address(vault), "vault"); + + // mint some tokens to trader1 + _mintTokens(token1, trader1.addr, 1.001 ether); + + // approve tokens to the balancer vault and approve the settlement contract to + // be able to spend the balancer internal/external balances + vm.startPrank(trader1.addr); + token1.approve(address(vault), type(uint256).max); + IBalancerVault(address(vault)).setRelayerApproval(trader1.addr, vaultRelayer, true); + vm.stopPrank(); + + // place order for selling 1 token1 for 500 token2 + encoder.signEncodeTrade( + vm, + trader1, + GPv2Order.Data({ + sellToken: token1, + buyToken: token2, + receiver: trader1.addr, + sellAmount: 1 ether, + buyAmount: 500 ether, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + feeAmount: 0.001 ether, + kind: GPv2Order.KIND_SELL, + partiallyFillable: false, + sellTokenBalance: GPv2Order.BALANCE_EXTERNAL, + buyTokenBalance: GPv2Order.BALANCE_ERC20 + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // mint some tokens to trader2 + _mintTokens(token2, trader2.addr, 300.3 ether); + + // approve tokens to the balancer vault and deposit some tokens to balancer internal + // balance + vm.startPrank(trader2.addr); + token2.approve(address(vault), type(uint256).max); + IVault.UserBalanceOp[] memory ops = new IVault.UserBalanceOp[](1); + ops[0] = IVault.UserBalanceOp({ + kind: IVault.UserBalanceOpKind.DEPOSIT_INTERNAL, + asset: token2, + amount: 300.3 ether, + sender: trader2.addr, + recipient: payable(trader2.addr) + }); + vault.manageUserBalance(ops); + IBalancerVault(address(vault)).setRelayerApproval(trader2.addr, vaultRelayer, true); + vm.stopPrank(); + + // place order for buying 0.5 token1 with max 300 token2 + encoder.signEncodeTrade( + vm, + trader2, + GPv2Order.Data({ + sellToken: token2, + buyToken: token1, + receiver: trader2.addr, + sellAmount: 300 ether, + buyAmount: 0.5 ether, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + feeAmount: 0.3 ether, + kind: GPv2Order.KIND_BUY, + partiallyFillable: false, + sellTokenBalance: GPv2Order.BALANCE_INTERNAL, + buyTokenBalance: GPv2Order.BALANCE_ERC20 + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // mint some tokens to trader3 + _mintTokens(token1, trader3.addr, 2.002 ether); + + // approve the tokens to cow vault relayer + vm.prank(trader3.addr); + token1.approve(vaultRelayer, type(uint256).max); + + // place order for selling 2 token1 for min 1000 token2 + encoder.signEncodeTrade( + vm, + trader3, + GPv2Order.Data({ + sellToken: token1, + buyToken: token2, + receiver: trader3.addr, + sellAmount: 2 ether, + buyAmount: 1000 ether, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + feeAmount: 0.002 ether, + kind: GPv2Order.KIND_SELL, + partiallyFillable: false, + sellTokenBalance: GPv2Order.BALANCE_ERC20, + buyTokenBalance: GPv2Order.BALANCE_INTERNAL + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // mint some tokens to trader4 + _mintTokens(token2, trader4.addr, 1501.5 ether); + + // approve tokens to the balancer vault and deposit some tokens to balancer internal + // balance + vm.startPrank(trader4.addr); + token2.approve(address(vault), type(uint256).max); + ops = new IVault.UserBalanceOp[](1); + ops[0] = IVault.UserBalanceOp({ + kind: IVault.UserBalanceOpKind.DEPOSIT_INTERNAL, + asset: token2, + amount: 1501.5 ether, + sender: trader4.addr, + recipient: payable(trader4.addr) + }); + IBalancerVault(address(vault)).manageUserBalance(ops); + IBalancerVault(address(vault)).setRelayerApproval(trader4.addr, vaultRelayer, true); + vm.stopPrank(); + + // place order to buy 2.5 token1 with max 1500 token2 + encoder.signEncodeTrade( + vm, + trader4, + GPv2Order.Data({ + sellToken: token2, + buyToken: token1, + receiver: trader4.addr, + sellAmount: 1500 ether, + buyAmount: 2.5 ether, + validTo: 0xffffffff, + appData: bytes32(uint256(1)), + feeAmount: 1.5 ether, + kind: GPv2Order.KIND_BUY, + partiallyFillable: false, + sellTokenBalance: GPv2Order.BALANCE_INTERNAL, + buyTokenBalance: GPv2Order.BALANCE_INTERNAL + }), + domainSeparator, + GPv2Signing.Scheme.Eip712, + 0 + ); + + // set token prices + IERC20[] memory tokens = new IERC20[](2); + tokens[0] = token1; + tokens[1] = token2; + uint256[] memory prices = new uint256[](2); + prices[0] = 550; + prices[1] = 1; + encoder.tokenRegistry.tokenRegistry().setPrices(tokens, prices); + + // settle the orders + SettlementEncoder.EncodedSettlement memory encodedSettlement = encoder.encode(settlement); + vm.prank(solver); + settle(encodedSettlement); + + assertEq(token2.balanceOf(trader1.addr), 550 ether, "trader1 amountOut not as expected"); + assertEq(token1.balanceOf(trader2.addr), 0.5 ether, "trader2 amountOut not as expected"); + assertEq(_getInternalBalance(address(token2), trader3.addr), 1100 ether, "trader3 amountOut not as expected"); + assertEq(_getInternalBalance(address(token1), trader4.addr), 2.5 ether, "trader4 amountOut not as expected"); + + assertEq(token1.balanceOf(address(settlement)), 0.003 ether, "token1 settlement fee amount not as expected"); + assertEq(token2.balanceOf(address(settlement)), 1.8 ether, "token2 settlement fee amount not as expected"); + } + + function _mintTokens(IERC20 token, address to, uint256 amt) internal { + StandardERC20(address(token)).mint(to, amt); + } + + function _getInternalBalance(address token, address who) internal view returns (uint256) { + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(token); + uint256[] memory bals = IBalancerVault(address(vault)).getInternalBalance(who, tokens); + return bals[0]; + } +} diff --git a/test/e2e/internalBalances.test.ts b/test/e2e/internalBalances.test.ts deleted file mode 100644 index 8cfdedb6..00000000 --- a/test/e2e/internalBalances.test.ts +++ /dev/null @@ -1,213 +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 { - OrderBalance, - OrderKind, - SettlementEncoder, - SigningScheme, - TypedDataDomain, - domain, - grantRequiredRoles, -} from "../../src/ts"; -import { UserBalanceOpKind } from "../balancer"; - -import { deployTestContracts } from "./fixture"; - -describe("E2E: Should allow trading with Vault internal balances", () => { - let deployer: Wallet; - let solver: Wallet; - let traders: Wallet[]; - - let vault: Contract; - let settlement: Contract; - let vaultRelayer: Contract; - let domainSeparator: TypedDataDomain; - - let tokens: [Contract, Contract]; - - beforeEach(async () => { - const deployment = await deployTestContracts(); - - ({ - deployer, - vault, - settlement, - vaultRelayer, - wallets: [solver, ...traders], - } = deployment); - - const { vaultAuthorizer, authenticator, manager } = deployment; - await grantRequiredRoles( - vaultAuthorizer.connect(manager), - vault.address, - vaultRelayer.address, - ); - await authenticator.connect(manager).addSolver(solver.address); - - const { chainId } = await ethers.provider.getNetwork(); - domainSeparator = domain(chainId, settlement.address); - - tokens = [ - await waffle.deployContract(deployer, ERC20, ["T0", 18]), - await waffle.deployContract(deployer, ERC20, ["T1", 18]), - ]; - - await settlement.connect(solver).settle( - ...SettlementEncoder.encodedSetup( - ...tokens.map((token) => ({ - target: token.address, - callData: token.interface.encodeFunctionData("approve", [ - vault.address, - ethers.constants.MaxUint256, - ]), - })), - ), - ); - }); - - it("should settle orders buying and selling with internal balances", async () => { - const encoder = new SettlementEncoder(domainSeparator); - - await tokens[0].mint(traders[0].address, ethers.utils.parseEther("1.001")); - await tokens[0] - .connect(traders[0]) - .approve(vault.address, ethers.constants.MaxUint256); - await vault - .connect(traders[0]) - .setRelayerApproval(traders[0].address, vaultRelayer.address, true); - await encoder.signEncodeTrade( - { - kind: OrderKind.SELL, - partiallyFillable: false, - sellToken: tokens[0].address, - buyToken: tokens[1].address, - sellAmount: ethers.utils.parseEther("1.0"), - buyAmount: ethers.utils.parseEther("500.0"), - feeAmount: ethers.utils.parseEther("0.001"), - validTo: 0xffffffff, - appData: 1, - sellTokenBalance: OrderBalance.EXTERNAL, - }, - traders[0], - SigningScheme.EIP712, - ); - - await tokens[1].mint(traders[1].address, ethers.utils.parseEther("300.3")); - await tokens[1] - .connect(traders[1]) - .approve(vault.address, ethers.constants.MaxUint256); - await vault.connect(traders[1]).manageUserBalance([ - { - kind: UserBalanceOpKind.DEPOSIT_INTERNAL, - asset: tokens[1].address, - amount: ethers.utils.parseEther("300.3"), - sender: traders[1].address, - recipient: traders[1].address, - }, - ]); - await vault - .connect(traders[1]) - .setRelayerApproval(traders[1].address, vaultRelayer.address, true); - await encoder.signEncodeTrade( - { - kind: OrderKind.BUY, - partiallyFillable: false, - buyToken: tokens[0].address, - sellToken: tokens[1].address, - buyAmount: ethers.utils.parseEther("0.5"), - sellAmount: ethers.utils.parseEther("300.0"), - feeAmount: ethers.utils.parseEther("0.3"), - validTo: 0xffffffff, - appData: 2, - sellTokenBalance: OrderBalance.INTERNAL, - }, - traders[1], - SigningScheme.EIP712, - ); - - await tokens[0].mint(traders[2].address, ethers.utils.parseEther("2.002")); - await tokens[0] - .connect(traders[2]) - .approve(vaultRelayer.address, ethers.constants.MaxUint256); - await encoder.signEncodeTrade( - { - kind: OrderKind.SELL, - partiallyFillable: false, - sellToken: tokens[0].address, - buyToken: tokens[1].address, - sellAmount: ethers.utils.parseEther("2.0"), - buyAmount: ethers.utils.parseEther("1000.0"), - feeAmount: ethers.utils.parseEther("0.002"), - validTo: 0xffffffff, - appData: 2, - buyTokenBalance: OrderBalance.INTERNAL, - }, - traders[2], - SigningScheme.EIP712, - ); - - await tokens[1].mint(traders[3].address, ethers.utils.parseEther("1501.5")); - await tokens[1] - .connect(traders[3]) - .approve(vault.address, ethers.constants.MaxUint256); - await vault.connect(traders[3]).manageUserBalance([ - { - kind: UserBalanceOpKind.DEPOSIT_INTERNAL, - asset: tokens[1].address, - amount: ethers.utils.parseEther("1501.5"), - sender: traders[3].address, - recipient: traders[3].address, - }, - ]); - await vault - .connect(traders[3]) - .setRelayerApproval(traders[3].address, vaultRelayer.address, true); - await encoder.signEncodeTrade( - { - kind: OrderKind.BUY, - partiallyFillable: false, - buyToken: tokens[0].address, - sellToken: tokens[1].address, - buyAmount: ethers.utils.parseEther("2.5"), - sellAmount: ethers.utils.parseEther("1500.0"), - feeAmount: ethers.utils.parseEther("1.5"), - validTo: 0xffffffff, - appData: 2, - sellTokenBalance: OrderBalance.INTERNAL, - buyTokenBalance: OrderBalance.INTERNAL, - }, - traders[3], - SigningScheme.EIP712, - ); - - await settlement.connect(solver).settle( - ...encoder.encodedSettlement({ - [tokens[0].address]: 550, - [tokens[1].address]: 1, - }), - ); - - expect(await tokens[1].balanceOf(traders[0].address)).to.equal( - ethers.utils.parseEther("550.0"), - ); - expect(await tokens[0].balanceOf(traders[1].address)).to.equal( - ethers.utils.parseEther("0.5"), - ); - expect( - await vault.getInternalBalance(traders[2].address, [tokens[1].address]), - ).to.deep.equal([ethers.utils.parseEther("1100")]); - expect( - await vault.getInternalBalance(traders[3].address, [tokens[0].address]), - ).to.deep.equal([ethers.utils.parseEther("2.5")]); - - expect(await tokens[0].balanceOf(settlement.address)).to.equal( - ethers.utils.parseEther("0.003"), - ); - expect(await tokens[1].balanceOf(settlement.address)).to.equal( - ethers.utils.parseEther("1.8"), - ); - }); -}); From cbfcd21466816bbec97338c17c19c51fa65eaae0 Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Thu, 12 Sep 2024 12:38:21 +0530 Subject: [PATCH 2/5] refactor: ForkedTest -> Helper --- test/e2e/InternalBalances.t.sol | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/e2e/InternalBalances.t.sol b/test/e2e/InternalBalances.t.sol index 70b2e777..70118f11 100644 --- a/test/e2e/InternalBalances.t.sol +++ b/test/e2e/InternalBalances.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8; import {Vm} from "forge-std/Vm.sol"; -import {StandardERC20} from "../src/NonStandardERC20.sol"; import {IERC20} from "src/contracts/interfaces/IERC20.sol"; import {IVault} from "src/contracts/interfaces/IVault.sol"; @@ -16,7 +15,7 @@ import { } from "../libraries/encoders/SettlementEncoder.sol"; import {Registry, TokenRegistry} from "../libraries/encoders/TokenRegistry.sol"; import {ERC20NoReturn, ERC20ReturningUint} from "../src/NonStandardERC20.sol"; -import {ForkedTest} from "./ForkedTest.t.sol"; +import {Helper, IERC20Mintable} from "./Helper.sol"; using SettlementEncoder for SettlementEncoder.State; using TokenRegistry for TokenRegistry.State; @@ -28,18 +27,15 @@ interface IBalancerVault is IVault { function hasApprovedRelayer(address, address) external view returns (bool); } -contract InternalBalancesTest is ForkedTest { - IERC20 token1; - IERC20 token2; +contract InternalBalancesTest is Helper(false) { + IERC20Mintable token1; + IERC20Mintable token2; function setUp() public override { super.setUp(); - token1 = IERC20(address(new StandardERC20())); - token2 = IERC20(address(new StandardERC20())); - - token1 = IERC20(address(token1)); - token2 = IERC20(address(token2)); + token1 = deployMintableErc20("TK1", "TK1"); + token2 = deployMintableErc20("TK2", "TK2"); GPv2Interaction.Data[] memory interactions = new GPv2Interaction.Data[](2); interactions[0] = GPv2Interaction.Data({ @@ -241,8 +237,8 @@ contract InternalBalancesTest is ForkedTest { assertEq(token2.balanceOf(address(settlement)), 1.8 ether, "token2 settlement fee amount not as expected"); } - function _mintTokens(IERC20 token, address to, uint256 amt) internal { - StandardERC20(address(token)).mint(to, amt); + function _mintTokens(IERC20Mintable token, address to, uint256 amt) internal { + token.mint(to, amt); } function _getInternalBalance(address token, address who) internal view returns (uint256) { From 6833157b361344710ba5977d33c7118086527298 Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Sun, 15 Sep 2024 20:11:34 +0530 Subject: [PATCH 3/5] chore: fix solhint --- test/e2e/InternalBalances.t.sol | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/e2e/InternalBalances.t.sol b/test/e2e/InternalBalances.t.sol index 70118f11..36494e8b 100644 --- a/test/e2e/InternalBalances.t.sol +++ b/test/e2e/InternalBalances.t.sol @@ -6,15 +6,8 @@ import {Vm} from "forge-std/Vm.sol"; import {IERC20} from "src/contracts/interfaces/IERC20.sol"; import {IVault} from "src/contracts/interfaces/IVault.sol"; -import { - GPv2Interaction, - GPv2Order, - GPv2Signing, - GPv2Trade, - SettlementEncoder -} from "../libraries/encoders/SettlementEncoder.sol"; +import {GPv2Interaction, GPv2Order, GPv2Signing, SettlementEncoder} from "../libraries/encoders/SettlementEncoder.sol"; import {Registry, TokenRegistry} from "../libraries/encoders/TokenRegistry.sol"; -import {ERC20NoReturn, ERC20ReturningUint} from "../src/NonStandardERC20.sol"; import {Helper, IERC20Mintable} from "./Helper.sol"; using SettlementEncoder for SettlementEncoder.State; From 1f4561eb88ece922270bb63781443ffa9845b037 Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Thu, 26 Sep 2024 10:59:09 +0530 Subject: [PATCH 4/5] chore: address review comments --- test/e2e/InternalBalances.t.sol | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/test/e2e/InternalBalances.t.sol b/test/e2e/InternalBalances.t.sol index 36494e8b..dc416e04 100644 --- a/test/e2e/InternalBalances.t.sol +++ b/test/e2e/InternalBalances.t.sol @@ -30,20 +30,10 @@ contract InternalBalancesTest is Helper(false) { token1 = deployMintableErc20("TK1", "TK1"); token2 = deployMintableErc20("TK2", "TK2"); - GPv2Interaction.Data[] memory interactions = new GPv2Interaction.Data[](2); - interactions[0] = GPv2Interaction.Data({ - target: address(token1), - value: 0, - callData: abi.encodeCall(IERC20.approve, (address(vault), type(uint256).max)) - }); - interactions[1] = GPv2Interaction.Data({ - target: address(token2), - value: 0, - callData: abi.encodeCall(IERC20.approve, (address(vault), type(uint256).max)) - }); - SettlementEncoder.EncodedSettlement memory encodedSettlement = encoder.encode(interactions); - vm.prank(solver); - settle(encodedSettlement); + vm.startPrank(address(settlement)); + token1.approve(address(vault), type(uint256).max); + token2.approve(address(vault), type(uint256).max); + vm.stopPrank(); } function test_should_settle_orders_buying_and_selling_with_internal_balances() external { @@ -51,14 +41,6 @@ contract InternalBalancesTest is Helper(false) { Vm.Wallet memory trader2 = vm.createWallet("trader2"); Vm.Wallet memory trader3 = vm.createWallet("trader3"); Vm.Wallet memory trader4 = vm.createWallet("trader4"); - vm.label(trader1.addr, "trader1"); - vm.label(trader2.addr, "trader2"); - vm.label(trader3.addr, "trader3"); - vm.label(trader4.addr, "trader4"); - vm.label(address(token1), "token1"); - vm.label(address(token2), "token2"); - vm.label(vaultRelayer, "vaultRelayer"); - vm.label(address(vault), "vault"); // mint some tokens to trader1 _mintTokens(token1, trader1.addr, 1.001 ether); From 8961d762c20e92e8d61fa0894727b8a4a8ae243d Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Tue, 1 Oct 2024 11:30:40 +0530 Subject: [PATCH 5/5] chore: fix ci --- test/e2e/InternalBalances.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/InternalBalances.t.sol b/test/e2e/InternalBalances.t.sol index dc416e04..77461e26 100644 --- a/test/e2e/InternalBalances.t.sol +++ b/test/e2e/InternalBalances.t.sol @@ -6,7 +6,7 @@ import {Vm} from "forge-std/Vm.sol"; import {IERC20} from "src/contracts/interfaces/IERC20.sol"; import {IVault} from "src/contracts/interfaces/IVault.sol"; -import {GPv2Interaction, GPv2Order, GPv2Signing, SettlementEncoder} from "../libraries/encoders/SettlementEncoder.sol"; +import {GPv2Order, GPv2Signing, SettlementEncoder} from "../libraries/encoders/SettlementEncoder.sol"; import {Registry, TokenRegistry} from "../libraries/encoders/TokenRegistry.sol"; import {Helper, IERC20Mintable} from "./Helper.sol";