Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(contracts-rfq): gas estimation tests [SLT-275] #3204

Merged
merged 6 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions .github/workflows/solidity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,10 @@ jobs:
with:
version: nightly

# TODO: consider defining a package-specific script for this
- name: Run tests and generate gas report
working-directory: './packages/${{matrix.package}}'
# Excluding tests with reverts to get accurate average gas cost estimates
run: forge test --nmt "(fail|revert)" --gas-report > "../../gas-report-${{ matrix.package }}.ansi"
env:
# make fuzzing semi-deterministic to avoid noisy gas cost estimation
# due to non-deterministic fuzzing (but still use pseudo-random fuzzing seeds)
FOUNDRY_FUZZ_SEED: 0x${{ github.event.pull_request.base.sha || github.sha }}
# Run separate set of tests (no fuzzing) to get accurate average gas cost estimates
run: forge test --mc GasBenchmark --gas-report > "../../gas-report-${{ matrix.package }}.ansi"
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved

- name: Compare gas reports
uses: Rubilmax/[email protected]
Expand Down
50 changes: 50 additions & 0 deletions packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {FastBridgeV2, FastBridgeV2Test, IFastBridge} from "./FastBridgeV2.t.sol";

// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2DstBaseTest is FastBridgeV2Test {
uint256 public constant LEFTOVER_BALANCE = 1 ether;

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

function deployFastBridge() public override returns (FastBridgeV2) {
return new FastBridgeV2(address(this));
}

function mintTokens() public virtual override {
dstToken.mint(address(relayerA), LEFTOVER_BALANCE + tokenParams.destAmount);
dstToken.mint(address(relayerB), LEFTOVER_BALANCE + tokenParams.destAmount);
deal(relayerA, LEFTOVER_BALANCE + ethParams.destAmount);
deal(relayerB, LEFTOVER_BALANCE + ethParams.destAmount);
vm.prank(relayerA);
dstToken.approve(address(fastBridge), type(uint256).max);
vm.prank(relayerB);
dstToken.approve(address(fastBridge), type(uint256).max);
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
}

// ══════════════════════════════════════════════════ HELPERS ══════════════════════════════════════════════════════

function relay(address caller, uint256 msgValue, IFastBridge.BridgeTransaction memory bridgeTx) public {
bytes memory request = abi.encode(bridgeTx);
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.relay{value: msgValue}(request);
}

function relayWithAddress(
address caller,
address relayer,
uint256 msgValue,
IFastBridge.BridgeTransaction memory bridgeTx
)
public
{
bytes memory request = abi.encode(bridgeTx);
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.relay{value: msgValue}(request, relayer);
}
}
41 changes: 2 additions & 39 deletions packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ pragma solidity ^0.8.20;

import {ChainIncorrect, DeadlineExceeded, TransactionRelayed, ZeroAddress} from "../contracts/libs/Errors.sol";

import {FastBridgeV2, FastBridgeV2Test, IFastBridge} from "./FastBridgeV2.t.sol";
import {FastBridgeV2DstBaseTest, IFastBridge} from "./FastBridgeV2.Dst.Base.t.sol";

// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2DstTest is FastBridgeV2Test {
contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest {
event BridgeRelayed(
bytes32 indexed transactionId,
address indexed relayer,
Expand All @@ -19,24 +19,6 @@ contract FastBridgeV2DstTest is FastBridgeV2Test {
uint256 chainGasAmount
);

uint256 public constant LEFTOVER_BALANCE = 1 ether;

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

function deployFastBridge() public override returns (FastBridgeV2) {
return new FastBridgeV2(address(this));
}

function mintTokens() public override {
dstToken.mint(address(relayerA), LEFTOVER_BALANCE + tokenParams.destAmount);
deal(relayerB, LEFTOVER_BALANCE + ethParams.destAmount);
vm.prank(relayerA);
dstToken.approve(address(fastBridge), type(uint256).max);
}

function expectBridgeRelayed(IFastBridge.BridgeTransaction memory bridgeTx, bytes32 txId, address relayer) public {
vm.expectEmit(address(fastBridge));
emit BridgeRelayed({
Expand All @@ -52,25 +34,6 @@ contract FastBridgeV2DstTest is FastBridgeV2Test {
});
}

function relay(address caller, uint256 msgValue, IFastBridge.BridgeTransaction memory bridgeTx) public {
bytes memory request = abi.encode(bridgeTx);
vm.prank(caller);
fastBridge.relay{value: msgValue}(request);
}

function relayWithAddress(
address caller,
address relayer,
uint256 msgValue,
IFastBridge.BridgeTransaction memory bridgeTx
)
public
{
bytes memory request = abi.encode(bridgeTx);
vm.prank(caller);
fastBridge.relay{value: msgValue}(request, relayer);
}

/// @notice RelayerA completes the ERC20 bridge request
function test_relay_token() public {
bytes32 txId = getTxId(tokenTx);
Expand Down
65 changes: 65 additions & 0 deletions packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {FastBridgeV2DstBaseTest} from "./FastBridgeV2.Dst.Base.t.sol";

// solhint-disable func-name-mixedcase, ordering
/// @notice This test is used to estimate the gas cost of FastBridgeV2 destination chain functions.
/// Very little state checks are performed, make sure to do full coverage in different tests.
contract FastBridgeV2DstGasBenchmarkTest is FastBridgeV2DstBaseTest {
uint256 public constant INITIAL_USER_BALANCE = 100 ether;

function mintTokens() public virtual override {
super.mintTokens();
deal(userB, INITIAL_USER_BALANCE);
dstToken.mint(userB, INITIAL_USER_BALANCE);
}

// ═══════════════════════════════════════════════════ TOKEN ═══════════════════════════════════════════════════════

function test_relay_token() public {
bytes32 txId = getTxId(tokenTx);
relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx});
(uint256 blockNumber, uint256 blockTimestamp, address relayer) = fastBridge.bridgeRelayDetails(txId);
assertEq(blockNumber, block.number);
assertEq(blockTimestamp, block.timestamp);
assertEq(relayer, relayerA);
assertEq(dstToken.balanceOf(userB), INITIAL_USER_BALANCE + tokenParams.destAmount);
assertEq(dstToken.balanceOf(relayerA), LEFTOVER_BALANCE);
}

function test_relay_token_withRelayerAddress() public {
bytes32 txId = getTxId(tokenTx);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx});
(uint256 blockNumber, uint256 blockTimestamp, address relayer) = fastBridge.bridgeRelayDetails(txId);
assertEq(blockNumber, block.number);
assertEq(blockTimestamp, block.timestamp);
assertEq(relayer, relayerA);
assertEq(dstToken.balanceOf(userB), INITIAL_USER_BALANCE + tokenParams.destAmount);
assertEq(dstToken.balanceOf(relayerB), LEFTOVER_BALANCE);
}
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved

// ════════════════════════════════════════════════════ ETH ════════════════════════════════════════════════════════

function test_relay_eth() public {
bytes32 txId = getTxId(ethTx);
relay({caller: relayerA, msgValue: ethParams.destAmount, bridgeTx: ethTx});
(uint256 blockNumber, uint256 blockTimestamp, address relayer) = fastBridge.bridgeRelayDetails(txId);
assertEq(blockNumber, block.number);
assertEq(blockTimestamp, block.timestamp);
assertEq(relayer, relayerA);
assertEq(address(userB).balance, INITIAL_USER_BALANCE + ethParams.destAmount);
assertEq(address(relayerA).balance, LEFTOVER_BALANCE);
}

function test_relay_eth_withRelayerAddress() public {
bytes32 txId = getTxId(ethTx);
relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ethParams.destAmount, bridgeTx: ethTx});
(uint256 blockNumber, uint256 blockTimestamp, address relayer) = fastBridge.bridgeRelayDetails(txId);
assertEq(blockNumber, block.number);
assertEq(blockTimestamp, block.timestamp);
assertEq(relayer, relayerA);
assertEq(address(userB).balance, INITIAL_USER_BALANCE + ethParams.destAmount);
assertEq(address(relayerB).balance, LEFTOVER_BALANCE);
}
ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol";

// solhint-disable func-name-mixedcase, ordering
contract FastBridgeV2GasBenchmarkSrcProtocolFeesTest is FastBridgeV2GasBenchmarkSrcTest {
function configureFastBridge() public virtual override {
super.configureFastBridge();
fastBridge.grantRole(fastBridge.GOVERNOR_ROLE(), address(this));
fastBridge.setProtocolFeeRate(1e4); // 1%
}

function createFixtures() public virtual override {
super.createFixtures();
tokenTx.originFeeAmount = 0.01e6;
tokenTx.originAmount = 0.99e6;
tokenTx.destAmount = 0.98e6;
tokenParams.destAmount = 0.98e6;
ethTx.originFeeAmount = 0.01 ether;
ethTx.originAmount = 0.99 ether;
ethTx.destAmount = 0.98 ether;
ethParams.destAmount = 0.98 ether;

// Copy txs to bridged and proven with different nonce
bridgedTokenTx = tokenTx;
provenTokenTx = tokenTx;
bridgedEthTx = ethTx;
provenEthTx = ethTx;

bridgedTokenTx.nonce = 0;
bridgedEthTx.nonce = 1;
provenTokenTx.nonce = 2;
provenEthTx.nonce = 3;
}
}
Loading
Loading