Skip to content

Commit

Permalink
test: FastBridgeV2 + TokenZapV1 integration
Browse files Browse the repository at this point in the history
  • Loading branch information
ChiTimesChi committed Oct 30, 2024
1 parent e76174f commit ae4fe60
Show file tree
Hide file tree
Showing 5 changed files with 392 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {TokenZapV1IntegrationTest, VaultManyArguments, IFastBridge, IFastBridgeV2} from "./TokenZapV1.t.sol";

// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2TokenZapV1DstTest is TokenZapV1IntegrationTest {
event BridgeRelayed(
bytes32 indexed transactionId,
address indexed relayer,
address indexed to,
uint32 originChainId,
address originToken,
address destToken,
uint256 originAmount,
uint256 destAmount,
uint256 chainGasAmount
);

function setUp() public virtual override {
vm.chainId(DST_CHAIN_ID);
super.setUp();
}

function mintTokens() public virtual override {
deal(relayer, DST_AMOUNT);
dstToken.mint(relayer, DST_AMOUNT);
vm.prank(relayer);
dstToken.approve(address(fastBridge), type(uint256).max);
}

function relay(
IFastBridge.BridgeParams memory params,
IFastBridgeV2.BridgeParamsV2 memory paramsV2,
bool isToken
)
public
{
bytes memory encodedBridgeTx = encodeBridgeTx(params, paramsV2);
vm.prank({msgSender: relayer, txOrigin: relayer});
fastBridge.relay{value: isToken ? paramsV2.zapNative : DST_AMOUNT}(encodedBridgeTx);
}

function expectEventBridgeRelayed(
IFastBridge.BridgeParams memory params,
IFastBridgeV2.BridgeParamsV2 memory paramsV2,
bool isToken
)
public
{
bytes32 txId = keccak256(encodeBridgeTx(params, paramsV2));
vm.expectEmit(address(fastBridge));
emit BridgeRelayed({
transactionId: txId,
relayer: relayer,
to: address(dstZap),
originChainId: SRC_CHAIN_ID,
originToken: isToken ? address(srcToken) : NATIVE_GAS_TOKEN,
destToken: isToken ? address(dstToken) : NATIVE_GAS_TOKEN,
originAmount: SRC_AMOUNT,
destAmount: DST_AMOUNT,
chainGasAmount: paramsV2.zapNative
});
}

function checkBalances(bool isToken) public view {
if (isToken) {
assertEq(dstToken.balanceOf(user), 0);
assertEq(dstToken.balanceOf(relayer), 0);
assertEq(dstToken.balanceOf(address(fastBridge)), 0);
assertEq(dstToken.balanceOf(address(dstZap)), 0);
assertEq(dstToken.balanceOf(address(dstVault)), DST_AMOUNT);
assertEq(dstVault.balanceOf(user, address(dstToken)), DST_AMOUNT);
} else {
assertEq(address(user).balance, 0);
assertEq(address(relayer).balance, 0);
assertEq(address(fastBridge).balance, 0);
assertEq(address(dstZap).balance, 0);
assertEq(address(dstVault).balance, DST_AMOUNT);
assertEq(dstVault.balanceOf(user, NATIVE_GAS_TOKEN), DST_AMOUNT);
}
}

function test_relay_depositTokenParams() public {
expectEventBridgeRelayed({params: tokenParams, paramsV2: depositTokenParams, isToken: true});
relay({params: tokenParams, paramsV2: depositTokenParams, isToken: true});
checkBalances({isToken: true});
}

function test_relay_depositTokenWithZapNativeParams() public {
expectEventBridgeRelayed({params: tokenParams, paramsV2: depositTokenWithZapNativeParams, isToken: true});
relay({params: tokenParams, paramsV2: depositTokenWithZapNativeParams, isToken: true});
checkBalances({isToken: true});
// Extra ETH will be also custodied by the Vault
assertEq(address(dstVault).balance, ZAP_NATIVE);
}

function test_relay_depositTokenRevertParams_revert() public {
vm.expectRevert(VaultManyArguments.VaultManyArguments__SomeError.selector);
relay({params: tokenParams, paramsV2: depositTokenRevertParams, isToken: true});
}

function test_relay_depositNativeParams() public {
expectEventBridgeRelayed({params: nativeParams, paramsV2: depositNativeParams, isToken: false});
relay({params: nativeParams, paramsV2: depositNativeParams, isToken: false});
checkBalances({isToken: false});
}

function test_relay_depositNativeNoAmountParams() public {
expectEventBridgeRelayed({params: nativeParams, paramsV2: depositNativeNoAmountParams, isToken: false});
relay({params: nativeParams, paramsV2: depositNativeNoAmountParams, isToken: false});
checkBalances({isToken: false});
}

function test_relay_depositNativeRevertParams_revert() public {
vm.expectRevert(VaultManyArguments.VaultManyArguments__SomeError.selector);
relay({params: nativeParams, paramsV2: depositNativeRevertParams, isToken: false});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {TokenZapV1IntegrationTest, IFastBridge, IFastBridgeV2} from "./TokenZapV1.t.sol";

// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2TokenZapV1SrcTest is TokenZapV1IntegrationTest {
event BridgeRequested(
bytes32 indexed transactionId,
address indexed sender,
bytes request,
uint32 destChainId,
address originToken,
address destToken,
uint256 originAmount,
uint256 destAmount,
bool sendChainGas
);

function setUp() public virtual override {
vm.chainId(SRC_CHAIN_ID);
super.setUp();
}

function mintTokens() public virtual override {
deal(user, SRC_AMOUNT);
srcToken.mint(user, SRC_AMOUNT);
vm.prank(user);
srcToken.approve(address(fastBridge), type(uint256).max);
}

function bridge(
IFastBridge.BridgeParams memory params,
IFastBridgeV2.BridgeParamsV2 memory paramsV2,
bool isToken
)
public
{
vm.prank({msgSender: user, txOrigin: user});
fastBridge.bridge{value: isToken ? 0 : SRC_AMOUNT}(params, paramsV2);
}

function expectEventBridgeRequested(
IFastBridge.BridgeParams memory params,
IFastBridgeV2.BridgeParamsV2 memory paramsV2,
bool isToken
)
public
{
bytes memory encodedBridgeTx = encodeBridgeTx(params, paramsV2);
bytes32 txId = keccak256(encodedBridgeTx);
vm.expectEmit(address(fastBridge));
emit BridgeRequested({
transactionId: txId,
sender: user,
request: encodedBridgeTx,
destChainId: DST_CHAIN_ID,
originToken: isToken ? address(srcToken) : NATIVE_GAS_TOKEN,
destToken: isToken ? address(dstToken) : NATIVE_GAS_TOKEN,
originAmount: SRC_AMOUNT,
destAmount: DST_AMOUNT,
sendChainGas: paramsV2.zapNative > 0
});
}

function checkBalances(bool isToken) public view {
if (isToken) {
assertEq(srcToken.balanceOf(user), 0);
assertEq(srcToken.balanceOf(address(fastBridge)), SRC_AMOUNT);
} else {
assertEq(address(user).balance, 0);
assertEq(address(fastBridge).balance, SRC_AMOUNT);
}
}

function test_bridge_depositTokenParams() public {
expectEventBridgeRequested({params: tokenParams, paramsV2: depositTokenParams, isToken: true});
bridge({params: tokenParams, paramsV2: depositTokenParams, isToken: true});
checkBalances({isToken: true});
}

function test_bridge_depositTokenWithZapNativeParams() public {
expectEventBridgeRequested({params: tokenParams, paramsV2: depositTokenWithZapNativeParams, isToken: true});
bridge({params: tokenParams, paramsV2: depositTokenWithZapNativeParams, isToken: true});
checkBalances({isToken: true});
}

function test_bridge_depositTokenRevertParams() public {
expectEventBridgeRequested({params: tokenParams, paramsV2: depositTokenRevertParams, isToken: true});
bridge({params: tokenParams, paramsV2: depositTokenRevertParams, isToken: true});
checkBalances({isToken: true});
}

function test_bridge_depositNativeParams() public {
expectEventBridgeRequested({params: nativeParams, paramsV2: depositNativeParams, isToken: false});
bridge({params: nativeParams, paramsV2: depositNativeParams, isToken: false});
checkBalances({isToken: false});
}

function test_bridge_depositNativeNoAmountParams() public {
expectEventBridgeRequested({params: nativeParams, paramsV2: depositNativeNoAmountParams, isToken: false});
bridge({params: nativeParams, paramsV2: depositNativeNoAmountParams, isToken: false});
checkBalances({isToken: false});
}

function test_bridge_depositNativeRevertParams() public {
expectEventBridgeRequested({params: nativeParams, paramsV2: depositNativeRevertParams, isToken: false});
bridge({params: nativeParams, paramsV2: depositNativeRevertParams, isToken: false});
checkBalances({isToken: false});
}
}
160 changes: 160 additions & 0 deletions packages/contracts-rfq/test/integration/TokenZapV1.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FastBridgeV2, IFastBridge, IFastBridgeV2} from "../../contracts/FastBridgeV2.sol";
import {BridgeTransactionV2Lib} from "../../contracts/libs/BridgeTransactionV2.sol";
import {ZapDataV1} from "../../contracts/libs/ZapDataV1.sol";
import {TokenZapV1} from "../../contracts/zaps/TokenZapV1.sol";

import {VaultManyArguments} from "../mocks/VaultManyArguments.sol";
import {MockERC20} from "../MockERC20.sol";

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

// solhint-disable ordering
abstract contract TokenZapV1IntegrationTest is Test {
address internal constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

uint32 internal constant SRC_CHAIN_ID = 1337;
uint32 internal constant DST_CHAIN_ID = 7331;

uint256 internal constant SRC_AMOUNT = 1 ether;
uint256 internal constant DST_AMOUNT = 0.9999 ether;
uint256 internal constant ZAP_NATIVE = 123_456;

FastBridgeV2 internal fastBridge;
TokenZapV1 internal dstZap;

address internal user = makeAddr("User");
address internal relayer = makeAddr("Relayer");

MockERC20 internal srcToken;
MockERC20 internal dstToken;

VaultManyArguments internal dstVault;

IFastBridge.BridgeParams internal tokenParams;
IFastBridge.BridgeParams internal nativeParams;

IFastBridgeV2.BridgeParamsV2 internal depositTokenParams;
IFastBridgeV2.BridgeParamsV2 internal depositTokenWithZapNativeParams;
IFastBridgeV2.BridgeParamsV2 internal depositTokenRevertParams;
IFastBridgeV2.BridgeParamsV2 internal depositNativeParams;
IFastBridgeV2.BridgeParamsV2 internal depositNativeNoAmountParams;
IFastBridgeV2.BridgeParamsV2 internal depositNativeRevertParams;

function setUp() public virtual {
fastBridge = new FastBridgeV2(address(this));
fastBridge.grantRole(fastBridge.RELAYER_ROLE(), relayer);

srcToken = new MockERC20("SRC", 18);
dstToken = new MockERC20("DST", 18);

dstZap = new TokenZapV1();
dstVault = new VaultManyArguments();

createFixtures();
mintTokens();
}

function createFixtures() public virtual {
tokenParams = IFastBridge.BridgeParams({
dstChainId: DST_CHAIN_ID,
sender: user,
to: address(dstZap),
originToken: address(srcToken),
destToken: address(dstToken),
originAmount: SRC_AMOUNT,
destAmount: DST_AMOUNT,
sendChainGas: false,
deadline: block.timestamp + 1 days
});
nativeParams = IFastBridge.BridgeParams({
dstChainId: DST_CHAIN_ID,
sender: user,
to: address(dstZap),
originToken: NATIVE_GAS_TOKEN,
destToken: NATIVE_GAS_TOKEN,
originAmount: SRC_AMOUNT,
destAmount: DST_AMOUNT,
sendChainGas: false,
deadline: block.timestamp + 1 days
});
// Deposit token
bytes memory zapData = dstZap.encodeZapData({
target: address(dstVault),
payload: getDepositPayload(address(dstToken)),
amountPosition: 4 + 32 * 2
});
depositTokenParams.zapData = zapData;
depositTokenWithZapNativeParams.zapData = zapData;
depositTokenWithZapNativeParams.zapNative = ZAP_NATIVE;
// Deposit native
depositNativeParams.zapData = dstZap.encodeZapData({
target: address(dstVault),
payload: getDepositPayload(NATIVE_GAS_TOKEN),
amountPosition: 4 + 32 * 2
});
// Deposit no amount
depositNativeNoAmountParams.zapData = dstZap.encodeZapData({
target: address(dstVault),
payload: getDepositNoAmountPayload(),
amountPosition: ZapDataV1.AMOUNT_NOT_PRESENT
});
// Deposit revert
depositTokenRevertParams.zapData = dstZap.encodeZapData({
target: address(dstVault),
payload: getDepositRevertPayload(),
amountPosition: ZapDataV1.AMOUNT_NOT_PRESENT
});
depositNativeRevertParams.zapData = dstZap.encodeZapData({
target: address(dstVault),
payload: getDepositRevertPayload(),
amountPosition: ZapDataV1.AMOUNT_NOT_PRESENT
});
}

function mintTokens() public virtual;

function encodeBridgeTx(
IFastBridge.BridgeParams memory params,
IFastBridgeV2.BridgeParamsV2 memory paramsV2
)
public
pure
returns (bytes memory)
{
IFastBridgeV2.BridgeTransactionV2 memory bridgeTx = IFastBridgeV2.BridgeTransactionV2({
originChainId: SRC_CHAIN_ID,
destChainId: params.dstChainId,
originSender: params.sender,
destRecipient: params.to,
originToken: params.originToken,
destToken: params.destToken,
originAmount: params.originAmount,
destAmount: params.destAmount,
// No protocol fees for the test
originFeeAmount: 0,
deadline: params.deadline,
// Single tx is sent, so nonce is 0
nonce: 0,
exclusivityRelayer: address(0),
exclusivityEndTime: 0,
zapNative: paramsV2.zapNative,
zapData: paramsV2.zapData
});
return BridgeTransactionV2Lib.encodeV2(bridgeTx);
}

function getDepositPayload(address token) public view returns (bytes memory) {
return abi.encodeCall(dstVault.deposit, (token, abi.encode(token), DST_AMOUNT, user, abi.encode(user)));
}

function getDepositNoAmountPayload() public view returns (bytes memory) {
return abi.encodeCall(dstVault.depositNoAmount, (user));
}

function getDepositRevertPayload() public view returns (bytes memory) {
return abi.encodeCall(dstVault.depositWithRevert, ());
}
}
Loading

0 comments on commit ae4fe60

Please sign in to comment.