Skip to content

Commit

Permalink
test: use mainnet addresses in fork tests (#55)
Browse files Browse the repository at this point in the history
* test: use mainnet address in fork testing

* script: remove virtual modifier from run script

* build: ignore fork tests for non optimized profiles
test(fork): initialize default contract in fork setup
test(fork): use deployed factory admin

* test: load factoryAdmin in Fork setUp

Co-authored-by: Andrei Vlad Birgaoanu <[email protected]>

---------

Co-authored-by: Andrei Vlad Birgaoanu <[email protected]>
  • Loading branch information
smol-ninja and andreivladbrg authored Feb 3, 2025
1 parent 76166a9 commit 1c19bd5
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 48 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@
"prepare": "husky",
"prettier:check": "prettier --check \"**/*.{json,md,yml}\"",
"prettier:write": "prettier --write \"**/*.{json,md,yml}\"",
"test": "forge test",
"test:lite": "FOUNDRY_PROFILE=lite forge test",
"test": "forge test --nmt testFork",
"test:lite": "FOUNDRY_PROFILE=lite forge test --nmt testFork",
"test:optimized": "bun run build:optimized && FOUNDRY_PROFILE=test-optimized forge test"
}
}
2 changes: 1 addition & 1 deletion script/CreateMerkleInstant.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { BaseScript } from "./Base.s.sol";
/// @dev Creates a dummy campaign to airdrop tokens instantly.
contract CreateMerkleInstant is BaseScript {
/// @dev Deploy via Forge.
function run() public virtual broadcast returns (ISablierMerkleInstant merkleInstant) {
function run() public broadcast returns (ISablierMerkleInstant merkleInstant) {
ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0x71DD3Ca88E7564416E5C2E350090C12Bf8F6144a);

// Prepare the constructor parameters.
Expand Down
2 changes: 1 addition & 1 deletion script/CreateMerkleLL.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// @dev Creates a dummy campaign to airdrop tokens through Lockup Linear.
contract CreateMerkleLL is BaseScript {
/// @dev Deploy via Forge.
function run() public virtual broadcast returns (ISablierMerkleLL merkleLL) {
function run() public broadcast returns (ISablierMerkleLL merkleLL) {
ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0x71DD3Ca88E7564416E5C2E350090C12Bf8F6144a);

// Prepare the constructor parameters.
Expand Down
2 changes: 1 addition & 1 deletion script/CreateMerkleLT.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { BaseScript } from "./Base.s.sol";
/// @dev Creates a dummy campaign to airdrop tokens through Lockup Tranched.
contract CreateMerkleLT is BaseScript {
/// @dev Deploy via Forge.
function run() public virtual broadcast returns (ISablierMerkleLT merkleLT) {
function run() public broadcast returns (ISablierMerkleLT merkleLT) {
ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0x71DD3Ca88E7564416E5C2E350090C12Bf8F6144a);

// Prepare the constructor parameters.
Expand Down
2 changes: 1 addition & 1 deletion script/DeployDeterministicMerkleFactory.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { BaseScript } from "./Base.s.sol";
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicMerkleFactory is BaseScript {
/// @dev Deploy via Forge.
function run() public virtual broadcast returns (SablierMerkleFactory merkleFactory) {
function run() public broadcast returns (SablierMerkleFactory merkleFactory) {
address initialAdmin = adminMap[block.chainid];
merkleFactory = new SablierMerkleFactory{ salt: SALT }(initialAdmin);
}
Expand Down
2 changes: 1 addition & 1 deletion script/DeployMerkleFactory.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { BaseScript } from "./Base.s.sol";

contract DeployMerkleFactory is BaseScript {
/// @dev Deploy via Forge.
function run() public virtual broadcast returns (SablierMerkleFactory merkleFactory) {
function run() public broadcast returns (SablierMerkleFactory merkleFactory) {
address initialAdmin = adminMap[block.chainid];
merkleFactory = new SablierMerkleFactory(initialAdmin);
}
Expand Down
33 changes: 18 additions & 15 deletions tests/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,12 @@ abstract contract Base_Test is Assertions, Constants, DeployOptimized, Modifiers
view
returns (address)
{
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams();
baseParams.token = token_;
baseParams.expiration = expiration;
baseParams.initialAdmin = campaignOwner;
baseParams.merkleRoot = merkleRoot;
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({
campaignOwner: campaignOwner,
token_: token_,
expiration: expiration,
merkleRoot: merkleRoot
});

bytes32 salt = keccak256(abi.encodePacked(campaignCreator, abi.encode(baseParams)));
bytes32 creationBytecodeHash =
Expand All @@ -218,11 +219,12 @@ abstract contract Base_Test is Assertions, Constants, DeployOptimized, Modifiers
view
returns (address)
{
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams();
baseParams.token = token_;
baseParams.expiration = expiration;
baseParams.initialAdmin = campaignOwner;
baseParams.merkleRoot = merkleRoot;
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({
campaignOwner: campaignOwner,
token_: token_,
expiration: expiration,
merkleRoot: merkleRoot
});
bytes32 salt = keccak256(
abi.encodePacked(
campaignCreator,
Expand Down Expand Up @@ -253,11 +255,12 @@ abstract contract Base_Test is Assertions, Constants, DeployOptimized, Modifiers
view
returns (address)
{
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams();
baseParams.token = token_;
baseParams.expiration = expiration;
baseParams.initialAdmin = campaignOwner;
baseParams.merkleRoot = merkleRoot;
MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({
campaignOwner: campaignOwner,
token_: token_,
expiration: expiration,
merkleRoot: merkleRoot
});
bytes32 salt = keccak256(
abi.encodePacked(
campaignCreator,
Expand Down
21 changes: 16 additions & 5 deletions tests/fork/Fork.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ pragma solidity >=0.8.22 <0.9.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISablierLockup } from "@sablier/lockup/src/interfaces/ISablierLockup.sol";
import { Merkle } from "murky/src/Merkle.sol";
import { ISablierMerkleFactory } from "src/interfaces/ISablierMerkleFactory.sol";

import { Base_Test } from "../Base.t.sol";
import { Defaults } from "../utils/Defaults.sol";

/// @notice Common logic needed by all fork tests.
abstract contract Fork_Test is Base_Test, Merkle {
Expand All @@ -14,6 +16,7 @@ abstract contract Fork_Test is Base_Test, Merkle {
//////////////////////////////////////////////////////////////////////////*/

IERC20 internal immutable FORK_TOKEN;
address internal factoryAdmin;

/*//////////////////////////////////////////////////////////////////////////
CONSTRUCTOR
Expand All @@ -29,12 +32,20 @@ abstract contract Fork_Test is Base_Test, Merkle {

function setUp() public virtual override {
// Fork Ethereum Mainnet at a specific block number.
vm.createSelectFork({ blockNumber: 21_745_237, urlOrAlias: "mainnet" });
vm.createSelectFork({ blockNumber: 21_719_244, urlOrAlias: "mainnet" });

// Set up the parent test contract.
Base_Test.setUp();

// Load the pre-deployed external dependencies.
// Load deployed addresses from Ethereum mainnet.
merkleFactory = ISablierMerkleFactory(0x71DD3Ca88E7564416E5C2E350090C12Bf8F6144a);
lockup = ISablierLockup(0x7C01AA3783577E15fD7e272443D44B92d5b21056);

// Load the factory admin from mainnet.
factoryAdmin = merkleFactory.admin();

// Initialize the defaults contract.
defaults = new Defaults();

// Set the default fee for campaign.
resetPrank({ msgSender: factoryAdmin });
merkleFactory.setDefaultFee(defaults.FEE());
}
}
14 changes: 7 additions & 7 deletions tests/fork/merkle-campaign/MerkleInstant.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test {
uint256[] public leaves;

function testForkFuzz_MerkleInstant(Params memory params) external {
vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner);
vm.assume(params.campaignOwner != address(0));
vm.assume(params.leafData.length > 0);
assumeNoBlacklisted({ token: address(FORK_TOKEN), addr: params.campaignOwner });
params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1);
Expand Down Expand Up @@ -80,7 +80,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test {
// Avoid zero recipient addresses.
uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max);
// Avoid recipient to be the protocol admin.
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != users.admin
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != factoryAdmin
? address(uint160(boundedRecipientSeed))
: address(uint160(boundedRecipientSeed) + 1);
}
Expand Down Expand Up @@ -109,8 +109,8 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test {
vars.baseParams = defaults.baseParams({
campaignOwner: params.campaignOwner,
token_: FORK_TOKEN,
merkleRoot: vars.merkleRoot,
expiration: params.expiration
expiration: params.expiration,
merkleRoot: vars.merkleRoot
});

vm.expectEmit({ emitter: address(merkleFactory) });
Expand Down Expand Up @@ -146,7 +146,7 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test {
resetPrank({ msgSender: vars.recipients[params.posBeforeSort] });
vm.deal(vars.recipients[params.posBeforeSort], 1 ether);

uint256 initialAdminBalance = users.admin.balance;
uint256 initialAdminBalance = factoryAdmin.balance;

assertFalse(vars.merkleInstant.hasClaimed(vars.indexes[params.posBeforeSort]));

Expand Down Expand Up @@ -223,13 +223,13 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test {

vm.expectEmit({ emitter: address(merkleFactory) });
emit ISablierMerkleFactory.CollectFees({
admin: users.admin,
admin: factoryAdmin,
merkleBase: vars.merkleInstant,
feeAmount: defaults.FEE()
});
merkleFactory.collectFees({ merkleBase: vars.merkleInstant });

assertEq(address(vars.merkleInstant).balance, 0, "merkleInstant ETH balance");
assertEq(users.admin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
assertEq(factoryAdmin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
}
}
14 changes: 7 additions & 7 deletions tests/fork/merkle-campaign/MerkleLL.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test {
uint256[] public leaves;

function testForkFuzz_MerkleLL(Params memory params) external {
vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner);
vm.assume(params.campaignOwner != address(0));
vm.assume(params.leafData.length > 0);
assumeNoBlacklisted({ token: address(FORK_TOKEN), addr: params.campaignOwner });
params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1);
Expand Down Expand Up @@ -83,7 +83,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test {
// Avoid zero recipient addresses.
uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max);
// Avoid recipient to be the protocol admin.
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != users.admin
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != factoryAdmin
? address(uint160(boundedRecipientSeed))
: address(uint160(boundedRecipientSeed) + 1);
}
Expand Down Expand Up @@ -112,8 +112,8 @@ abstract contract MerkleLL_Fork_Test is Fork_Test {
vars.baseParams = defaults.baseParams({
campaignOwner: params.campaignOwner,
token_: FORK_TOKEN,
merkleRoot: vars.merkleRoot,
expiration: params.expiration
expiration: params.expiration,
merkleRoot: vars.merkleRoot
});

vm.expectEmit({ emitter: address(merkleFactory) });
Expand Down Expand Up @@ -153,7 +153,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test {
resetPrank({ msgSender: vars.recipients[params.posBeforeSort] });
vm.deal(vars.recipients[params.posBeforeSort], 1 ether);

uint256 initialAdminBalance = users.admin.balance;
uint256 initialAdminBalance = factoryAdmin.balance;

assertFalse(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort]));

Expand Down Expand Up @@ -263,13 +263,13 @@ abstract contract MerkleLL_Fork_Test is Fork_Test {

vm.expectEmit({ emitter: address(merkleFactory) });
emit ISablierMerkleFactory.CollectFees({
admin: users.admin,
admin: factoryAdmin,
merkleBase: vars.merkleLL,
feeAmount: defaults.FEE()
});
merkleFactory.collectFees({ merkleBase: vars.merkleLL });

assertEq(address(vars.merkleLL).balance, 0, "merkleLL ETH balance");
assertEq(users.admin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
assertEq(factoryAdmin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
}
}
14 changes: 7 additions & 7 deletions tests/fork/merkle-campaign/MerkleLT.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test {
uint256[] public leaves;

function testForkFuzz_MerkleLT(Params memory params) external {
vm.assume(params.campaignOwner != address(0) && params.campaignOwner != users.campaignOwner);
vm.assume(params.campaignOwner != address(0));
vm.assume(params.leafData.length > 0);
assumeNoBlacklisted({ token: address(FORK_TOKEN), addr: params.campaignOwner });
params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1);
Expand Down Expand Up @@ -81,7 +81,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test {
// Avoid zero recipient addresses.
uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max);
// Avoid recipient to be the protocol admin.
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != users.admin
vars.recipients[i] = address(uint160(boundedRecipientSeed)) != factoryAdmin
? address(uint160(boundedRecipientSeed))
: address(uint160(boundedRecipientSeed) + 1);
}
Expand Down Expand Up @@ -110,8 +110,8 @@ abstract contract MerkleLT_Fork_Test is Fork_Test {
vars.baseParams = defaults.baseParams({
campaignOwner: params.campaignOwner,
token_: FORK_TOKEN,
merkleRoot: vars.merkleRoot,
expiration: params.expiration
expiration: params.expiration,
merkleRoot: vars.merkleRoot
});

vm.expectEmit({ emitter: address(merkleFactory) });
Expand Down Expand Up @@ -154,7 +154,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test {
resetPrank({ msgSender: vars.recipients[params.posBeforeSort] });
vm.deal(vars.recipients[params.posBeforeSort], 1 ether);

uint256 initialAdminBalance = users.admin.balance;
uint256 initialAdminBalance = factoryAdmin.balance;

assertFalse(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort]));

Expand Down Expand Up @@ -253,13 +253,13 @@ abstract contract MerkleLT_Fork_Test is Fork_Test {

vm.expectEmit({ emitter: address(merkleFactory) });
emit ISablierMerkleFactory.CollectFees({
admin: users.admin,
admin: factoryAdmin,
merkleBase: vars.merkleLT,
feeAmount: defaults.FEE()
});
merkleFactory.collectFees({ merkleBase: vars.merkleLT });

assertEq(address(vars.merkleLT).balance, 0, "merkleLT ETH balance");
assertEq(users.admin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
assertEq(factoryAdmin.balance, initialAdminBalance + defaults.FEE(), "admin ETH balance");
}
}

0 comments on commit 1c19bd5

Please sign in to comment.