@bananapus/suckers-v6 0.0.36 → 0.0.37
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/README.md +3 -3
- package/package.json +2 -2
- package/references/operations.md +2 -2
- package/references/runtime.md +1 -1
- package/src/JBArbitrumSucker.sol +5 -17
- package/src/JBCCIPSucker.sol +2 -5
- package/src/JBCeloSucker.sol +1 -8
- package/src/JBOptimismSucker.sol +1 -4
- package/src/JBSucker.sol +53 -61
- package/src/JBSuckerRegistry.sol +4 -22
- package/src/JBSwapCCIPSucker.sol +50 -24
- package/src/deployers/JBArbitrumSuckerDeployer.sol +5 -3
- package/src/deployers/JBCCIPSuckerDeployer.sol +5 -3
- package/src/deployers/JBCeloSuckerDeployer.sol +5 -3
- package/src/deployers/JBOptimismSuckerDeployer.sol +5 -3
- package/src/deployers/JBSuckerDeployer.sol +14 -10
- package/src/deployers/JBSwapCCIPSuckerDeployer.sol +5 -7
- package/src/libraries/ARBAddresses.sol +6 -3
- package/src/libraries/ARBChains.sol +4 -1
- package/src/libraries/CCIPHelper.sol +66 -9
- package/src/libraries/JBCCIPLib.sol +0 -9
- package/src/libraries/JBSuckerLib.sol +2 -13
- package/src/libraries/JBSwapPoolLib.sol +34 -26
- package/src/utils/MerkleLib.sol +3 -5
package/README.md
CHANGED
|
@@ -72,8 +72,8 @@ That means every bridge path has two trust surfaces:
|
|
|
72
72
|
1. `test/unit/registry.t.sol`
|
|
73
73
|
2. `test/unit/multi_chain_evolution.t.sol`
|
|
74
74
|
3. `test/ForkClaimMainnet.t.sol`
|
|
75
|
-
4. `test/
|
|
76
|
-
5. `test/
|
|
75
|
+
4. `test/regression/PeerSnapshotDesync.t.sol`
|
|
76
|
+
5. `test/regression/ToRemoteFeeIrrecoverable.t.sol`
|
|
77
77
|
|
|
78
78
|
## Install
|
|
79
79
|
|
|
@@ -113,7 +113,7 @@ src/
|
|
|
113
113
|
structs/
|
|
114
114
|
utils/
|
|
115
115
|
test/
|
|
116
|
-
unit, fork, interoperability, attack,
|
|
116
|
+
unit, fork, interoperability, attack, review, and regression coverage
|
|
117
117
|
script/
|
|
118
118
|
Deploy.s.sol
|
|
119
119
|
helpers/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bananapus/suckers-v6",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"deploy:mainnets": "source ./.env && npx sphinx propose ./script/Deploy.s.sol --networks mainnets",
|
|
27
27
|
"deploy:testnets": "source ./.env && npx sphinx propose ./script/Deploy.s.sol --networks testnets",
|
|
28
28
|
"artifacts": "source ./.env && npx sphinx artifacts --org-id 'ea165b21-7cdc-4d7b-be59-ecdd4c26bee4' --project-name 'nana-suckers-v6'",
|
|
29
|
-
"analyze": "
|
|
29
|
+
"analyze": "forge lint --deny notes"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@arbitrum/nitro-contracts": "3.2.0",
|
package/references/operations.md
CHANGED
|
@@ -23,6 +23,6 @@
|
|
|
23
23
|
|
|
24
24
|
## Useful Proof Points
|
|
25
25
|
|
|
26
|
-
- [`test/SuckerAttacks.t.sol`](../test/SuckerAttacks.t.sol), [`test/SuckerDeepAttacks.t.sol`](../test/SuckerDeepAttacks.t.sol), and [`test/
|
|
26
|
+
- [`test/SuckerAttacks.t.sol`](../test/SuckerAttacks.t.sol), [`test/SuckerDeepAttacks.t.sol`](../test/SuckerDeepAttacks.t.sol), and [`test/TestRegressionGaps.sol`](../test/TestRegressionGaps.sol) for security-sensitive assumptions.
|
|
27
27
|
- [`test/InteropCompat.t.sol`](../test/InteropCompat.t.sol) when the problem is deployment wiring rather than runtime logic.
|
|
28
|
-
- [`test/unit/invariants.t.sol`](../test/unit/invariants.t.sol), [`test/unit/peer_chain_state.t.sol`](../test/unit/peer_chain_state.t.sol), and [`test/
|
|
28
|
+
- [`test/unit/invariants.t.sol`](../test/unit/invariants.t.sol), [`test/unit/peer_chain_state.t.sol`](../test/unit/peer_chain_state.t.sol), and [`test/regression/PeerSnapshotDesync.t.sol`](../test/regression/PeerSnapshotDesync.t.sol) when shared accounting or snapshot boundaries are in doubt.
|
package/references/runtime.md
CHANGED
|
@@ -27,4 +27,4 @@
|
|
|
27
27
|
- [`test/ForkMainnet.t.sol`](../test/ForkMainnet.t.sol), [`test/ForkArbitrum.t.sol`](../test/ForkArbitrum.t.sol), [`test/ForkCelo.t.sol`](../test/ForkCelo.t.sol), and [`test/ForkOPStack.t.sol`](../test/ForkOPStack.t.sol) for real transport assumptions.
|
|
28
28
|
- [`test/ForkSwap.t.sol`](../test/ForkSwap.t.sol), [`test/ForkClaimMainnet.t.sol`](../test/ForkClaimMainnet.t.sol), and [`test/SuckerRegressions.t.sol`](../test/SuckerRegressions.t.sol) for pinned cross-chain edge cases.
|
|
29
29
|
- [`test/unit/invariants.t.sol`](../test/unit/invariants.t.sol), [`test/unit/peer_chain_state.t.sol`](../test/unit/peer_chain_state.t.sol), and [`test/unit/registry.t.sol`](../test/unit/registry.t.sol) for shared-accounting invariants.
|
|
30
|
-
- [`test/SuckerAttacks.t.sol`](../test/SuckerAttacks.t.sol), [`test/SuckerDeepAttacks.t.sol`](../test/SuckerDeepAttacks.t.sol), [`test/
|
|
30
|
+
- [`test/SuckerAttacks.t.sol`](../test/SuckerAttacks.t.sol), [`test/SuckerDeepAttacks.t.sol`](../test/SuckerDeepAttacks.t.sol), [`test/regression/PeerSnapshotDesync.t.sol`](../test/regression/PeerSnapshotDesync.t.sol), and [`test/regression/PeerDeterminism.t.sol`](../test/regression/PeerDeterminism.t.sol) when the bug could involve base logic, registry behavior, or a specific bridge implementation.
|
package/src/JBArbitrumSucker.sol
CHANGED
|
@@ -127,7 +127,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
127
127
|
internal
|
|
128
128
|
{
|
|
129
129
|
address peerAddress = _peerAddress();
|
|
130
|
-
// slither-disable-next-line unused-return,calls-loop
|
|
131
130
|
ARBINBOX.unsafeCreateRetryableTicket{value: callTransportCost + nativeValue}({
|
|
132
131
|
to: peerAddress,
|
|
133
132
|
l2CallValue: nativeValue,
|
|
@@ -144,7 +143,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
144
143
|
/// @param token The ERC-20 token to approve.
|
|
145
144
|
/// @param amount The amount to approve.
|
|
146
145
|
function _approveGateway(address token, uint256 amount) internal {
|
|
147
|
-
// slither-disable-next-line calls-loop
|
|
148
146
|
SafeERC20.forceApprove({token: IERC20(token), spender: GATEWAYROUTER.getGateway(token), value: amount});
|
|
149
147
|
}
|
|
150
148
|
|
|
@@ -168,10 +166,9 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
168
166
|
bytes memory data = abi.encodeCall(JBSucker.fromRemote, (message));
|
|
169
167
|
|
|
170
168
|
// Depending on which layer we are on, send the call to the other layer.
|
|
171
|
-
// slither-disable-start out-of-order-retryable
|
|
172
169
|
if (LAYER == JBLayer.L1) {
|
|
173
170
|
// L1→L2 requires transport payment for retryable tickets.
|
|
174
|
-
if (transportPayment == 0) revert JBSucker_ExpectedMsgValue();
|
|
171
|
+
if (transportPayment == 0) revert JBSucker_ExpectedMsgValue({msgValue: transportPayment});
|
|
175
172
|
_toL2({
|
|
176
173
|
token: token, transportPayment: transportPayment, amount: amount, data: data, remoteToken: remoteToken
|
|
177
174
|
});
|
|
@@ -180,7 +177,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
180
177
|
if (transportPayment != 0) revert JBSucker_UnexpectedMsgValue(transportPayment);
|
|
181
178
|
_toL1({token: token, amount: amount, data: data, remoteToken: remoteToken});
|
|
182
179
|
}
|
|
183
|
-
// slither-disable-end out-of-order-retryable
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
/// @notice Bridge the `token` and data to the remote L1 chain.
|
|
@@ -208,7 +204,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
208
204
|
_approveGateway({token: token, amount: amount});
|
|
209
205
|
|
|
210
206
|
// Convert bytes32 types to address at the Arbitrum bridge API boundary.
|
|
211
|
-
// slither-disable-next-line calls-loop,unused-return
|
|
212
207
|
IArbL2GatewayRouter(address(GATEWAYROUTER))
|
|
213
208
|
.outboundTransfer({
|
|
214
209
|
l1Token: _toAddress(remoteToken.addr), to: peerAddress, amount: amount, data: bytes("")
|
|
@@ -220,7 +215,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
220
215
|
|
|
221
216
|
// Send the message to the peer with the reclaimed ETH.
|
|
222
217
|
// Address `100` is the ArbSys precompile address.
|
|
223
|
-
// slither-disable-next-line calls-loop,unused-return
|
|
224
218
|
ArbSys(address(100)).sendTxToL1{value: nativeValue}({destination: peerAddress, data: data});
|
|
225
219
|
}
|
|
226
220
|
|
|
@@ -251,7 +245,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
251
245
|
uint256 maxSubmissionCost;
|
|
252
246
|
|
|
253
247
|
{
|
|
254
|
-
// slither-disable-next-line calls-loop
|
|
255
248
|
maxSubmissionCost =
|
|
256
249
|
ARBINBOX.calculateRetryableSubmissionFee({dataLength: data.length, baseFee: maxFeePerGas});
|
|
257
250
|
|
|
@@ -267,15 +260,12 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
267
260
|
{
|
|
268
261
|
// Get the exact calldata length the gateway will create for the retryable ticket.
|
|
269
262
|
// The Arbitrum Inbox validates maxSubmissionCost against this actual payload, not the user data.
|
|
270
|
-
// slither-disable-next-line calls-loop
|
|
271
263
|
address gateway = GATEWAYROUTER.getGateway(token);
|
|
272
|
-
// slither-disable-next-line calls-loop
|
|
273
264
|
uint256 outboundCalldataLength =
|
|
274
265
|
IL1ArbitrumGateway(gateway)
|
|
275
266
|
.getOutboundCalldata({
|
|
276
267
|
_token: token, _from: address(this), _to: _peerAddress(), _amount: amount, _data: bytes("")
|
|
277
268
|
}).length;
|
|
278
|
-
// slither-disable-next-line calls-loop
|
|
279
269
|
maxSubmissionCostERC20 = ARBINBOX.calculateRetryableSubmissionFee({
|
|
280
270
|
dataLength: outboundCalldataLength, baseFee: maxFeePerGas
|
|
281
271
|
});
|
|
@@ -284,7 +274,9 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
284
274
|
|
|
285
275
|
// Ensure we bridge enough for gas costs on L2 side
|
|
286
276
|
if (transportPayment < callTransportCost + tokenTransportCost) {
|
|
287
|
-
revert JBArbitrumSucker_NotEnoughGas(
|
|
277
|
+
revert JBArbitrumSucker_NotEnoughGas({
|
|
278
|
+
payment: transportPayment, cost: callTransportCost + tokenTransportCost
|
|
279
|
+
});
|
|
288
280
|
}
|
|
289
281
|
|
|
290
282
|
{
|
|
@@ -298,8 +290,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
298
290
|
_approveGateway({token: token, amount: amount});
|
|
299
291
|
|
|
300
292
|
// Perform the ERC-20 bridge transfer. Convert bytes32 peer to address at the Arbitrum bridge API boundary.
|
|
301
|
-
// slither-disable-start out-of-order-retryable
|
|
302
|
-
// slither-disable-next-line calls-loop,unused-return
|
|
303
293
|
IArbL1GatewayRouter(address(GATEWAYROUTER)).outboundTransferCustomRefund{value: tokenTransportCost}({
|
|
304
294
|
token: token,
|
|
305
295
|
refundTo: _msgSender(),
|
|
@@ -312,7 +302,7 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
312
302
|
} else {
|
|
313
303
|
// Ensure we bridge enough for gas costs on L2 side
|
|
314
304
|
if (transportPayment < callTransportCost) {
|
|
315
|
-
revert JBArbitrumSucker_NotEnoughGas(transportPayment, callTransportCost);
|
|
305
|
+
revert JBArbitrumSucker_NotEnoughGas({payment: transportPayment, cost: callTransportCost});
|
|
316
306
|
}
|
|
317
307
|
|
|
318
308
|
// If the token is the native token then we only need to do a single call.
|
|
@@ -328,7 +318,6 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
328
318
|
// The above check is the same check that makes it `safeCreateRetryableTicket`.
|
|
329
319
|
|
|
330
320
|
// Convert bytes32 peer to address at the Arbitrum inbox API boundary.
|
|
331
|
-
// slither-disable-next-line calls-loop,unused-return
|
|
332
321
|
_createRetryableTicket({
|
|
333
322
|
callTransportCost: callTransportCost,
|
|
334
323
|
nativeValue: nativeValue,
|
|
@@ -336,6 +325,5 @@ contract JBArbitrumSucker is JBSucker, IJBArbitrumSucker {
|
|
|
336
325
|
maxFeePerGas: maxFeePerGas,
|
|
337
326
|
data: data
|
|
338
327
|
});
|
|
339
|
-
// slither-disable-end out-of-order-retryable
|
|
340
328
|
}
|
|
341
329
|
}
|
package/src/JBCCIPSucker.sol
CHANGED
|
@@ -163,7 +163,7 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
|
|
|
163
163
|
|
|
164
164
|
// Make sure that the message came from our peer.
|
|
165
165
|
if (origin != _peerAddress() || any2EvmMessage.sourceChainSelector != REMOTE_CHAIN_SELECTOR) {
|
|
166
|
-
revert JBSucker_NotPeer(_toBytes32(origin));
|
|
166
|
+
revert JBSucker_NotPeer({caller: _toBytes32(origin)});
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// Discriminate message type: abi.encode(uint8 type, bytes payload).
|
|
@@ -184,7 +184,7 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
|
|
|
184
184
|
// Forward the root message to this contract's fromRemote handler.
|
|
185
185
|
this.fromRemote(root);
|
|
186
186
|
} else {
|
|
187
|
-
revert JBCCIPSucker_UnknownMessageType(messageType);
|
|
187
|
+
revert JBCCIPSucker_UnknownMessageType({messageType: messageType});
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -225,7 +225,6 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
|
|
|
225
225
|
gasLimit += remoteToken.minGas;
|
|
226
226
|
|
|
227
227
|
// Wrap native tokens if needed, build the CCIP token amounts array, and approve the router.
|
|
228
|
-
// slither-disable-next-line unused-return
|
|
229
228
|
(tokenAmounts,) = JBCCIPLib.prepareTokenAmounts({ccipRouter: CCIP_ROUTER, token: token, amount: amount});
|
|
230
229
|
} else {
|
|
231
230
|
// No tokens to bridge — use an empty array.
|
|
@@ -239,7 +238,6 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
|
|
|
239
238
|
address feeToken = transportPayment == 0 ? CCIPHelper.linkOfChain(block.chainid) : address(0);
|
|
240
239
|
|
|
241
240
|
// Build and send the CCIP message with the root payload.
|
|
242
|
-
// slither-disable-next-line reentrancy-events
|
|
243
241
|
(bool refundFailed, uint256 refundAmount) = JBCCIPLib.sendCCIPMessage({
|
|
244
242
|
ccipRouter: CCIP_ROUTER,
|
|
245
243
|
remoteChainSelector: REMOTE_CHAIN_SELECTOR,
|
|
@@ -256,7 +254,6 @@ contract JBCCIPSucker is JBSucker, IAny2EVMMessageReceiver {
|
|
|
256
254
|
// Retain failed refunds as caller credit instead of leaving them project-addable or stranded.
|
|
257
255
|
if (refundFailed) {
|
|
258
256
|
// Refund accounting is isolated per caller; reentry cannot increase the retained credit.
|
|
259
|
-
// slither-disable-next-line reentrancy-benign
|
|
260
257
|
_retainTransportPaymentRefund({account: _msgSender(), amount: refundAmount});
|
|
261
258
|
emit TransportPaymentRefundFailed({recipient: _msgSender(), amount: refundAmount});
|
|
262
259
|
}
|
package/src/JBCeloSucker.sol
CHANGED
|
@@ -90,11 +90,9 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
// Unwrap wrapped native tokens → native tokens.
|
|
93
|
-
// slither-disable-next-line calls-loop
|
|
94
93
|
WRAPPED_NATIVE_TOKEN.withdraw(amount);
|
|
95
94
|
|
|
96
95
|
// Get the project's primary terminal for native token.
|
|
97
|
-
// slither-disable-next-line calls-loop
|
|
98
96
|
IJBTerminal terminal =
|
|
99
97
|
DIRECTORY.primaryTerminalOf({projectId: cachedProjectId, token: JBConstants.NATIVE_TOKEN});
|
|
100
98
|
|
|
@@ -103,7 +101,6 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
// Add native ETH to the project's balance.
|
|
106
|
-
// slither-disable-next-line arbitrary-send-eth,calls-loop
|
|
107
104
|
terminal.addToBalanceOf{value: amount}({
|
|
108
105
|
projectId: cachedProjectId,
|
|
109
106
|
token: JBConstants.NATIVE_TOKEN,
|
|
@@ -140,7 +137,7 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
140
137
|
|
|
141
138
|
// Revert if there's a `msg.value`. The OP bridge does not expect to be paid.
|
|
142
139
|
if (transportPayment != 0) {
|
|
143
|
-
revert JBSucker_UnexpectedMsgValue(transportPayment);
|
|
140
|
+
revert JBSucker_UnexpectedMsgValue({value: transportPayment});
|
|
144
141
|
}
|
|
145
142
|
|
|
146
143
|
// Cache peer address to avoid redundant calls.
|
|
@@ -151,17 +148,14 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
151
148
|
address bridgeToken = token;
|
|
152
149
|
if (token == JBConstants.NATIVE_TOKEN) {
|
|
153
150
|
// Wrap native tokens so they can be bridged as ERC-20.
|
|
154
|
-
// slither-disable-next-line arbitrary-send-eth,calls-loop
|
|
155
151
|
WRAPPED_NATIVE_TOKEN.deposit{value: amount}();
|
|
156
152
|
bridgeToken = address(WRAPPED_NATIVE_TOKEN);
|
|
157
153
|
}
|
|
158
154
|
|
|
159
155
|
// Approve the bridge to spend the token.
|
|
160
|
-
// slither-disable-next-line reentrancy-events
|
|
161
156
|
SafeERC20.forceApprove({token: IERC20(bridgeToken), spender: address(OPBRIDGE), value: amount});
|
|
162
157
|
|
|
163
158
|
// Bridge the ERC-20 token to the peer.
|
|
164
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
165
159
|
OPBRIDGE.bridgeERC20To({
|
|
166
160
|
localToken: bridgeToken,
|
|
167
161
|
remoteToken: _toAddress(remoteToken.addr),
|
|
@@ -175,7 +169,6 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
175
169
|
// Send the messenger message with nativeValue = 0.
|
|
176
170
|
// Celo's native token is CELO, not ETH — we never attach ETH as msg.value on the messenger.
|
|
177
171
|
// On L1, the ETH was already wrapped and bridged as ERC-20 above.
|
|
178
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
179
172
|
OPMESSENGER.sendMessage({
|
|
180
173
|
target: peerAddress,
|
|
181
174
|
message: abi.encodeCall(JBSucker.fromRemote, (message)),
|
package/src/JBOptimismSucker.sol
CHANGED
|
@@ -105,7 +105,7 @@ contract JBOptimismSucker is JBSucker, IJBOptimismSucker {
|
|
|
105
105
|
|
|
106
106
|
// Revert if there's a `msg.value`. The OP bridge does not expect to be paid.
|
|
107
107
|
if (transportPayment != 0) {
|
|
108
|
-
revert JBSucker_UnexpectedMsgValue(transportPayment);
|
|
108
|
+
revert JBSucker_UnexpectedMsgValue({value: transportPayment});
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
// Cache peer address to avoid redundant calls.
|
|
@@ -115,11 +115,9 @@ contract JBOptimismSucker is JBSucker, IJBOptimismSucker {
|
|
|
115
115
|
// If the amount is `0` then we do not need to bridge any ERC20.
|
|
116
116
|
if (token != JBConstants.NATIVE_TOKEN && amount != 0) {
|
|
117
117
|
// Approve the tokens being bridged.
|
|
118
|
-
// slither-disable-next-line reentrancy-events
|
|
119
118
|
SafeERC20.forceApprove({token: IERC20(token), spender: address(OPBRIDGE), value: amount});
|
|
120
119
|
|
|
121
120
|
// Bridge the tokens to the peer sucker. Convert bytes32 types to address at the OP Bridge API boundary.
|
|
122
|
-
// slither-disable-next-line reentrancy-events,calls-loop
|
|
123
121
|
OPBRIDGE.bridgeERC20To({
|
|
124
122
|
localToken: token,
|
|
125
123
|
remoteToken: _toAddress(remoteToken.addr),
|
|
@@ -134,7 +132,6 @@ contract JBOptimismSucker is JBSucker, IJBOptimismSucker {
|
|
|
134
132
|
}
|
|
135
133
|
|
|
136
134
|
// Send the message to the peer with the reclaimed ETH.
|
|
137
|
-
// slither-disable-next-line arbitrary-send-eth,reentrancy-events,calls-loop
|
|
138
135
|
OPMESSENGER.sendMessage{value: nativeValue}({
|
|
139
136
|
target: peerAddress,
|
|
140
137
|
message: abi.encodeCall(JBSucker.fromRemote, (message)),
|