Skip to content

Commit

Permalink
chore: migrate GPv2VaultRelayer.transferFromAccounts test to Foundry (#…
Browse files Browse the repository at this point in the history
…173)

## Description

See title.

## Test Plan

CI.

## Related Issues

#124
  • Loading branch information
fedgiac authored Jul 18, 2024
1 parent 88464e6 commit 13795b4
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 138 deletions.
138 changes: 0 additions & 138 deletions test/GPv2VaultRelayer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,144 +27,6 @@ describe("GPv2VaultRelayer", () => {
vaultRelayer = await GPv2VaultRelayer.deploy(vault.address);
});

describe("transferFromAccounts", () => {
it("should revert if not called by the creator", async () => {
await expect(
vaultRelayer.connect(nonCreator).transferFromAccounts([]),
).to.be.revertedWith("not creator");
});

it("should execute ERC20 and Vault transfers", async () => {
const tokens = [
await waffle.deployMockContract(deployer, IERC20.abi),
await waffle.deployMockContract(deployer, IERC20.abi),
await waffle.deployMockContract(deployer, IERC20.abi),
];

const amount = ethers.utils.parseEther("13.37");
await tokens[0].mock.transferFrom
.withArgs(traders[0].address, creator.address, amount)
.returns(true);
await vault.mock.manageUserBalance
.withArgs([
{
kind: UserBalanceOpKind.TRANSFER_EXTERNAL,
asset: tokens[1].address,
amount,
sender: traders[1].address,
recipient: creator.address,
},
{
kind: UserBalanceOpKind.WITHDRAW_INTERNAL,
asset: tokens[2].address,
amount,
sender: traders[2].address,
recipient: creator.address,
},
])
.returns();

await expect(
vaultRelayer.transferFromAccounts([
{
account: traders[0].address,
token: tokens[0].address,
amount,
balance: OrderBalanceId.ERC20,
},
{
account: traders[1].address,
token: tokens[1].address,
amount,
balance: OrderBalanceId.EXTERNAL,
},
{
account: traders[2].address,
token: tokens[2].address,
amount,
balance: OrderBalanceId.INTERNAL,
},
]),
).to.not.be.reverted;
});

it("should revert on failed ERC20 transfers", async () => {
const token = await waffle.deployMockContract(deployer, IERC20.abi);

const amount = ethers.utils.parseEther("4.2");
await token.mock.transferFrom
.withArgs(traders[0].address, creator.address, amount)
.revertsWithReason("test error");

await expect(
vaultRelayer.transferFromAccounts([
{
account: traders[0].address,
token: token.address,
amount,
balance: OrderBalanceId.ERC20,
},
]),
).to.be.revertedWith("test error");
});

it("should revert on failed Vault transfers", async () => {
const token = await waffle.deployMockContract(deployer, IERC20.abi);

const amount = ethers.utils.parseEther("4.2");
await vault.mock.manageUserBalance
.withArgs([
{
kind: UserBalanceOpKind.TRANSFER_EXTERNAL,
asset: token.address,
amount,
sender: traders[0].address,
recipient: creator.address,
},
])
.revertsWithReason("test error");

await expect(
vaultRelayer.transferFromAccounts([
{
account: traders[0].address,
token: token.address,
amount,
balance: OrderBalanceId.EXTERNAL,
},
]),
).to.be.revertedWith("test error");
});

it("should revert on failed Vault withdrawals", async () => {
const token = await waffle.deployMockContract(deployer, IERC20.abi);

const amount = ethers.utils.parseEther("4.2");
await vault.mock.manageUserBalance
.withArgs([
{
kind: UserBalanceOpKind.WITHDRAW_INTERNAL,
asset: token.address,
amount,
sender: traders[0].address,
recipient: creator.address,
},
])
.revertsWithReason("test error");

await expect(
vaultRelayer.transferFromAccounts([
{
account: traders[0].address,
token: token.address,
amount,
balance: OrderBalanceId.INTERNAL,
},
]),
).to.be.revertedWith("test error");
});
});

describe("batchSwapWithFee", () => {
interface BatchSwapWithFee {
kind: SwapKind;
Expand Down
22 changes: 22 additions & 0 deletions test/GPv2VaultRelayer/Helper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity ^0.8.0;

import {Test} from "forge-std/Test.sol";

import {GPv2VaultRelayer, IVault} from "src/contracts/GPv2VaultRelayer.sol";

contract Helper is Test {
address payable internal creator = payable(makeAddr("GPv2VaultRelayer.Helper creator"));
IVault internal vault = IVault(makeAddr("GPv2VaultRelayer.Helper vault"));
GPv2VaultRelayer internal vaultRelayer;

function setUp() public {
// Some calls check if the vault is a contract. `0xfe` is the designated
// invalid instruction: this way, calling the vault without a mock
// triggers a revert with `InvalidEFOpcode`.
vm.etch(address(vault), hex"fe");

vm.prank(creator);
vaultRelayer = new GPv2VaultRelayer(vault);
}
}
120 changes: 120 additions & 0 deletions test/GPv2VaultRelayer/TransferFromAccounts.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity ^0.8.0;

import {
GPv2VaultRelayer, GPv2Transfer, IERC20, IVault, GPv2Transfer, GPv2Order
} from "src/contracts/GPv2VaultRelayer.sol";

import {Helper} from "./Helper.sol";

contract TransferFromAccounts is Helper {
function test_should_revert_if_not_called_by_the_creator() public {
vm.prank(makeAddr("not the creator"));
vm.expectRevert("GPv2: not creator");
vaultRelayer.transferFromAccounts(new GPv2Transfer.Data[](0));
}

function test_should_execute_ERC20_and_Vault_transfers() public {
IERC20 token0 = IERC20(makeAddr("token 0"));
IERC20 token1 = IERC20(makeAddr("token 1"));
IERC20 token2 = IERC20(makeAddr("token 2"));
address trader0 = makeAddr("trader 0");
address trader1 = makeAddr("trader 1");
address trader2 = makeAddr("trader 2");

uint256 amount = 13.37 ether;
vm.mockCall(address(token0), abi.encodeCall(IERC20.transferFrom, (trader0, creator, amount)), abi.encode(true));

IVault.UserBalanceOp[] memory vaultOps = new IVault.UserBalanceOp[](2);
vaultOps[0] = IVault.UserBalanceOp({
kind: IVault.UserBalanceOpKind.TRANSFER_EXTERNAL,
asset: token1,
amount: amount,
sender: trader1,
recipient: creator
});
vaultOps[1] = IVault.UserBalanceOp({
kind: IVault.UserBalanceOpKind.WITHDRAW_INTERNAL,
asset: token2,
amount: amount,
sender: trader2,
recipient: creator
});
vm.mockCall(address(vault), abi.encodeCall(IVault.manageUserBalance, (vaultOps)), hex"");

GPv2Transfer.Data[] memory transfers = new GPv2Transfer.Data[](3);
transfers[0] =
GPv2Transfer.Data({account: trader0, token: token0, amount: amount, balance: GPv2Order.BALANCE_ERC20});
transfers[1] =
GPv2Transfer.Data({account: trader1, token: token1, amount: amount, balance: GPv2Order.BALANCE_EXTERNAL});
transfers[2] =
GPv2Transfer.Data({account: trader2, token: token2, amount: amount, balance: GPv2Order.BALANCE_INTERNAL});

vm.prank(creator);
vaultRelayer.transferFromAccounts(transfers);
}

function test_reverts_on_failed_ERC20_transfer() public {
IERC20 token = IERC20(makeAddr("token"));
address trader = makeAddr("trader");

uint256 amount = 4.2 ether;
vm.mockCallRevert(address(token), abi.encodeCall(IERC20.transferFrom, (trader, creator, amount)), "mock revert");

GPv2Transfer.Data[] memory transfers = new GPv2Transfer.Data[](1);
transfers[0] =
GPv2Transfer.Data({account: trader, token: token, amount: amount, balance: GPv2Order.BALANCE_ERC20});

vm.prank(creator);
vm.expectRevert("mock revert");
vaultRelayer.transferFromAccounts(transfers);
}

function test_reverts_on_failed_vault_transfer() public {
IERC20 token = IERC20(makeAddr("token"));
address trader = makeAddr("trader");

uint256 amount = 4.2 ether;
IVault.UserBalanceOp[] memory vaultOps = new IVault.UserBalanceOp[](1);
vaultOps[0] = IVault.UserBalanceOp({
kind: IVault.UserBalanceOpKind.TRANSFER_EXTERNAL,
asset: token,
amount: amount,
sender: trader,
recipient: creator
});
vm.mockCallRevert(address(vault), abi.encodeCall(IVault.manageUserBalance, (vaultOps)), "mock revert");

GPv2Transfer.Data[] memory transfers = new GPv2Transfer.Data[](1);
transfers[0] =
GPv2Transfer.Data({account: trader, token: token, amount: amount, balance: GPv2Order.BALANCE_EXTERNAL});

vm.prank(creator);
vm.expectRevert("mock revert");
vaultRelayer.transferFromAccounts(transfers);
}

function test_reverts_on_failed_vault_withdrawal() public {
IERC20 token = IERC20(makeAddr("token"));
address trader = makeAddr("trader");

uint256 amount = 4.2 ether;
IVault.UserBalanceOp[] memory vaultOps = new IVault.UserBalanceOp[](1);
vaultOps[0] = IVault.UserBalanceOp({
kind: IVault.UserBalanceOpKind.WITHDRAW_INTERNAL,
asset: token,
amount: amount,
sender: trader,
recipient: creator
});
vm.mockCallRevert(address(vault), abi.encodeCall(IVault.manageUserBalance, (vaultOps)), "mock revert");

GPv2Transfer.Data[] memory transfers = new GPv2Transfer.Data[](1);
transfers[0] =
GPv2Transfer.Data({account: trader, token: token, amount: amount, balance: GPv2Order.BALANCE_INTERNAL});

vm.prank(creator);
vm.expectRevert("mock revert");
vaultRelayer.transferFromAccounts(transfers);
}
}

0 comments on commit 13795b4

Please sign in to comment.