@bananapus/suckers-v6 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +422 -0
- package/SECURITY.md +55 -0
- package/SKILLS.md +163 -0
- package/deployments/nana-suckers-v5/arbitrum/JBArbitrumSucker.json +1425 -0
- package/deployments/nana-suckers-v5/arbitrum/JBArbitrumSuckerDeployer.json +391 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer_1.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSuckerDeployer_2.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker_1.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum/JBCCIPSucker_2.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum/JBSuckerRegistry.json +690 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBArbitrumSucker.json +1425 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBArbitrumSuckerDeployer.json +391 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer_1.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSuckerDeployer_2.json +433 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker_1.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBCCIPSucker_2.json +1479 -0
- package/deployments/nana-suckers-v5/arbitrum_sepolia/JBSuckerRegistry.json +690 -0
- package/deployments/nana-suckers-v5/base/JBBaseSucker.json +1389 -0
- package/deployments/nana-suckers-v5/base/JBBaseSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSucker.json +1483 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer.json +436 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer_1.json +436 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSuckerDeployer_2.json +436 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSucker_1.json +1483 -0
- package/deployments/nana-suckers-v5/base/JBCCIPSucker_2.json +1483 -0
- package/deployments/nana-suckers-v5/base/JBSuckerRegistry.json +694 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBBaseSucker.json +1389 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBBaseSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker.json +1483 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer.json +436 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer_1.json +436 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSuckerDeployer_2.json +436 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker_1.json +1483 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBCCIPSucker_2.json +1483 -0
- package/deployments/nana-suckers-v5/base_sepolia/JBSuckerRegistry.json +694 -0
- package/deployments/nana-suckers-v5/ethereum/JBArbitrumSucker.json +1429 -0
- package/deployments/nana-suckers-v5/ethereum/JBArbitrumSuckerDeployer.json +394 -0
- package/deployments/nana-suckers-v5/ethereum/JBBaseSucker.json +1389 -0
- package/deployments/nana-suckers-v5/ethereum/JBBaseSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker.json +1483 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer.json +436 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer_1.json +436 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSuckerDeployer_2.json +436 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker_1.json +1483 -0
- package/deployments/nana-suckers-v5/ethereum/JBCCIPSucker_2.json +1483 -0
- package/deployments/nana-suckers-v5/ethereum/JBOptimismSucker.json +1389 -0
- package/deployments/nana-suckers-v5/ethereum/JBOptimismSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/ethereum/JBSuckerRegistry.json +694 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSucker.json +1479 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer.json +433 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer_1.json +433 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSuckerDeployer_2.json +433 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSucker_1.json +1479 -0
- package/deployments/nana-suckers-v5/optimism/JBCCIPSucker_2.json +1479 -0
- package/deployments/nana-suckers-v5/optimism/JBOptimismSucker.json +1385 -0
- package/deployments/nana-suckers-v5/optimism/JBOptimismSuckerDeployer.json +373 -0
- package/deployments/nana-suckers-v5/optimism/JBSuckerRegistry.json +690 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker.json +1483 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer.json +436 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer_1.json +436 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSuckerDeployer_2.json +436 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker_1.json +1483 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBCCIPSucker_2.json +1483 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBOptimismSucker.json +1389 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBOptimismSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/optimism_sepolia/JBSuckerRegistry.json +694 -0
- package/deployments/nana-suckers-v5/sepolia/JBArbitrumSucker.json +1429 -0
- package/deployments/nana-suckers-v5/sepolia/JBArbitrumSuckerDeployer.json +394 -0
- package/deployments/nana-suckers-v5/sepolia/JBBaseSucker.json +1389 -0
- package/deployments/nana-suckers-v5/sepolia/JBBaseSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker.json +1483 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer.json +436 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer_1.json +436 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSuckerDeployer_2.json +436 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker_1.json +1483 -0
- package/deployments/nana-suckers-v5/sepolia/JBCCIPSucker_2.json +1483 -0
- package/deployments/nana-suckers-v5/sepolia/JBOptimismSucker.json +1389 -0
- package/deployments/nana-suckers-v5/sepolia/JBOptimismSuckerDeployer.json +376 -0
- package/deployments/nana-suckers-v5/sepolia/JBSuckerRegistry.json +694 -0
- package/foundry.lock +11 -0
- package/foundry.toml +22 -0
- package/package.json +33 -0
- package/remappings.txt +1 -0
- package/script/Deploy.s.sol +506 -0
- package/script/helpers/SuckerDeploymentLib.sol +97 -0
- package/slither-ci.config.json +10 -0
- package/sphinx.lock +476 -0
- package/src/JBArbitrumSucker.sol +311 -0
- package/src/JBBaseSucker.sol +41 -0
- package/src/JBCCIPSucker.sol +303 -0
- package/src/JBOptimismSucker.sol +143 -0
- package/src/JBSucker.sol +1159 -0
- package/src/JBSuckerRegistry.sol +262 -0
- package/src/deployers/JBArbitrumSuckerDeployer.sol +86 -0
- package/src/deployers/JBBaseSuckerDeployer.sol +26 -0
- package/src/deployers/JBCCIPSuckerDeployer.sol +88 -0
- package/src/deployers/JBOptimismSuckerDeployer.sol +82 -0
- package/src/deployers/JBSuckerDeployer.sol +147 -0
- package/src/enums/JBAddToBalanceMode.sol +11 -0
- package/src/enums/JBLayer.sol +8 -0
- package/src/enums/JBSuckerState.sol +14 -0
- package/src/interfaces/IArbGatewayRouter.sol +11 -0
- package/src/interfaces/IArbL1GatewayRouter.sol +17 -0
- package/src/interfaces/IArbL2GatewayRouter.sol +14 -0
- package/src/interfaces/ICCIPRouter.sol +11 -0
- package/src/interfaces/IJBArbitrumSucker.sol +13 -0
- package/src/interfaces/IJBArbitrumSuckerDeployer.sol +12 -0
- package/src/interfaces/IJBCCIPSuckerDeployer.sol +15 -0
- package/src/interfaces/IJBOpSuckerDeployer.sol +11 -0
- package/src/interfaces/IJBOptimismSucker.sol +10 -0
- package/src/interfaces/IJBSucker.sol +144 -0
- package/src/interfaces/IJBSuckerDeployer.sol +40 -0
- package/src/interfaces/IJBSuckerExtended.sol +22 -0
- package/src/interfaces/IJBSuckerRegistry.sol +75 -0
- package/src/interfaces/IOPMessenger.sol +18 -0
- package/src/interfaces/IOPStandardBridge.sol +29 -0
- package/src/interfaces/IWrappedNativeToken.sol +13 -0
- package/src/libraries/ARBAddresses.sol +17 -0
- package/src/libraries/ARBChains.sol +11 -0
- package/src/libraries/CCIPHelper.sol +136 -0
- package/src/structs/JBClaim.sol +13 -0
- package/src/structs/JBInboxTreeRoot.sol +12 -0
- package/src/structs/JBLeaf.sol +14 -0
- package/src/structs/JBMessageRoot.sol +16 -0
- package/src/structs/JBOutboxTree.sol +18 -0
- package/src/structs/JBRemoteToken.sol +17 -0
- package/src/structs/JBSuckerDeployerConfig.sol +12 -0
- package/src/structs/JBSuckersPair.sol +11 -0
- package/src/structs/JBTokenMapping.sol +13 -0
- package/src/utils/MerkleLib.sol +1020 -0
- package/test/Fork.t.sol +514 -0
- package/test/InteropCompat.t.sol +676 -0
- package/test/SuckerAttacks.t.sol +509 -0
- package/test/SuckerDeepAttacks.t.sol +1563 -0
- package/test/mocks/ERC20Mock.sol +36 -0
- package/test/mocks/MockMessenger.sol +42 -0
- package/test/unit/arb.t.sol +28 -0
- package/test/unit/ccip_native_interop.t.sol +719 -0
- package/test/unit/ccip_refund.t.sol +234 -0
- package/test/unit/deployer.t.sol +475 -0
- package/test/unit/emergency.t.sol +305 -0
- package/test/unit/merkle.t.sol +212 -0
- package/test/unit/multi_chain_evolution.t.sol +622 -0
- package/test/unit/registry.t.sol +26 -0
package/test/Fork.t.sol
ADDED
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity 0.8.23;
|
|
3
|
+
|
|
4
|
+
import /* {*} from */ "@bananapus/core-v6/test/helpers/TestBaseWorkflow.sol";
|
|
5
|
+
import {MockPriceFeed} from "@bananapus/core-v6/test/mock/MockPriceFeed.sol";
|
|
6
|
+
import {IJBSucker} from "../src/interfaces/IJBSucker.sol";
|
|
7
|
+
import {IJBSuckerDeployer} from "../src/interfaces/IJBSuckerDeployer.sol";
|
|
8
|
+
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
9
|
+
import {IJBController} from "@bananapus/core-v6/src/interfaces/IJBController.sol";
|
|
10
|
+
import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
|
|
11
|
+
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
12
|
+
import {IJBCashOutTerminal} from "@bananapus/core-v6/src/interfaces/IJBCashOutTerminal.sol";
|
|
13
|
+
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
14
|
+
import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
|
|
15
|
+
import {JBPermissionsData} from "@bananapus/core-v6/src/structs/JBPermissionsData.sol";
|
|
16
|
+
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
17
|
+
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
18
|
+
import {ICCIPRouter} from "src/interfaces/ICCIPRouter.sol";
|
|
19
|
+
import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
20
|
+
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
|
|
21
|
+
|
|
22
|
+
import {JBTokenMapping} from "../src/structs/JBTokenMapping.sol";
|
|
23
|
+
import {JBRemoteToken} from "../src/structs/JBRemoteToken.sol";
|
|
24
|
+
import {JBOutboxTree} from "../src/structs/JBOutboxTree.sol";
|
|
25
|
+
import {JBInboxTreeRoot} from "../src/structs/JBInboxTreeRoot.sol";
|
|
26
|
+
import {JBMessageRoot} from "../src/structs/JBMessageRoot.sol";
|
|
27
|
+
import {JBClaim} from "../src/structs/JBClaim.sol";
|
|
28
|
+
import {JBAddToBalanceMode} from "../src/enums/JBAddToBalanceMode.sol";
|
|
29
|
+
import {MerkleLib} from "../src/utils/MerkleLib.sol";
|
|
30
|
+
|
|
31
|
+
import "forge-std/Test.sol";
|
|
32
|
+
import {JBCCIPSuckerDeployer} from "src/deployers/JBCCIPSuckerDeployer.sol";
|
|
33
|
+
import {JBCCIPSucker} from "../src/JBCCIPSucker.sol";
|
|
34
|
+
import {BurnMintERC677Helper} from "@chainlink/local/src/ccip/CCIPLocalSimulator.sol";
|
|
35
|
+
import {CCIPLocalSimulatorFork, Register} from "@chainlink/local/src/ccip/CCIPLocalSimulatorFork.sol";
|
|
36
|
+
|
|
37
|
+
import {JBClaim} from "../src/structs/JBClaim.sol";
|
|
38
|
+
import {JBLeaf} from "../src/structs/JBClaim.sol";
|
|
39
|
+
import {MerkleLib} from "../src/utils/MerkleLib.sol";
|
|
40
|
+
import {CCIPHelper} from "../src/libraries/CCIPHelper.sol";
|
|
41
|
+
|
|
42
|
+
contract CCIPSuckerForkedTests is TestBaseWorkflow, JBTest {
|
|
43
|
+
// CCIP Local Simulator Contracts
|
|
44
|
+
CCIPLocalSimulatorFork ccipLocalSimulatorFork;
|
|
45
|
+
BurnMintERC677Helper ccipBnM;
|
|
46
|
+
BurnMintERC677Helper ccipBnMArbSepolia;
|
|
47
|
+
|
|
48
|
+
// Re-used parameters for project/ruleset/sucker setups
|
|
49
|
+
JBRulesetMetadata _metadata;
|
|
50
|
+
JBAddToBalanceMode atbMode = JBAddToBalanceMode.ON_CLAIM;
|
|
51
|
+
|
|
52
|
+
// Sucker and token
|
|
53
|
+
JBCCIPSuckerDeployer suckerDeployer;
|
|
54
|
+
JBCCIPSuckerDeployer suckerDeployer2;
|
|
55
|
+
IJBSucker suckerGlobal;
|
|
56
|
+
IJBToken projectOneToken;
|
|
57
|
+
|
|
58
|
+
// Chain ids and selectors
|
|
59
|
+
uint256 sepoliaFork;
|
|
60
|
+
uint256 arbSepoliaFork;
|
|
61
|
+
uint64 arbSepoliaChainSelector = 3_478_487_238_524_512_106;
|
|
62
|
+
uint64 ethSepoliaChainSelector = 16_015_286_601_757_825_753;
|
|
63
|
+
|
|
64
|
+
// RPCs
|
|
65
|
+
string ETHEREUM_SEPOLIA_RPC_URL = vm.envOr("RPC_ETHEREUM_SEPOLIA", string("https://1rpc.io/sepolia"));
|
|
66
|
+
string ARBITRUM_SEPOLIA_RPC_URL =
|
|
67
|
+
vm.envOr("RPC_ARBITRUM_SEPOLIA", string("https://arbitrum-sepolia.gateway.tenderly.co"));
|
|
68
|
+
|
|
69
|
+
//*********************************************************************//
|
|
70
|
+
// ---------------------------- Setup parts -------------------------- //
|
|
71
|
+
//*********************************************************************//
|
|
72
|
+
|
|
73
|
+
function initL1AndUtils() public {
|
|
74
|
+
// Setup starts on sepolia fork
|
|
75
|
+
sepoliaFork = vm.createSelectFork(ETHEREUM_SEPOLIA_RPC_URL);
|
|
76
|
+
|
|
77
|
+
ccipLocalSimulatorFork = new CCIPLocalSimulatorFork();
|
|
78
|
+
vm.makePersistent(address(ccipLocalSimulatorFork));
|
|
79
|
+
Register.NetworkDetails memory sepoliaNetworkDetails = ccipLocalSimulatorFork.getNetworkDetails(block.chainid);
|
|
80
|
+
|
|
81
|
+
ccipBnM = BurnMintERC677Helper(sepoliaNetworkDetails.ccipBnMAddress);
|
|
82
|
+
vm.label(address(ccipBnM), "bnmEthSep");
|
|
83
|
+
vm.makePersistent(address(ccipBnM));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function initMetadata() public {
|
|
87
|
+
_metadata = JBRulesetMetadata({
|
|
88
|
+
reservedPercent: JBConstants.MAX_RESERVED_PERCENT / 2, //50%
|
|
89
|
+
cashOutTaxRate: 0,
|
|
90
|
+
baseCurrency: uint32(uint160(address(JBConstants.NATIVE_TOKEN))),
|
|
91
|
+
pausePay: false,
|
|
92
|
+
pauseCreditTransfers: false,
|
|
93
|
+
allowOwnerMinting: true,
|
|
94
|
+
allowSetCustomToken: false,
|
|
95
|
+
allowTerminalMigration: false,
|
|
96
|
+
allowSetTerminals: false,
|
|
97
|
+
allowSetController: false,
|
|
98
|
+
allowAddAccountingContext: true,
|
|
99
|
+
allowAddPriceFeed: true,
|
|
100
|
+
ownerMustSendPayouts: false,
|
|
101
|
+
holdFees: false,
|
|
102
|
+
useTotalSurplusForCashOuts: true,
|
|
103
|
+
useDataHookForPay: false,
|
|
104
|
+
useDataHookForCashOut: false,
|
|
105
|
+
dataHook: address(0),
|
|
106
|
+
metadata: 0
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function launchAndConfigureL1Project() public {
|
|
111
|
+
// Setup: terminal / project
|
|
112
|
+
// Package up the limits for the given terminal.
|
|
113
|
+
JBFundAccessLimitGroup[] memory _fundAccessLimitGroup = new JBFundAccessLimitGroup[](1);
|
|
114
|
+
{
|
|
115
|
+
// Specify a payout limit.
|
|
116
|
+
JBCurrencyAmount[] memory _payoutLimits = new JBCurrencyAmount[](0);
|
|
117
|
+
// _payoutLimits[0] =
|
|
118
|
+
// JBCurrencyAmount({amount: 10 * 10 ** 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
|
|
119
|
+
|
|
120
|
+
// Specify a surplus allowance.
|
|
121
|
+
JBCurrencyAmount[] memory _surplusAllowances = new JBCurrencyAmount[](1);
|
|
122
|
+
_surplusAllowances[0] =
|
|
123
|
+
JBCurrencyAmount({amount: 5 * 10 ** 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))});
|
|
124
|
+
|
|
125
|
+
_fundAccessLimitGroup[0] = JBFundAccessLimitGroup({
|
|
126
|
+
terminal: address(jbMultiTerminal()),
|
|
127
|
+
token: JBConstants.NATIVE_TOKEN,
|
|
128
|
+
payoutLimits: _payoutLimits,
|
|
129
|
+
surplusAllowances: _surplusAllowances
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
{
|
|
134
|
+
// Package up the ruleset configuration.
|
|
135
|
+
JBRulesetConfig[] memory _rulesetConfigurations = new JBRulesetConfig[](1);
|
|
136
|
+
_rulesetConfigurations[0].mustStartAtOrAfter = 0;
|
|
137
|
+
_rulesetConfigurations[0].duration = 0;
|
|
138
|
+
_rulesetConfigurations[0].weight = 1000 * 10 ** 18;
|
|
139
|
+
_rulesetConfigurations[0].weightCutPercent = 0;
|
|
140
|
+
_rulesetConfigurations[0].approvalHook = IJBRulesetApprovalHook(address(0));
|
|
141
|
+
_rulesetConfigurations[0].metadata = _metadata;
|
|
142
|
+
_rulesetConfigurations[0].splitGroups = new JBSplitGroup[](0);
|
|
143
|
+
_rulesetConfigurations[0].fundAccessLimitGroups = _fundAccessLimitGroup;
|
|
144
|
+
|
|
145
|
+
JBTerminalConfig[] memory _terminalConfigurations = new JBTerminalConfig[](1);
|
|
146
|
+
JBAccountingContext[] memory _tokensToAccept = new JBAccountingContext[](2);
|
|
147
|
+
|
|
148
|
+
_tokensToAccept[0] = JBAccountingContext({
|
|
149
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
_tokensToAccept[1] = JBAccountingContext({
|
|
153
|
+
token: address(ccipBnM), decimals: 18, currency: uint32(uint160(address(ccipBnM)))
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
_terminalConfigurations[0] =
|
|
157
|
+
JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _tokensToAccept});
|
|
158
|
+
|
|
159
|
+
vm.expectCall(address(ccipBnM), abi.encodeWithSelector(IERC20Metadata.decimals.selector));
|
|
160
|
+
|
|
161
|
+
// Create a first project to collect fees.
|
|
162
|
+
jbController()
|
|
163
|
+
.launchProjectFor({
|
|
164
|
+
owner: multisig(),
|
|
165
|
+
projectUri: "whatever",
|
|
166
|
+
rulesetConfigurations: _rulesetConfigurations,
|
|
167
|
+
terminalConfigurations: _terminalConfigurations, // Set terminals to receive fees.
|
|
168
|
+
memo: ""
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Setup an erc20 for the project
|
|
172
|
+
projectOneToken = jbController().deployERC20For(1, "SuckerToken", "SOOK", bytes32(0));
|
|
173
|
+
|
|
174
|
+
// Add a price-feed to reconcile pays and cash outs with our test token
|
|
175
|
+
MockPriceFeed _priceFeedNativeTest = new MockPriceFeed(100 * 10 ** 18, 18); // 2000 test token == 1 native
|
|
176
|
+
// token
|
|
177
|
+
vm.label(address(_priceFeedNativeTest), "Mock Price Feed Native-ccipBnM");
|
|
178
|
+
|
|
179
|
+
vm.startPrank(address(jbController()));
|
|
180
|
+
IJBPrices(jbPrices())
|
|
181
|
+
.addPriceFeedFor({
|
|
182
|
+
projectId: 1,
|
|
183
|
+
pricingCurrency: uint32(uint160(address(ccipBnM))),
|
|
184
|
+
unitCurrency: uint32(uint160(JBConstants.NATIVE_TOKEN)),
|
|
185
|
+
feed: IJBPriceFeed(_priceFeedNativeTest)
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function initL2AndUtils() public {
|
|
191
|
+
// Create and select our L2 fork- preparing to deploy our project and sucker
|
|
192
|
+
arbSepoliaFork = vm.createSelectFork(ARBITRUM_SEPOLIA_RPC_URL);
|
|
193
|
+
|
|
194
|
+
// Get the corresponding remote token and label it for convenience in reading any trace in console
|
|
195
|
+
Register.NetworkDetails memory arbSepoliaNetworkDetails = ccipLocalSimulatorFork.getNetworkDetails(421_614);
|
|
196
|
+
|
|
197
|
+
// This is a faux token helper provided to emulate token bridges of the burn and mint type via CCIP
|
|
198
|
+
ccipBnMArbSepolia = BurnMintERC677Helper(arbSepoliaNetworkDetails.ccipBnMAddress);
|
|
199
|
+
vm.label(address(ccipBnMArbSepolia), "bnmArbSep");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function launchAndConfigureL2Project() public {
|
|
203
|
+
JBFundAccessLimitGroup[] memory _fundAccessLimitGroup = new JBFundAccessLimitGroup[](1);
|
|
204
|
+
{
|
|
205
|
+
// Package up the ruleset configuration.
|
|
206
|
+
JBRulesetConfig[] memory _rulesetConfigurations = new JBRulesetConfig[](1);
|
|
207
|
+
_rulesetConfigurations[0].mustStartAtOrAfter = 0;
|
|
208
|
+
_rulesetConfigurations[0].duration = 0;
|
|
209
|
+
_rulesetConfigurations[0].weight = 1000 * 10 ** 18;
|
|
210
|
+
_rulesetConfigurations[0].weightCutPercent = 0;
|
|
211
|
+
_rulesetConfigurations[0].approvalHook = IJBRulesetApprovalHook(address(0));
|
|
212
|
+
_rulesetConfigurations[0].metadata = _metadata;
|
|
213
|
+
_rulesetConfigurations[0].splitGroups = new JBSplitGroup[](0);
|
|
214
|
+
_rulesetConfigurations[0].fundAccessLimitGroups = _fundAccessLimitGroup;
|
|
215
|
+
|
|
216
|
+
JBTerminalConfig[] memory _terminalConfigurations = new JBTerminalConfig[](1);
|
|
217
|
+
JBAccountingContext[] memory _tokensToAccept = new JBAccountingContext[](2);
|
|
218
|
+
|
|
219
|
+
_tokensToAccept[0] = JBAccountingContext({
|
|
220
|
+
token: JBConstants.NATIVE_TOKEN, decimals: 18, currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
_tokensToAccept[1] = JBAccountingContext({
|
|
224
|
+
token: address(ccipBnMArbSepolia), decimals: 18, currency: uint32(uint160(address(ccipBnMArbSepolia)))
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
_terminalConfigurations[0] =
|
|
228
|
+
JBTerminalConfig({terminal: jbMultiTerminal(), accountingContextsToAccept: _tokensToAccept});
|
|
229
|
+
|
|
230
|
+
vm.expectCall(address(ccipBnMArbSepolia), abi.encodeWithSelector(IERC20Metadata.decimals.selector));
|
|
231
|
+
|
|
232
|
+
// Create a first project to collect fees.
|
|
233
|
+
jbController()
|
|
234
|
+
.launchProjectFor({
|
|
235
|
+
owner: multisig(),
|
|
236
|
+
projectUri: "whatever",
|
|
237
|
+
rulesetConfigurations: _rulesetConfigurations,
|
|
238
|
+
terminalConfigurations: _terminalConfigurations, // Set terminals to receive fees.
|
|
239
|
+
memo: ""
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//*********************************************************************//
|
|
245
|
+
// ------------------------------- Setup ----------------------------- //
|
|
246
|
+
//*********************************************************************//
|
|
247
|
+
|
|
248
|
+
function setUp() public override {
|
|
249
|
+
// Create (and select) Sepolia fork and make simulator helper contracts persistent.
|
|
250
|
+
initL1AndUtils();
|
|
251
|
+
|
|
252
|
+
// Set metadata for the test projects to use.
|
|
253
|
+
initMetadata();
|
|
254
|
+
|
|
255
|
+
// run setup on our first fork (sepolia) so we have a JBV4 setup (deploys v4 contracts).
|
|
256
|
+
super.setUp();
|
|
257
|
+
|
|
258
|
+
vm.stopPrank();
|
|
259
|
+
vm.startPrank(address(0x1112222));
|
|
260
|
+
suckerDeployer = new JBCCIPSuckerDeployer(jbDirectory(), jbPermissions(), jbTokens(), address(this), address(0));
|
|
261
|
+
vm.stopPrank();
|
|
262
|
+
|
|
263
|
+
// Set the remote chain as arb-sep, which also grabs the chain selector from CCIPHelper for deployer
|
|
264
|
+
suckerDeployer.setChainSpecificConstants(
|
|
265
|
+
421_614, CCIPHelper.selectorOfChain(421_614), ICCIPRouter(CCIPHelper.routerOfChain(block.chainid))
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
// Deploy the singleton and configure it.
|
|
269
|
+
vm.startPrank(address(0x1112222));
|
|
270
|
+
JBCCIPSucker singleton = new JBCCIPSucker({
|
|
271
|
+
deployer: suckerDeployer,
|
|
272
|
+
directory: jbDirectory(),
|
|
273
|
+
permissions: jbPermissions(),
|
|
274
|
+
tokens: jbTokens(),
|
|
275
|
+
addToBalanceMode: JBAddToBalanceMode.MANUAL,
|
|
276
|
+
trustedForwarder: address(0)
|
|
277
|
+
});
|
|
278
|
+
vm.stopPrank();
|
|
279
|
+
|
|
280
|
+
suckerDeployer.configureSingleton(singleton);
|
|
281
|
+
|
|
282
|
+
// deploy our first sucker (on sepolia, the current fork, or "L1").
|
|
283
|
+
suckerGlobal = suckerDeployer.createForSender(1, "salty");
|
|
284
|
+
vm.label(address(suckerGlobal), "suckerGlobal");
|
|
285
|
+
|
|
286
|
+
// In-memory vars needed for setup
|
|
287
|
+
// Allow the sucker to mint- This permission array is also used in second project config toward the end of this
|
|
288
|
+
// setup.
|
|
289
|
+
uint8[] memory ids = new uint8[](1);
|
|
290
|
+
ids[0] = JBPermissionIds.MINT_TOKENS;
|
|
291
|
+
|
|
292
|
+
// Permissions data for setPermissionsFor().
|
|
293
|
+
JBPermissionsData memory perms =
|
|
294
|
+
JBPermissionsData({operator: address(suckerGlobal), projectId: 1, permissionIds: ids});
|
|
295
|
+
|
|
296
|
+
// Chain selectors of remote chains allowed by the suckers (bi-directional in this example).
|
|
297
|
+
uint64[] memory allowedChains = new uint64[](2);
|
|
298
|
+
allowedChains[0] = arbSepoliaChainSelector;
|
|
299
|
+
allowedChains[1] = ethSepoliaChainSelector;
|
|
300
|
+
|
|
301
|
+
// Allow our L1 sucker to mint.
|
|
302
|
+
vm.startPrank(multisig());
|
|
303
|
+
jbPermissions().setPermissionsFor(multisig(), perms);
|
|
304
|
+
|
|
305
|
+
// Launch and configure our project on L1 (selected fork is still sepolia).
|
|
306
|
+
launchAndConfigureL1Project();
|
|
307
|
+
|
|
308
|
+
// Sucker (on L1) now allows our intended chains and L1 setup is complete.
|
|
309
|
+
vm.stopPrank();
|
|
310
|
+
|
|
311
|
+
// Init our L2 fork and CCIP Local simulator utils for L2.
|
|
312
|
+
initL2AndUtils();
|
|
313
|
+
|
|
314
|
+
// Setup JBV4 on our forked L2 (arb-sep).
|
|
315
|
+
super.setUp();
|
|
316
|
+
|
|
317
|
+
vm.stopPrank();
|
|
318
|
+
|
|
319
|
+
vm.startPrank(address(0x1112222));
|
|
320
|
+
suckerDeployer2 =
|
|
321
|
+
new JBCCIPSuckerDeployer(jbDirectory(), jbPermissions(), jbTokens(), address(this), address(0));
|
|
322
|
+
vm.stopPrank();
|
|
323
|
+
|
|
324
|
+
suckerDeployer2.setChainSpecificConstants(
|
|
325
|
+
11_155_111, CCIPHelper.selectorOfChain(11_155_111), ICCIPRouter(CCIPHelper.routerOfChain(block.chainid))
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
// Deploy the singleton and configure it.
|
|
329
|
+
vm.startPrank(address(0x1112222));
|
|
330
|
+
JBCCIPSucker singleton2 = new JBCCIPSucker({
|
|
331
|
+
deployer: suckerDeployer2,
|
|
332
|
+
directory: jbDirectory(),
|
|
333
|
+
permissions: jbPermissions(),
|
|
334
|
+
tokens: jbTokens(),
|
|
335
|
+
addToBalanceMode: JBAddToBalanceMode.MANUAL,
|
|
336
|
+
trustedForwarder: address(0)
|
|
337
|
+
});
|
|
338
|
+
vm.stopPrank();
|
|
339
|
+
|
|
340
|
+
suckerDeployer2.configureSingleton(singleton2);
|
|
341
|
+
|
|
342
|
+
// Deploy the sucker on L2.
|
|
343
|
+
suckerDeployer2.createForSender(1, "salty");
|
|
344
|
+
|
|
345
|
+
// Launch our project on L2.
|
|
346
|
+
vm.startPrank(multisig());
|
|
347
|
+
launchAndConfigureL2Project();
|
|
348
|
+
|
|
349
|
+
// Allow the L2 sucker to mint.
|
|
350
|
+
jbPermissions().setPermissionsFor(multisig(), perms);
|
|
351
|
+
|
|
352
|
+
// Enable intended chains for the L2 Sucker
|
|
353
|
+
vm.stopPrank();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
//*********************************************************************//
|
|
357
|
+
// ------------------------------- Tests ----------------------------- //
|
|
358
|
+
//*********************************************************************//
|
|
359
|
+
|
|
360
|
+
function test_forkNativeTransfer() external {
|
|
361
|
+
// The pool is disabled for now, but functionality was confirmed in past runs.
|
|
362
|
+
// vm.skip(true);
|
|
363
|
+
|
|
364
|
+
// Declare test actors and parameters
|
|
365
|
+
address rootSender = makeAddr("rootSender");
|
|
366
|
+
address user = makeAddr("him");
|
|
367
|
+
uint256 amountToSend = 0.05 ether;
|
|
368
|
+
uint256 maxCashedOut = amountToSend / 2;
|
|
369
|
+
|
|
370
|
+
// Select our L1 fork to begin this test.
|
|
371
|
+
vm.selectFork(sepoliaFork);
|
|
372
|
+
|
|
373
|
+
// Give ourselves test tokens
|
|
374
|
+
vm.deal(user, amountToSend);
|
|
375
|
+
|
|
376
|
+
// Map the token
|
|
377
|
+
JBTokenMapping memory map = JBTokenMapping({
|
|
378
|
+
localToken: JBConstants.NATIVE_TOKEN,
|
|
379
|
+
minGas: 200_000,
|
|
380
|
+
remoteToken: bytes32(uint256(uint160(JBConstants.NATIVE_TOKEN))),
|
|
381
|
+
minBridgeAmount: 1
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
vm.prank(multisig());
|
|
385
|
+
suckerGlobal.mapToken(map);
|
|
386
|
+
|
|
387
|
+
// Let the terminal spend our test tokens so we can pay and receive project tokens
|
|
388
|
+
vm.startPrank(user);
|
|
389
|
+
// ccipBnM.approve(address(jbMultiTerminal()), amountToSend);
|
|
390
|
+
|
|
391
|
+
// receive 500 project tokens as a result
|
|
392
|
+
uint256 projectTokenAmount =
|
|
393
|
+
jbMultiTerminal().pay{value: amountToSend}(1, JBConstants.NATIVE_TOKEN, amountToSend, user, 0, "", "");
|
|
394
|
+
|
|
395
|
+
// Approve the sucker to use those project tokens received by the user (we are still pranked as user)
|
|
396
|
+
IERC20(address(projectOneToken)).approve(address(suckerGlobal), projectTokenAmount);
|
|
397
|
+
|
|
398
|
+
// Call prepare which uses our project tokens to retrieve (cash out) for our backing tokens (test token)
|
|
399
|
+
suckerGlobal.prepare(
|
|
400
|
+
projectTokenAmount, bytes32(uint256(uint160(user))), maxCashedOut, JBConstants.NATIVE_TOKEN
|
|
401
|
+
);
|
|
402
|
+
vm.stopPrank();
|
|
403
|
+
|
|
404
|
+
// Give the root sender some eth to pay the fees
|
|
405
|
+
vm.deal(rootSender, 1 ether);
|
|
406
|
+
|
|
407
|
+
// Initiates the bridging
|
|
408
|
+
vm.prank(rootSender);
|
|
409
|
+
suckerGlobal.toRemote{value: 1 ether}(JBConstants.NATIVE_TOKEN);
|
|
410
|
+
|
|
411
|
+
// Check outbox is cleared
|
|
412
|
+
uint256 outboxBalance = suckerGlobal.outboxOf(JBConstants.NATIVE_TOKEN).balance;
|
|
413
|
+
assertEq(outboxBalance, 0);
|
|
414
|
+
|
|
415
|
+
// Fees are paid but balance isn't zero (excess msg.value is returned)
|
|
416
|
+
assert(rootSender.balance < 1 ether);
|
|
417
|
+
assert(rootSender.balance > 0);
|
|
418
|
+
|
|
419
|
+
// Use CCIP local to initiate the transfer on the L2
|
|
420
|
+
ccipLocalSimulatorFork.switchChainAndRouteMessage(arbSepoliaFork);
|
|
421
|
+
|
|
422
|
+
// Check that the tokens were transferred
|
|
423
|
+
assertEq(address(suckerGlobal).balance, maxCashedOut);
|
|
424
|
+
|
|
425
|
+
// This is the most simple verification that messages are being sent and received though
|
|
426
|
+
// Meaning CCIP transferred the data to our sucker on L2's inbox
|
|
427
|
+
bytes32 inboxRoot = suckerGlobal.inboxOf(JBConstants.NATIVE_TOKEN).root;
|
|
428
|
+
assertNotEq(inboxRoot, bytes32(0));
|
|
429
|
+
|
|
430
|
+
// Ensure correct native value was sent.
|
|
431
|
+
assertEq(address(suckerGlobal).balance, maxCashedOut);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function test_forkTokenTransfer() external {
|
|
435
|
+
// Declare test actors and parameters
|
|
436
|
+
address rootSender = makeAddr("rootSender");
|
|
437
|
+
address user = makeAddr("him");
|
|
438
|
+
uint256 amountToSend = 100;
|
|
439
|
+
uint256 maxCashedOut = amountToSend / 2;
|
|
440
|
+
|
|
441
|
+
// Select our L1 fork to begin this test.
|
|
442
|
+
vm.selectFork(sepoliaFork);
|
|
443
|
+
|
|
444
|
+
// Give ourselves test tokens
|
|
445
|
+
ccipBnM.drip(address(user));
|
|
446
|
+
|
|
447
|
+
// Map the token
|
|
448
|
+
JBTokenMapping memory map = JBTokenMapping({
|
|
449
|
+
localToken: address(ccipBnM),
|
|
450
|
+
minGas: 200_000,
|
|
451
|
+
remoteToken: bytes32(uint256(uint160(address(ccipBnMArbSepolia)))),
|
|
452
|
+
minBridgeAmount: 1
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
vm.prank(multisig());
|
|
456
|
+
suckerGlobal.mapToken(map);
|
|
457
|
+
|
|
458
|
+
// Let the terminal spend our test tokens so we can pay and receive project tokens
|
|
459
|
+
vm.startPrank(user);
|
|
460
|
+
ccipBnM.approve(address(jbMultiTerminal()), amountToSend);
|
|
461
|
+
|
|
462
|
+
// receive 500 project tokens as a result
|
|
463
|
+
uint256 projectTokenAmount = jbMultiTerminal().pay(1, address(ccipBnM), amountToSend, user, 0, "", "");
|
|
464
|
+
|
|
465
|
+
// Approve the sucker to use those project tokens received by the user (we are still pranked as user)
|
|
466
|
+
IERC20(address(projectOneToken)).approve(address(suckerGlobal), projectTokenAmount);
|
|
467
|
+
|
|
468
|
+
// Call prepare which uses our project tokens to retrieve (cash out) for our backing tokens (test token)
|
|
469
|
+
suckerGlobal.prepare(projectTokenAmount, bytes32(uint256(uint160(user))), maxCashedOut, address(ccipBnM));
|
|
470
|
+
vm.stopPrank();
|
|
471
|
+
|
|
472
|
+
// Give the root sender some eth to pay the fees
|
|
473
|
+
vm.deal(rootSender, 1 ether);
|
|
474
|
+
|
|
475
|
+
// Initiates the bridging
|
|
476
|
+
vm.prank(rootSender);
|
|
477
|
+
suckerGlobal.toRemote{value: 1 ether}(address(ccipBnM));
|
|
478
|
+
|
|
479
|
+
// Fees are paid but balance isn't zero (excess msg.value is returned)
|
|
480
|
+
assert(rootSender.balance < 1 ether);
|
|
481
|
+
assert(rootSender.balance > 0);
|
|
482
|
+
|
|
483
|
+
// Check outbox is cleared
|
|
484
|
+
uint256 outboxBalance = suckerGlobal.outboxOf(address(ccipBnM)).balance;
|
|
485
|
+
assertEq(outboxBalance, 0);
|
|
486
|
+
|
|
487
|
+
// Use CCIP local to initiate the transfer on the L2
|
|
488
|
+
ccipLocalSimulatorFork.switchChainAndRouteMessage(arbSepoliaFork);
|
|
489
|
+
|
|
490
|
+
// Check that the tokens were transferred
|
|
491
|
+
assertEq(ccipBnMArbSepolia.balanceOf(address(suckerGlobal)), maxCashedOut);
|
|
492
|
+
|
|
493
|
+
// This is the most simple verification that messages are being sent and received though
|
|
494
|
+
// Meaning CCIP transferred the data to our sucker on L2's inbox
|
|
495
|
+
bytes32 inboxRoot = suckerGlobal.inboxOf(address(ccipBnMArbSepolia)).root;
|
|
496
|
+
assertNotEq(inboxRoot, bytes32(0));
|
|
497
|
+
|
|
498
|
+
// TODO: Maybe test claiming but it was working in previous version from another repo
|
|
499
|
+
// Setup claim data
|
|
500
|
+
/* JBLeaf memory _leaf = JBLeaf({
|
|
501
|
+
index: 1,
|
|
502
|
+
beneficiary: user,
|
|
503
|
+
projectTokenAmount: projectTokenAmount,
|
|
504
|
+
terminalTokenAmount: maxCashedOut
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// faux proof data for test claim
|
|
508
|
+
bytes32[32] memory _proof;
|
|
509
|
+
|
|
510
|
+
JBClaim memory _claimData = JBClaim({token: address(ccipBnMArbSepolia), leaf: _leaf, proof: _proof});
|
|
511
|
+
|
|
512
|
+
suckerGlobal.testClaim(_claimData); */
|
|
513
|
+
}
|
|
514
|
+
}
|