From 3c7d2c6f7d8a229b2aa0ee60f6460870a1d178be Mon Sep 17 00:00:00 2001 From: Rooh Afza <96720500+r0ohafza@users.noreply.github.com> Date: Mon, 23 Dec 2024 02:12:09 -0800 Subject: [PATCH] feat: split v2.1 (#55) * feat(splitv2.1): use forceApprove and other nit changes * feat(splitv2.1): store last updated block number * fix: lint * test: add usdt distribution test on mainnet fork * chore: add missing env to gh action * fix: update doc * feat: pausable deposit to warehouse * feat: update v2.1 deployment script * fix: update wallet version --- .github/workflows/test.yml | 1 + packages/smart-vaults/deployments/1.json | 2 +- packages/smart-vaults/deployments/10.json | 2 +- .../smart-vaults/deployments/11155111.json | 2 +- .../smart-vaults/deployments/11155420.json | 2 +- .../smart-vaults/deployments/7777777.json | 2 +- packages/smart-vaults/deployments/8453.json | 2 +- packages/smart-vaults/deployments/84532.json | 2 +- .../smart-vaults/deployments/999999999.json | 2 +- packages/splits-v2/README.md | 12 ++-- packages/splits-v2/deployments/360.json | 2 +- .../splits-v2/script/SplitFactoryV2.s.sol | 20 ++----- packages/splits-v2/src/SplitsWarehouse.sol | 6 +- .../src/splitters/SplitFactoryV2.sol | 22 +++++-- .../splits-v2/src/splitters/SplitWalletV2.sol | 11 ++-- .../src/splitters/pull/PullSplit.sol | 28 +++++---- .../src/splitters/push/PushSplit.sol | 1 + .../splits-v2/test/splitters/PullSplit.t.sol | 59 ++++++++++++++++++- .../test/splitters/SplitFactoryV2.t.sol | 12 +++- .../test/splitters/SplitWalletV2.t.sol | 4 ++ .../test/warehouse/SplitsWarehouseHandler.sol | 11 ++++ 21 files changed, 150 insertions(+), 55 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 51be04d..b7faf41 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,7 @@ on: env: FOUNDRY_PROFILE: ci + MAINNET_RPC_URL: ${{ vars.MAINNET_RPC_URL }} jobs: check: diff --git a/packages/smart-vaults/deployments/1.json b/packages/smart-vaults/deployments/1.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/1.json +++ b/packages/smart-vaults/deployments/1.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/10.json b/packages/smart-vaults/deployments/10.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/10.json +++ b/packages/smart-vaults/deployments/10.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/11155111.json b/packages/smart-vaults/deployments/11155111.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/11155111.json +++ b/packages/smart-vaults/deployments/11155111.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/11155420.json b/packages/smart-vaults/deployments/11155420.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/11155420.json +++ b/packages/smart-vaults/deployments/11155420.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/7777777.json b/packages/smart-vaults/deployments/7777777.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/7777777.json +++ b/packages/smart-vaults/deployments/7777777.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/8453.json b/packages/smart-vaults/deployments/8453.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/8453.json +++ b/packages/smart-vaults/deployments/8453.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/84532.json b/packages/smart-vaults/deployments/84532.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/84532.json +++ b/packages/smart-vaults/deployments/84532.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/smart-vaults/deployments/999999999.json b/packages/smart-vaults/deployments/999999999.json index 2833395..d71a174 100644 --- a/packages/smart-vaults/deployments/999999999.json +++ b/packages/smart-vaults/deployments/999999999.json @@ -1,3 +1,3 @@ { "SmartVaultFactory": "0x8E6Af8Ed94E87B4402D0272C5D6b0D47F0483e7C" -} \ No newline at end of file +} diff --git a/packages/splits-v2/README.md b/packages/splits-v2/README.md index 16a7b55..59ffa30 100644 --- a/packages/splits-v2/README.md +++ b/packages/splits-v2/README.md @@ -66,13 +66,15 @@ For a test run, use the following command: To deploy split v2 contracts on a given chain, please make sure the following requirements are met: -1. Send the minimum amount of native gas token for deployment to the deployer address: `0x60C65c9a8674DA22e89C7d09e839908B9f0ecC3a`. Mainnet deployment transactions for gas cost: +1. Send the minimum amount of native gas token for deployment to the deployer address: + `0x60C65c9a8674DA22e89C7d09e839908B9f0ecC3a`. Mainnet deployment transactions for gas cost: - * [Warehouse](https://etherscan.io/tx/0x9a24df13332fafff979c35d5475be6a0594b9e8a632b1ff603150c413b7c134c) - * [Pull Splits](https://etherscan.io/tx/0xe81eb2677e597ae98c65558487693d94494e28387f2a9d76782992e4f399f44a) - * [Push Splits](https://etherscan.io/tx/0x20e8da208491560c658a25dcaa2bf37f94f26ccb4d5caaac4a346b2152818513) + - [Warehouse](https://etherscan.io/tx/0x9a24df13332fafff979c35d5475be6a0594b9e8a632b1ff603150c413b7c134c) + - [Pull Splits](https://etherscan.io/tx/0xe81eb2677e597ae98c65558487693d94494e28387f2a9d76782992e4f399f44a) + - [Push Splits](https://etherscan.io/tx/0x20e8da208491560c658a25dcaa2bf37f94f26ccb4d5caaac4a346b2152818513) -2. Support for [CreateX](https://createx.rocks/). We use createX as our deployer factory. This will ensure that the addresses match existing deployments. +2. Support for [CreateX](https://createx.rocks/). We use createX as our deployer factory. This will ensure that the + addresses match existing deployments. 3. Complete OP Code compatibility with evm version: `Shanghai`. diff --git a/packages/splits-v2/deployments/360.json b/packages/splits-v2/deployments/360.json index ccaf35d..bbfcccc 100644 --- a/packages/splits-v2/deployments/360.json +++ b/packages/splits-v2/deployments/360.json @@ -2,4 +2,4 @@ "PullSplitFactory": "0x80f1B766817D04870f115fEBbcCADF8DBF75E017", "PushSplitFactory": "0xaDC87646f736d6A82e9a6539cddC488b2aA07f38", "SplitsWarehouse": "0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8" -} \ No newline at end of file +} diff --git a/packages/splits-v2/script/SplitFactoryV2.s.sol b/packages/splits-v2/script/SplitFactoryV2.s.sol index 5bc0317..adbac93 100644 --- a/packages/splits-v2/script/SplitFactoryV2.s.sol +++ b/packages/splits-v2/script/SplitFactoryV2.s.sol @@ -7,25 +7,17 @@ import { PushSplitFactory } from "../src/splitters/push/PushSplitFactory.sol"; import { BaseScript } from "./Base.s.sol"; contract SplitFactoryV2Script is BaseScript { - uint88 private constant PUSH_DEPLOYMENT_SALT = 1; - uint88 private constant PULL_DEPLOYMENT_SALT = 2; - function run() public { address warehouse = getAddressFromConfig("splitsWarehouse"); - bytes memory args = abi.encode(warehouse); - - address deployer = vm.envAddress("DEPLOYER"); - - bytes32 pull_salt = computeSalt(deployer, bytes11(PULL_DEPLOYMENT_SALT)); - bytes32 push_salt = computeSalt(deployer, bytes11(PUSH_DEPLOYMENT_SALT)); - vm.startBroadcast(); - address pull_factory = create3(pull_salt, abi.encodePacked(type(PullSplitFactory).creationCode, args)); - address push_factory = create3(push_salt, abi.encodePacked(type(PushSplitFactory).creationCode, args)); + address pull_factory = + address(new PullSplitFactory{ salt: keccak256("splits.pullSplitFactory.v2.1") }(warehouse)); + address push_factory = + address(new PushSplitFactory{ salt: keccak256("splits.pushSplitFactory.v2.1") }(warehouse)); vm.stopBroadcast(); - updateDeployment(pull_factory, "PullSplitFactory"); - updateDeployment(push_factory, "PushSplitFactory"); + updateDeployment(pull_factory, "PullSplitFactoryV2.1"); + updateDeployment(push_factory, "PushSplitFactoryV2.1"); } } diff --git a/packages/splits-v2/src/SplitsWarehouse.sol b/packages/splits-v2/src/SplitsWarehouse.sol index 05b98c6..11a801a 100644 --- a/packages/splits-v2/src/SplitsWarehouse.sol +++ b/packages/splits-v2/src/SplitsWarehouse.sol @@ -13,7 +13,7 @@ import { ShortString, ShortStrings } from "@openzeppelin/contracts/utils/ShortSt * @title Splits Token Warehouse * @author Splits * @notice ERC6909 compliant token warehouse for Splits ecosystem - * @dev Token id here is address(uint160(uint256 id)). + * @dev Token id here is uint256(uint160(address tokenAddress)). */ contract SplitsWarehouse is ERC6909X { using Cast for uint256; @@ -29,7 +29,6 @@ contract SplitsWarehouse is ERC6909X { error InvalidAmount(); error LengthMismatch(); - error ZeroOwner(); error WithdrawalPaused(address owner); /* -------------------------------------------------------------------------- */ @@ -210,6 +209,7 @@ contract SplitsWarehouse is ERC6909X { * @param _token The address of the token to be withdrawn. */ function withdraw(address _owner, address _token) external { + // solhint-disable-next-line avoid-tx-origin if (msg.sender != _owner && tx.origin != _owner) { if (withdrawConfig[_owner].paused) { revert WithdrawalPaused(_owner); @@ -262,8 +262,8 @@ contract SplitsWarehouse is ERC6909X { /** * @notice Batch transfers tokens to the specified addresses from msg.sender. - * @param _token The address of the token to be transferred. * @param _receivers The addresses of the receivers. + * @param _token The address of the token to be transferred. * @param _amounts The amounts of the tokens to be transferred. */ function batchTransfer(address[] calldata _receivers, address _token, uint256[] calldata _amounts) external { diff --git a/packages/splits-v2/src/splitters/SplitFactoryV2.sol b/packages/splits-v2/src/splitters/SplitFactoryV2.sol index 616f4ce..4512257 100644 --- a/packages/splits-v2/src/splitters/SplitFactoryV2.sol +++ b/packages/splits-v2/src/splitters/SplitFactoryV2.sol @@ -17,6 +17,10 @@ abstract contract SplitFactoryV2 is Nonces { /* EVENTS */ /* -------------------------------------------------------------------------- */ + event SplitCreated( + address indexed split, SplitV2Lib.Split splitParams, address owner, address creator, bytes32 salt + ); + event SplitCreated(address indexed split, SplitV2Lib.Split splitParams, address owner, address creator); /* -------------------------------------------------------------------------- */ @@ -32,8 +36,7 @@ abstract contract SplitFactoryV2 is Nonces { /** * @notice Create a new split using create2. - * @dev if integrating, please make sure you understand how to handle greifing - * properly to avoid potential issues with frontrunning. See docs for more information. + * @dev Returns existing split if already created, otherwise creates new split. * @param _splitParams Params to create split with. * @param _owner Owner of created split. * @param _creator Creator of created split. @@ -48,14 +51,23 @@ abstract contract SplitFactoryV2 is Nonces { external returns (address split) { - split = Clone.cloneDeterministic({ + bytes32 salt = _getSalt({ _splitParams: _splitParams, _owner: _owner, _salt: _salt }); + + split = Clone.predictDeterministicAddress({ _implementation: SPLIT_WALLET_IMPLEMENTATION, - _salt: _getSalt({ _splitParams: _splitParams, _owner: _owner, _salt: _salt }) + _salt: salt, + _deployer: address(this) }); + if (split.code.length > 0) { + return split; + } + + split = Clone.cloneDeterministic({ _implementation: SPLIT_WALLET_IMPLEMENTATION, _salt: salt }); + SplitWalletV2(split).initialize(_splitParams, _owner); - emit SplitCreated({ split: split, splitParams: _splitParams, owner: _owner, creator: _creator }); + emit SplitCreated({ split: split, splitParams: _splitParams, owner: _owner, creator: _creator, salt: _salt }); } /** diff --git a/packages/splits-v2/src/splitters/SplitWalletV2.sol b/packages/splits-v2/src/splitters/SplitWalletV2.sol index c84d2eb..e84318b 100644 --- a/packages/splits-v2/src/splitters/SplitWalletV2.sol +++ b/packages/splits-v2/src/splitters/SplitWalletV2.sol @@ -54,11 +54,14 @@ abstract contract SplitWalletV2 is Wallet, ERC1271 { /// @notice the split hash - Keccak256 hash of the split struct bytes32 public splitHash; + /// @notice the block number at which the split was last updated + uint256 public updateBlockNumber; + /* -------------------------------------------------------------------------- */ /* CONSTRUCTOR & INITIALIZER */ /* -------------------------------------------------------------------------- */ - constructor(address _splitWarehouse) ERC1271("splitWallet", "2") { + constructor(address _splitWarehouse) ERC1271("splitWallet", "2.1") { SPLITS_WAREHOUSE = ISplitsWarehouse(_splitWarehouse); NATIVE_TOKEN = SPLITS_WAREHOUSE.NATIVE_TOKEN(); FACTORY = msg.sender; @@ -73,8 +76,9 @@ abstract contract SplitWalletV2 is Wallet, ERC1271 { if (msg.sender != FACTORY) revert UnauthorizedInitializer(); _split.validate(); - splitHash = _split.getHash(); + updateBlockNumber = block.number; + emit SplitUpdated(_split); Wallet.__initWallet(_owner); } @@ -115,9 +119,8 @@ abstract contract SplitWalletV2 is Wallet, ERC1271 { function updateSplit(SplitV2Lib.Split calldata _split) external onlyOwner { // throws error if invalid _split.validate(); - splitHash = _split.getHash(); - + updateBlockNumber = block.number; emit SplitUpdated(_split); } diff --git a/packages/splits-v2/src/splitters/pull/PullSplit.sol b/packages/splits-v2/src/splitters/pull/PullSplit.sol index ae386dc..91aa4c7 100644 --- a/packages/splits-v2/src/splitters/pull/PullSplit.sol +++ b/packages/splits-v2/src/splitters/pull/PullSplit.sol @@ -50,6 +50,7 @@ contract PullSplit is SplitWalletV2 { (uint256 splitBalance, uint256 warehouseBalance) = getSplitBalance(_token); // @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { // splitBalance -= uint(splitBalance > 0); splitBalance := sub(splitBalance, iszero(iszero(splitBalance))) @@ -57,7 +58,7 @@ contract PullSplit is SplitWalletV2 { warehouseBalance := sub(warehouseBalance, iszero(iszero(warehouseBalance))) } - if (splitBalance > 0) depositToWarehouse(_token, splitBalance); + if (splitBalance > 0) _depositToWarehouse(_token, splitBalance); _distribute({ _split: _split, @@ -93,7 +94,7 @@ contract PullSplit is SplitWalletV2 { if (_performWarehouseTransfer) { uint256 amount = (_token == NATIVE_TOKEN ? address(this).balance : IERC20(_token).balanceOf(address(this))) - 1; - depositToWarehouse(_token, amount); + _depositToWarehouse(_token, amount); } _distribute({ _split: _split, _token: _token, _amount: _distributeAmount, _distributor: _distributor }); @@ -104,22 +105,27 @@ contract PullSplit is SplitWalletV2 { * @param _token The token to deposit. * @param _amount The amount of tokens to deposit */ - function depositToWarehouse(address _token, uint256 _amount) public { + function depositToWarehouse(address _token, uint256 _amount) external pausable { + _depositToWarehouse(_token, _amount); + } + + /* -------------------------------------------------------------------------- */ + /* INTERNAL/PRIVATE */ + /* -------------------------------------------------------------------------- */ + + function _depositToWarehouse(address _token, uint256 _amount) internal { if (_token == NATIVE_TOKEN) { SPLITS_WAREHOUSE.deposit{ value: _amount }({ receiver: address(this), token: _token, amount: _amount }); } else { + // solhint-disable-next-line no-empty-blocks try SPLITS_WAREHOUSE.deposit({ receiver: address(this), token: _token, amount: _amount }) { } catch { - IERC20(_token).approve({ spender: address(SPLITS_WAREHOUSE), amount: type(uint256).max }); + IERC20(_token).forceApprove({ spender: address(SPLITS_WAREHOUSE), value: type(uint256).max }); SPLITS_WAREHOUSE.deposit({ receiver: address(this), token: _token, amount: _amount }); } } } - /* -------------------------------------------------------------------------- */ - /* INTERNAL/PRIVATE */ - /* -------------------------------------------------------------------------- */ - /// @dev Assumes the amount is already deposited to the warehouse. function _distribute( SplitV2Lib.Split calldata _split, @@ -129,12 +135,12 @@ contract PullSplit is SplitWalletV2 { ) internal { - (uint256[] memory amounts, uint256 distibutorReward) = _split.getDistributions(_amount); + (uint256[] memory amounts, uint256 distributorReward) = _split.getDistributions(_amount); SPLITS_WAREHOUSE.batchTransfer({ receivers: _split.recipients, token: _token, amounts: amounts }); - if (distibutorReward > 0) { - SPLITS_WAREHOUSE.transfer({ receiver: _distributor, id: _token.toUint256(), amount: distibutorReward }); + if (distributorReward > 0) { + SPLITS_WAREHOUSE.transfer({ receiver: _distributor, id: _token.toUint256(), amount: distributorReward }); } emit SplitDistributed({ token: _token, distributor: _distributor, amount: _amount }); diff --git a/packages/splits-v2/src/splitters/push/PushSplit.sol b/packages/splits-v2/src/splitters/push/PushSplit.sol index 2ed0a54..c5a22c9 100644 --- a/packages/splits-v2/src/splitters/push/PushSplit.sol +++ b/packages/splits-v2/src/splitters/push/PushSplit.sol @@ -52,6 +52,7 @@ contract PushSplit is SplitWalletV2 { if (warehouseBalance > 1) withdrawFromWarehouse(_token); // @solidity memory-safe-assembly + // solhint-disable-next-line no-inline-assembly assembly { // splitBalance -= uint(splitBalance > 0); splitBalance := sub(splitBalance, iszero(iszero(splitBalance))) diff --git a/packages/splits-v2/test/splitters/PullSplit.t.sol b/packages/splits-v2/test/splitters/PullSplit.t.sol index 33b88a2..b274a32 100644 --- a/packages/splits-v2/test/splitters/PullSplit.t.sol +++ b/packages/splits-v2/test/splitters/PullSplit.t.sol @@ -2,19 +2,26 @@ pragma solidity ^0.8.23; import { Clone } from "../../src/libraries/Clone.sol"; - +import { SplitV2Lib } from "../../src/libraries/SplitV2.sol"; import { PullSplit } from "../../src/splitters/pull/PullSplit.sol"; +import { PullSplitFactory } from "../../src/splitters/pull/PullSplitFactory.sol"; +import { Pausable } from "../../src/utils/Pausable.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { BaseTest } from "../Base.t.sol"; contract PullSplitTest is BaseTest { PullSplit private pullSplit; + string MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL"); + function setUp() public override { super.setUp(); pullSplit = PullSplit(Clone.cloneDeterministic((address(new PullSplit(address(warehouse)))), 0)); + SplitV2Lib.Split memory split; + pullSplit.initialize(split, ALICE.addr); } function testFuzz_depositToWarehouse(bool _native, uint256 _amount) public { @@ -48,4 +55,54 @@ contract PullSplitTest is BaseTest { vm.expectRevert(); pullSplit.depositToWarehouse(_token, _amount); } + + function testFuzz_depositToWarehouse_Revert_whenPaused() public { + vm.prank(ALICE.addr); + pullSplit.setPaused(true); + + vm.expectRevert(Pausable.Paused.selector); + pullSplit.depositToWarehouse(address(0), 0); + } + + function test_distribute_USDT_Mainnet() public { + // create new mainnet fork + uint256 mainnetFork = vm.createFork(MAINNET_RPC_URL, 21_395_163); + vm.selectFork(mainnetFork); + + // replicate v2.0 split on mainnet failing to distribute usdt + address[] memory recipients = new address[](2); + recipients[0] = 0xa7128c450131A6a39751D1B0E2aA44f21B55Ea73; + recipients[1] = 0xAe4B8c350BB31ce40eaf75F154a2d354450cBe0f; + + uint256[] memory allocations = new uint256[](2); + allocations[0] = 500_000; + allocations[1] = 500_000; + + SplitV2Lib.Split memory split = SplitV2Lib.Split(recipients, allocations, 1_000_000, 0); + + address owner = 0x0F17233C18aEB1278C6814b979a37031d123cFB8; + address splitAddress = 0xb051D24BDa0CB26877A982870E7B02Fb426c1963; + address token = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address oldWarehouse = 0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8; + + // deploy v2.1 split on mainnet + pullFactory = new PullSplitFactory(oldWarehouse); + + // deploy new split + address newSplit = pullFactory.createSplit(split, owner, owner); + + // try to distribute v2.0 split which should revert + vm.expectRevert(); + PullSplit(splitAddress).distribute(split, token, owner); + + vm.startPrank(splitAddress); + // transfer usdt to new split + SafeERC20.safeTransfer(IERC20(token), newSplit, IERC20(token).balanceOf(splitAddress)); + vm.stopPrank(); + + // distribute usdt + PullSplit(newSplit).distribute(split, token, owner); + + assertEq(IERC20(token).balanceOf(newSplit), 1); + } } diff --git a/packages/splits-v2/test/splitters/SplitFactoryV2.t.sol b/packages/splits-v2/test/splitters/SplitFactoryV2.t.sol index 3e4043a..450042f 100644 --- a/packages/splits-v2/test/splitters/SplitFactoryV2.t.sol +++ b/packages/splits-v2/test/splitters/SplitFactoryV2.t.sol @@ -7,6 +7,10 @@ import { SplitWalletV2 } from "../../src/splitters/SplitWalletV2.sol"; import { BaseTest } from "../Base.t.sol"; contract SplitFactoryV2Test is BaseTest { + event SplitCreated( + address indexed split, SplitV2Lib.Split splitParams, address owner, address creator, bytes32 salt + ); + event SplitCreated(address indexed split, SplitV2Lib.Split splitParams, address owner, address creator); function setUp() public override { @@ -27,7 +31,7 @@ contract SplitFactoryV2Test is BaseTest { address predictedAddress = predictDeterministicAddress(params, _owner, _salt, _distributeByPush); vm.expectEmit(); - emit SplitCreated(predictedAddress, params, _owner, _creator); + emit SplitCreated(predictedAddress, params, _owner, _creator, _salt); SplitWalletV2 split = SplitWalletV2(createSplitDeterministic(params, _owner, _creator, _salt, _distributeByPush)); @@ -48,9 +52,11 @@ contract SplitFactoryV2Test is BaseTest { testFuzz_create2Split(_receivers, _distributionIncentive, _distributeByPush, _owner, _creator, _salt); SplitV2Lib.Split memory params = createSplitParams(_receivers, _distributionIncentive); + address predictedAddress = predictDeterministicAddress(params, _owner, _salt, _distributeByPush); + + address split = createSplitDeterministic(params, _owner, _creator, _salt, _distributeByPush); - vm.expectRevert(); - createSplitDeterministic(params, _owner, _creator, _salt, _distributeByPush); + assertEq(split, predictedAddress); } function testFuzz_createSplitWithoutSalt( diff --git a/packages/splits-v2/test/splitters/SplitWalletV2.t.sol b/packages/splits-v2/test/splitters/SplitWalletV2.t.sol index 91ef1c6..88c17fb 100644 --- a/packages/splits-v2/test/splitters/SplitWalletV2.t.sol +++ b/packages/splits-v2/test/splitters/SplitWalletV2.t.sol @@ -51,11 +51,13 @@ contract SplitWalletV2Test is BaseTest { wallet = _distributeByPush ? pushSplit : pullSplit; + emit SplitUpdated(split); wallet.initialize(split, _owner); assertEq(wallet.owner(), _owner); assertEq(address(wallet.SPLITS_WAREHOUSE()), address(warehouse)); assertEq(wallet.splitHash(), split.getHashMem()); + assertEq(wallet.updateBlockNumber(), block.number); } function testFuzz_initialize_Revert_whenNotFactory( @@ -139,6 +141,8 @@ contract SplitWalletV2Test is BaseTest { emit SplitUpdated(split); vm.prank(_owner); wallet.updateSplit(split); + + assertEq(wallet.updateBlockNumber(), block.number); } function testFuzz_updateSplit_Revert_Unauthorized( diff --git a/packages/splits-v2/test/warehouse/SplitsWarehouseHandler.sol b/packages/splits-v2/test/warehouse/SplitsWarehouseHandler.sol index 49037a0..6a8b4ad 100644 --- a/packages/splits-v2/test/warehouse/SplitsWarehouseHandler.sol +++ b/packages/splits-v2/test/warehouse/SplitsWarehouseHandler.sol @@ -11,6 +11,7 @@ import { Address } from "../utils/Address.sol"; import { CommonBase } from "forge-std/Base.sol"; import { StdCheats } from "forge-std/StdCheats.sol"; import { StdUtils } from "forge-std/StdUtils.sol"; +import { Vm, VmSafe } from "forge-std/Vm.sol"; contract SplitsWarehouseHandler is CommonBase, StdCheats, StdUtils { using Math for uint256[]; @@ -45,6 +46,10 @@ contract SplitsWarehouseHandler is CommonBase, StdCheats, StdUtils { } modifier mockDepositor() { + (VmSafe.CallerMode mode,,) = vm.readCallers(); + if (mode == VmSafe.CallerMode.Prank || mode == VmSafe.CallerMode.RecurrentPrank) { + vm.stopPrank(); + } vm.startPrank(depositor); _; vm.stopPrank(); @@ -53,6 +58,12 @@ contract SplitsWarehouseHandler is CommonBase, StdCheats, StdUtils { modifier mockUser(uint256 _user) { _user = bound(_user, 0, users.length - 1); + (VmSafe.CallerMode mode,,) = vm.readCallers(); + + if (mode == VmSafe.CallerMode.Prank || mode == VmSafe.CallerMode.RecurrentPrank) { + vm.stopPrank(); + } + address user = users[_user]; vm.startPrank(user); _;