@bananapus/suckers-v6 0.0.47 → 0.0.49
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/package.json +3 -3
- package/script/Deploy.s.sol +125 -139
- package/script/helpers/SuckerDeploymentLib.sol +10 -12
- package/src/JBArbitrumSucker.sol +5 -2
- package/src/JBCCIPSucker.sol +3 -3
- package/src/JBCeloSucker.sol +2 -0
- package/src/JBOptimismSucker.sol +2 -0
- package/src/JBSucker.sol +42 -8
- package/src/JBSuckerRegistry.sol +79 -60
- package/src/JBSwapCCIPSucker.sol +38 -101
- package/src/deployers/JBSwapCCIPSuckerDeployer.sol +17 -17
- package/src/interfaces/IJBSucker.sol +11 -6
- package/src/interfaces/IJBSuckerRegistry.sol +6 -3
- package/src/interfaces/IL1ArbitrumGateway.sol +10 -10
- package/src/libraries/CCIPHelper.sol +64 -64
- package/src/libraries/JBCCIPLib.sol +18 -0
- package/src/libraries/JBRelayBeneficiary.sol +1 -1
- package/src/libraries/JBSuckerLib.sol +157 -161
- package/src/libraries/JBSwapPoolLib.sol +268 -268
- package/src/structs/PeerValueScratch.sol +18 -0
- package/src/utils/MerkleLib.sol +108 -108
|
@@ -38,6 +38,56 @@ library JBSuckerLib {
|
|
|
38
38
|
/// @notice The ETH decimal precision used for cross-chain peer snapshots.
|
|
39
39
|
uint8 internal constant _ETH_DECIMALS = 18;
|
|
40
40
|
|
|
41
|
+
//*********************************************************************//
|
|
42
|
+
// ---------------------- external transactions ---------------------- //
|
|
43
|
+
//*********************************************************************//
|
|
44
|
+
|
|
45
|
+
/// @notice Build the cross-chain snapshot message (total supply, surplus, balance).
|
|
46
|
+
/// @dev Extracted from `JBSucker._buildSnapshotAndSend` to reduce child contract bytecode.
|
|
47
|
+
/// Called via DELEGATECALL. Includes ETH aggregate computation inline (cannot call own external fns).
|
|
48
|
+
/// @param directory The JB directory to look up controllers and terminals.
|
|
49
|
+
/// @param prices The price oracle to use for non-ETH terminal-token balances.
|
|
50
|
+
/// @param projectId The project ID.
|
|
51
|
+
/// @param remoteToken The remote token bytes32 address.
|
|
52
|
+
/// @param amount The amount of terminal tokens to bridge.
|
|
53
|
+
/// @param nonce The outbox nonce for this send.
|
|
54
|
+
/// @param root The merkle root of the outbox tree.
|
|
55
|
+
/// @param messageVersion The message format version.
|
|
56
|
+
/// @param sourceTimestamp The monotonic source freshness key for this snapshot.
|
|
57
|
+
/// @return message The constructed JBMessageRoot.
|
|
58
|
+
function buildSnapshotMessage(
|
|
59
|
+
IJBDirectory directory,
|
|
60
|
+
IJBPrices prices,
|
|
61
|
+
uint256 projectId,
|
|
62
|
+
bytes32 remoteToken,
|
|
63
|
+
uint256 amount,
|
|
64
|
+
uint64 nonce,
|
|
65
|
+
bytes32 root,
|
|
66
|
+
uint8 messageVersion,
|
|
67
|
+
uint256 sourceTimestamp
|
|
68
|
+
)
|
|
69
|
+
external
|
|
70
|
+
view
|
|
71
|
+
returns (JBMessageRoot memory message)
|
|
72
|
+
{
|
|
73
|
+
(uint256 localTotalSupply, uint256 ethSurplus, uint256 ethBalance) =
|
|
74
|
+
_snapshotAccountsOf({directory: directory, prices: prices, projectId: projectId});
|
|
75
|
+
|
|
76
|
+
// Construct the cross-chain message with the snapshot data.
|
|
77
|
+
message = JBMessageRoot({
|
|
78
|
+
version: messageVersion,
|
|
79
|
+
token: remoteToken,
|
|
80
|
+
amount: amount,
|
|
81
|
+
remoteRoot: JBInboxTreeRoot({nonce: nonce, root: root}),
|
|
82
|
+
sourceTotalSupply: localTotalSupply,
|
|
83
|
+
sourceCurrency: JBCurrencyIds.ETH,
|
|
84
|
+
sourceDecimals: _ETH_DECIMALS,
|
|
85
|
+
sourceSurplus: ethSurplus,
|
|
86
|
+
sourceBalance: ethBalance,
|
|
87
|
+
sourceTimestamp: sourceTimestamp
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
41
91
|
//*********************************************************************//
|
|
42
92
|
// ------------------------- external views -------------------------- //
|
|
43
93
|
//*********************************************************************//
|
|
@@ -61,8 +111,114 @@ library JBSuckerLib {
|
|
|
61
111
|
return _buildETHAggregateInternal({directory: directory, projectId: projectId, prices: prices});
|
|
62
112
|
}
|
|
63
113
|
|
|
114
|
+
/// @notice Compute a branch root from a leaf, branch, and index. Wraps MerkleLib.branchRoot so its
|
|
115
|
+
/// ~170 lines of unrolled assembly live in the library's bytecode instead of each sucker's.
|
|
116
|
+
/// @param item The leaf hash.
|
|
117
|
+
/// @param branch The 32-element merkle proof branch.
|
|
118
|
+
/// @param index The leaf index.
|
|
119
|
+
/// @return The computed merkle root.
|
|
120
|
+
function computeBranchRoot(bytes32 item, bytes32[32] memory branch, uint256 index) external pure returns (bytes32) {
|
|
121
|
+
// Delegate to MerkleLib's unrolled assembly implementation.
|
|
122
|
+
return MerkleLib.branchRoot({item: item, branch: branch, index: index});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// @notice Compute the merkle tree root from branch and count. Loop-based replacement for the unrolled
|
|
126
|
+
/// MerkleLib.root() — saves ~3KB per sucker when called via DELEGATECALL instead of inlining.
|
|
127
|
+
/// @param branch The 32-element branch array (caller copies from storage to memory).
|
|
128
|
+
/// @param count The number of leaves inserted into the tree.
|
|
129
|
+
/// @return current The merkle root.
|
|
130
|
+
function computeTreeRoot(bytes32[32] memory branch, uint256 count) external pure returns (bytes32 current) {
|
|
131
|
+
// An empty tree has a well-known root.
|
|
132
|
+
if (count == 0) return MerkleLib.Z_32;
|
|
133
|
+
|
|
134
|
+
// solhint-disable-next-line no-inline-assembly
|
|
135
|
+
assembly ("memory-safe") {
|
|
136
|
+
// Build zero hashes on-the-fly: Z[0] = 0, Z[i+1] = keccak256(Z[i], Z[i]).
|
|
137
|
+
let zPtr := mload(0x40)
|
|
138
|
+
mstore(0x40, add(zPtr, 0x420)) // 33 slots × 32 bytes
|
|
139
|
+
mstore(zPtr, 0) // Z[0] = bytes32(0)
|
|
140
|
+
for { let j := 0 } lt(j, 32) { j := add(j, 1) } {
|
|
141
|
+
let prev := mload(add(zPtr, mul(j, 0x20)))
|
|
142
|
+
mstore(0x00, prev)
|
|
143
|
+
mstore(0x20, prev)
|
|
144
|
+
mstore(add(zPtr, mul(add(j, 1), 0x20)), keccak256(0x00, 0x40))
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Walk bits of `count` from LSB to MSB.
|
|
148
|
+
// First set bit → initialize current = keccak256(branch[i], Z[i]).
|
|
149
|
+
// Each subsequent level → merge branch[i] or Z[i] with current.
|
|
150
|
+
let started := 0
|
|
151
|
+
for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
|
|
152
|
+
switch started
|
|
153
|
+
case 0 {
|
|
154
|
+
if and(count, shl(i, 1)) {
|
|
155
|
+
mstore(0x00, mload(add(branch, mul(i, 0x20))))
|
|
156
|
+
mstore(0x20, mload(add(zPtr, mul(i, 0x20))))
|
|
157
|
+
current := keccak256(0x00, 0x40)
|
|
158
|
+
started := 1
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
default {
|
|
162
|
+
switch and(count, shl(i, 1))
|
|
163
|
+
case 0 {
|
|
164
|
+
mstore(0x00, current)
|
|
165
|
+
mstore(0x20, mload(add(zPtr, mul(i, 0x20))))
|
|
166
|
+
}
|
|
167
|
+
default {
|
|
168
|
+
mstore(0x00, mload(add(branch, mul(i, 0x20))))
|
|
169
|
+
mstore(0x20, current)
|
|
170
|
+
}
|
|
171
|
+
current := keccak256(0x00, 0x40)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/// @notice Convert a peer chain snapshot value to the requested currency and decimal precision.
|
|
178
|
+
/// @param prices The price oracle to use when currency conversion is needed.
|
|
179
|
+
/// @param projectId The project ID.
|
|
180
|
+
/// @param source The peer chain snapshot containing value, currency, and decimals.
|
|
181
|
+
/// @param decimals The target decimal precision.
|
|
182
|
+
/// @param currency The target currency.
|
|
183
|
+
/// @return converted The converted value.
|
|
184
|
+
function convertPeerValue(
|
|
185
|
+
IJBPrices prices,
|
|
186
|
+
uint256 projectId,
|
|
187
|
+
JBDenominatedAmount memory source,
|
|
188
|
+
uint256 decimals,
|
|
189
|
+
uint256 currency
|
|
190
|
+
)
|
|
191
|
+
external
|
|
192
|
+
view
|
|
193
|
+
returns (uint256 converted)
|
|
194
|
+
{
|
|
195
|
+
// Nothing to convert if the source value is zero.
|
|
196
|
+
if (source.value == 0) return 0;
|
|
197
|
+
|
|
198
|
+
// If the source currency matches the target, just adjust decimals.
|
|
199
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
200
|
+
if (source.currency == uint32(currency)) {
|
|
201
|
+
converted = JBFixedPointNumber.adjustDecimals({
|
|
202
|
+
value: source.value, decimals: source.decimals, targetDecimals: decimals
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
// Convert using the price oracle.
|
|
206
|
+
try prices.pricePerUnitOf({
|
|
207
|
+
projectId: projectId,
|
|
208
|
+
pricingCurrency: source.currency,
|
|
209
|
+
// forge-lint: disable-next-line(unsafe-typecast)
|
|
210
|
+
unitCurrency: uint32(currency),
|
|
211
|
+
decimals: source.decimals
|
|
212
|
+
}) returns (
|
|
213
|
+
uint256 price
|
|
214
|
+
) {
|
|
215
|
+
converted = mulDiv({x: source.value, y: 10 ** decimals, denominator: price});
|
|
216
|
+
} catch {}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
64
220
|
//*********************************************************************//
|
|
65
|
-
//
|
|
221
|
+
// ------------------------- internal views -------------------------- //
|
|
66
222
|
//*********************************************************************//
|
|
67
223
|
|
|
68
224
|
/// @dev Shared implementation for ETH aggregate. Internal so it can be called from other
|
|
@@ -151,49 +307,6 @@ library JBSuckerLib {
|
|
|
151
307
|
}
|
|
152
308
|
}
|
|
153
309
|
|
|
154
|
-
/// @notice Convert a peer chain snapshot value to the requested currency and decimal precision.
|
|
155
|
-
/// @param prices The price oracle to use when currency conversion is needed.
|
|
156
|
-
/// @param projectId The project ID.
|
|
157
|
-
/// @param source The peer chain snapshot containing value, currency, and decimals.
|
|
158
|
-
/// @param decimals The target decimal precision.
|
|
159
|
-
/// @param currency The target currency.
|
|
160
|
-
/// @return converted The converted value.
|
|
161
|
-
function convertPeerValue(
|
|
162
|
-
IJBPrices prices,
|
|
163
|
-
uint256 projectId,
|
|
164
|
-
JBDenominatedAmount memory source,
|
|
165
|
-
uint256 decimals,
|
|
166
|
-
uint256 currency
|
|
167
|
-
)
|
|
168
|
-
external
|
|
169
|
-
view
|
|
170
|
-
returns (uint256 converted)
|
|
171
|
-
{
|
|
172
|
-
// Nothing to convert if the source value is zero.
|
|
173
|
-
if (source.value == 0) return 0;
|
|
174
|
-
|
|
175
|
-
// If the source currency matches the target, just adjust decimals.
|
|
176
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
177
|
-
if (source.currency == uint32(currency)) {
|
|
178
|
-
converted = JBFixedPointNumber.adjustDecimals({
|
|
179
|
-
value: source.value, decimals: source.decimals, targetDecimals: decimals
|
|
180
|
-
});
|
|
181
|
-
} else {
|
|
182
|
-
// Convert using the price oracle.
|
|
183
|
-
try prices.pricePerUnitOf({
|
|
184
|
-
projectId: projectId,
|
|
185
|
-
pricingCurrency: source.currency,
|
|
186
|
-
// forge-lint: disable-next-line(unsafe-typecast)
|
|
187
|
-
unitCurrency: uint32(currency),
|
|
188
|
-
decimals: source.decimals
|
|
189
|
-
}) returns (
|
|
190
|
-
uint256 price
|
|
191
|
-
) {
|
|
192
|
-
converted = mulDiv({x: source.value, y: 10 ** decimals, denominator: price});
|
|
193
|
-
} catch {}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
310
|
/// @notice Return the project's controller if it exists and advertises the controller interface.
|
|
198
311
|
/// @param directory The JB directory to look up the controller.
|
|
199
312
|
/// @param projectId The project ID.
|
|
@@ -208,56 +321,6 @@ library JBSuckerLib {
|
|
|
208
321
|
} catch {}
|
|
209
322
|
}
|
|
210
323
|
|
|
211
|
-
//*********************************************************************//
|
|
212
|
-
// -------------------- external state-changing ---------------------- //
|
|
213
|
-
//*********************************************************************//
|
|
214
|
-
|
|
215
|
-
/// @notice Build the cross-chain snapshot message (total supply, surplus, balance).
|
|
216
|
-
/// @dev Extracted from `JBSucker._buildSnapshotAndSend` to reduce child contract bytecode.
|
|
217
|
-
/// Called via DELEGATECALL. Includes ETH aggregate computation inline (cannot call own external fns).
|
|
218
|
-
/// @param directory The JB directory to look up controllers and terminals.
|
|
219
|
-
/// @param prices The price oracle to use for non-ETH terminal-token balances.
|
|
220
|
-
/// @param projectId The project ID.
|
|
221
|
-
/// @param remoteToken The remote token bytes32 address.
|
|
222
|
-
/// @param amount The amount of terminal tokens to bridge.
|
|
223
|
-
/// @param nonce The outbox nonce for this send.
|
|
224
|
-
/// @param root The merkle root of the outbox tree.
|
|
225
|
-
/// @param messageVersion The message format version.
|
|
226
|
-
/// @param sourceTimestamp The monotonic source freshness key for this snapshot.
|
|
227
|
-
/// @return message The constructed JBMessageRoot.
|
|
228
|
-
function buildSnapshotMessage(
|
|
229
|
-
IJBDirectory directory,
|
|
230
|
-
IJBPrices prices,
|
|
231
|
-
uint256 projectId,
|
|
232
|
-
bytes32 remoteToken,
|
|
233
|
-
uint256 amount,
|
|
234
|
-
uint64 nonce,
|
|
235
|
-
bytes32 root,
|
|
236
|
-
uint8 messageVersion,
|
|
237
|
-
uint256 sourceTimestamp
|
|
238
|
-
)
|
|
239
|
-
external
|
|
240
|
-
view
|
|
241
|
-
returns (JBMessageRoot memory message)
|
|
242
|
-
{
|
|
243
|
-
(uint256 localTotalSupply, uint256 ethSurplus, uint256 ethBalance) =
|
|
244
|
-
_snapshotAccountsOf({directory: directory, prices: prices, projectId: projectId});
|
|
245
|
-
|
|
246
|
-
// Construct the cross-chain message with the snapshot data.
|
|
247
|
-
message = JBMessageRoot({
|
|
248
|
-
version: messageVersion,
|
|
249
|
-
token: remoteToken,
|
|
250
|
-
amount: amount,
|
|
251
|
-
remoteRoot: JBInboxTreeRoot({nonce: nonce, root: root}),
|
|
252
|
-
sourceTotalSupply: localTotalSupply,
|
|
253
|
-
sourceCurrency: JBCurrencyIds.ETH,
|
|
254
|
-
sourceDecimals: _ETH_DECIMALS,
|
|
255
|
-
sourceSurplus: ethSurplus,
|
|
256
|
-
sourceBalance: ethBalance,
|
|
257
|
-
sourceTimestamp: sourceTimestamp
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
324
|
/// @notice Optional project-specific adjusted accounts to add to peer-chain snapshots.
|
|
262
325
|
/// @dev Reads the current ruleset's data hook and asks it for extra supply/surplus. Non-supporting hooks,
|
|
263
326
|
/// broken hooks, and short return data are ignored so a project's baseline snapshot remains usable.
|
|
@@ -337,71 +400,4 @@ library JBSuckerLib {
|
|
|
337
400
|
ethBalance += additionalBalance;
|
|
338
401
|
}
|
|
339
402
|
}
|
|
340
|
-
|
|
341
|
-
//*********************************************************************//
|
|
342
|
-
// -------------------- merkle tree helpers -------------------------- //
|
|
343
|
-
//*********************************************************************//
|
|
344
|
-
|
|
345
|
-
/// @notice Compute the merkle tree root from branch and count. Loop-based replacement for the unrolled
|
|
346
|
-
/// MerkleLib.root() — saves ~3KB per sucker when called via DELEGATECALL instead of inlining.
|
|
347
|
-
/// @param branch The 32-element branch array (caller copies from storage to memory).
|
|
348
|
-
/// @param count The number of leaves inserted into the tree.
|
|
349
|
-
/// @return current The merkle root.
|
|
350
|
-
function computeTreeRoot(bytes32[32] memory branch, uint256 count) external pure returns (bytes32 current) {
|
|
351
|
-
// An empty tree has a well-known root.
|
|
352
|
-
if (count == 0) return MerkleLib.Z_32;
|
|
353
|
-
|
|
354
|
-
// solhint-disable-next-line no-inline-assembly
|
|
355
|
-
assembly ("memory-safe") {
|
|
356
|
-
// Build zero hashes on-the-fly: Z[0] = 0, Z[i+1] = keccak256(Z[i], Z[i]).
|
|
357
|
-
let zPtr := mload(0x40)
|
|
358
|
-
mstore(0x40, add(zPtr, 0x420)) // 33 slots × 32 bytes
|
|
359
|
-
mstore(zPtr, 0) // Z[0] = bytes32(0)
|
|
360
|
-
for { let j := 0 } lt(j, 32) { j := add(j, 1) } {
|
|
361
|
-
let prev := mload(add(zPtr, mul(j, 0x20)))
|
|
362
|
-
mstore(0x00, prev)
|
|
363
|
-
mstore(0x20, prev)
|
|
364
|
-
mstore(add(zPtr, mul(add(j, 1), 0x20)), keccak256(0x00, 0x40))
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Walk bits of `count` from LSB to MSB.
|
|
368
|
-
// First set bit → initialize current = keccak256(branch[i], Z[i]).
|
|
369
|
-
// Each subsequent level → merge branch[i] or Z[i] with current.
|
|
370
|
-
let started := 0
|
|
371
|
-
for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
|
|
372
|
-
switch started
|
|
373
|
-
case 0 {
|
|
374
|
-
if and(count, shl(i, 1)) {
|
|
375
|
-
mstore(0x00, mload(add(branch, mul(i, 0x20))))
|
|
376
|
-
mstore(0x20, mload(add(zPtr, mul(i, 0x20))))
|
|
377
|
-
current := keccak256(0x00, 0x40)
|
|
378
|
-
started := 1
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
default {
|
|
382
|
-
switch and(count, shl(i, 1))
|
|
383
|
-
case 0 {
|
|
384
|
-
mstore(0x00, current)
|
|
385
|
-
mstore(0x20, mload(add(zPtr, mul(i, 0x20))))
|
|
386
|
-
}
|
|
387
|
-
default {
|
|
388
|
-
mstore(0x00, mload(add(branch, mul(i, 0x20))))
|
|
389
|
-
mstore(0x20, current)
|
|
390
|
-
}
|
|
391
|
-
current := keccak256(0x00, 0x40)
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/// @notice Compute a branch root from a leaf, branch, and index. Wraps MerkleLib.branchRoot so its
|
|
398
|
-
/// ~170 lines of unrolled assembly live in the library's bytecode instead of each sucker's.
|
|
399
|
-
/// @param item The leaf hash.
|
|
400
|
-
/// @param branch The 32-element merkle proof branch.
|
|
401
|
-
/// @param index The leaf index.
|
|
402
|
-
/// @return The computed merkle root.
|
|
403
|
-
function computeBranchRoot(bytes32 item, bytes32[32] memory branch, uint256 index) external pure returns (bytes32) {
|
|
404
|
-
// Delegate to MerkleLib's unrolled assembly implementation.
|
|
405
|
-
return MerkleLib.branchRoot({_item: item, _branch: branch, _index: index});
|
|
406
|
-
}
|
|
407
403
|
}
|