@bananapus/suckers-v6 0.0.68 → 0.0.69
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 +1 -1
- package/script/Deploy.s.sol +3 -11
- package/src/JBArbitrumSucker.sol +1 -4
- package/src/JBBaseSucker.sol +1 -4
- package/src/JBCCIPSucker.sol +1 -4
- package/src/JBOptimismSucker.sol +1 -4
- package/src/JBSucker.sol +141 -119
- package/src/JBSuckerRegistry.sol +224 -59
- package/src/archive/JBCeloSucker.sol +1 -4
- package/src/archive/JBSwapCCIPSucker.sol +1 -4
- package/src/interfaces/IJBPeerChainAdjustedAccounts.sol +10 -12
- package/src/interfaces/IJBSucker.sol +12 -32
- package/src/interfaces/IJBSuckerRegistry.sol +26 -24
- package/src/libraries/JBSuckerLib.sol +151 -172
- package/src/structs/JBMessageRoot.sol +9 -12
- package/src/structs/JBPeerChainContext.sol +19 -0
- package/src/structs/JBSourceContext.sol +25 -0
- package/src/structs/JBDenominatedAmount.sol +0 -12
package/src/JBSuckerRegistry.sol
CHANGED
|
@@ -4,13 +4,17 @@ pragma solidity 0.8.28;
|
|
|
4
4
|
import {JBPermissioned} from "@bananapus/core-v6/src/abstract/JBPermissioned.sol";
|
|
5
5
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
6
6
|
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
7
|
+
import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
|
|
7
8
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
9
|
+
import {JBFixedPointNumber} from "@bananapus/core-v6/src/libraries/JBFixedPointNumber.sol";
|
|
8
10
|
import {JBPermissionIds} from "@bananapus/permission-ids-v6/src/JBPermissionIds.sol";
|
|
9
11
|
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
10
12
|
import {ERC2771Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
|
|
11
13
|
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
|
|
12
14
|
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
|
|
15
|
+
import {mulDiv} from "@prb/math/src/Common.sol";
|
|
13
16
|
|
|
17
|
+
import {JBPeerChainContext} from "./structs/JBPeerChainContext.sol";
|
|
14
18
|
import {JBPeerChainValue} from "./structs/JBPeerChainValue.sol";
|
|
15
19
|
import {JBSuckerState} from "./enums/JBSuckerState.sol";
|
|
16
20
|
import {IJBSucker} from "./interfaces/IJBSucker.sol";
|
|
@@ -48,6 +52,10 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
48
52
|
// ------------------------- internal constants ----------------------- //
|
|
49
53
|
//*********************************************************************//
|
|
50
54
|
|
|
55
|
+
/// @notice The fixed-point fidelity used when valuing remote contexts across currencies, matching the terminal
|
|
56
|
+
/// store's `_MAX_FIXED_POINT_FIDELITY`.
|
|
57
|
+
uint256 internal constant _PRICE_FIDELITY = 18;
|
|
58
|
+
|
|
51
59
|
/// @notice A constant indicating that this sucker exists and belongs to a specific project.
|
|
52
60
|
uint256 internal constant _SUCKER_EXISTS = 1;
|
|
53
61
|
|
|
@@ -62,6 +70,10 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
62
70
|
/// @notice The Juicebox directory used to look up project terminals and controllers.
|
|
63
71
|
IJBDirectory public immutable override DIRECTORY;
|
|
64
72
|
|
|
73
|
+
/// @notice The prices contract used to value remote per-context surplus and balance into a requested currency,
|
|
74
|
+
/// exactly as the terminal store values local surplus.
|
|
75
|
+
IJBPrices public immutable PRICES;
|
|
76
|
+
|
|
65
77
|
/// @notice A contract which mints ERC-721s that represent project ownership and transfers.
|
|
66
78
|
IJBProjects public immutable override PROJECTS;
|
|
67
79
|
|
|
@@ -89,10 +101,12 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
89
101
|
|
|
90
102
|
/// @param directory The juicebox directory.
|
|
91
103
|
/// @param permissions A contract storing permissions.
|
|
104
|
+
/// @param prices The prices contract used to value remote per-context surplus/balance into a requested currency.
|
|
92
105
|
/// @param initialOwner The initial owner of this contract.
|
|
93
106
|
constructor(
|
|
94
107
|
IJBDirectory directory,
|
|
95
108
|
IJBPermissions permissions,
|
|
109
|
+
IJBPrices prices,
|
|
96
110
|
address initialOwner,
|
|
97
111
|
address trustedForwarder
|
|
98
112
|
)
|
|
@@ -101,6 +115,7 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
101
115
|
Ownable(initialOwner)
|
|
102
116
|
{
|
|
103
117
|
DIRECTORY = directory;
|
|
118
|
+
PRICES = prices;
|
|
104
119
|
PROJECTS = directory.PROJECTS();
|
|
105
120
|
toRemoteFee = MAX_TO_REMOTE_FEE;
|
|
106
121
|
}
|
|
@@ -131,6 +146,145 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
131
146
|
return exists && (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED);
|
|
132
147
|
}
|
|
133
148
|
|
|
149
|
+
/// @notice Values one sucker's raw peer-chain balance into a currency, bundled with the peer chain ID and
|
|
150
|
+
/// freshness.
|
|
151
|
+
/// @dev Exposed as an external self-call boundary so `totalRemoteBalanceOf` can `try` it and drop a single sucker
|
|
152
|
+
/// whose price feed is missing. A context whose currency already matches `currency` folds in at par (no feed read);
|
|
153
|
+
/// a missing cross-currency feed reverts, and the aggregator catches it and skips just this sucker.
|
|
154
|
+
/// @param sucker The sucker to read.
|
|
155
|
+
/// @param projectId The project whose price feeds to use.
|
|
156
|
+
/// @param currency The currency to value into.
|
|
157
|
+
/// @param decimals The decimal precision for the returned value.
|
|
158
|
+
/// @return A `JBPeerChainValue` with the valued balance, the sucker's peer chain ID, and its snapshot freshness
|
|
159
|
+
/// key.
|
|
160
|
+
function remoteBalanceOf(
|
|
161
|
+
address sucker,
|
|
162
|
+
uint256 projectId,
|
|
163
|
+
uint256 currency,
|
|
164
|
+
uint256 decimals
|
|
165
|
+
)
|
|
166
|
+
external
|
|
167
|
+
view
|
|
168
|
+
returns (JBPeerChainValue memory)
|
|
169
|
+
{
|
|
170
|
+
// Read this sucker's raw snapshot: one context per distinct local currency the peer reported, plus the peer
|
|
171
|
+
// chain ID and the snapshot's freshness key.
|
|
172
|
+
(JBPeerChainContext[] memory contexts, uint256 chainId, uint256 snapshot) =
|
|
173
|
+
IJBSucker(sucker).peerChainContextsOf();
|
|
174
|
+
|
|
175
|
+
// Value each context's balance out of the currency and decimals it was recorded in, into the requested
|
|
176
|
+
// `currency` and `decimals`, and sum across every context. A context already denominated in `currency` folds
|
|
177
|
+
// in at par; a cross-currency context is converted through the project's price feed.
|
|
178
|
+
uint256 value;
|
|
179
|
+
uint256 numContexts = contexts.length;
|
|
180
|
+
for (uint256 i; i < numContexts;) {
|
|
181
|
+
value += _valued({
|
|
182
|
+
amount: contexts[i].balance,
|
|
183
|
+
fromCurrency: contexts[i].currency,
|
|
184
|
+
fromDecimals: contexts[i].decimals,
|
|
185
|
+
toCurrency: currency,
|
|
186
|
+
toDecimals: decimals,
|
|
187
|
+
projectId: projectId
|
|
188
|
+
});
|
|
189
|
+
unchecked {
|
|
190
|
+
++i;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Carry the peer chain ID and snapshot freshness alongside the summed value so the aggregator can deduplicate
|
|
195
|
+
// peers and keep only the freshest snapshot per chain.
|
|
196
|
+
return JBPeerChainValue({value: value, peerChainId: chainId, snapshotTimestamp: snapshot});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/// @notice Values one sucker's raw peer-chain surplus into a currency, bundled with the peer chain ID and
|
|
200
|
+
/// freshness.
|
|
201
|
+
/// @dev Exposed as an external self-call boundary so `totalRemoteSurplusOf` can `try` it and drop a single sucker
|
|
202
|
+
/// whose price feed is missing. A context whose currency already matches `currency` folds in at par (no feed read);
|
|
203
|
+
/// a missing cross-currency feed reverts, and the aggregator catches it and skips just this sucker.
|
|
204
|
+
/// @param sucker The sucker to read.
|
|
205
|
+
/// @param projectId The project whose price feeds to use.
|
|
206
|
+
/// @param currency The currency to value into.
|
|
207
|
+
/// @param decimals The decimal precision for the returned value.
|
|
208
|
+
/// @return A `JBPeerChainValue` with the valued surplus, the sucker's peer chain ID, and its snapshot freshness
|
|
209
|
+
/// key.
|
|
210
|
+
function remoteSurplusOf(
|
|
211
|
+
address sucker,
|
|
212
|
+
uint256 projectId,
|
|
213
|
+
uint256 currency,
|
|
214
|
+
uint256 decimals
|
|
215
|
+
)
|
|
216
|
+
external
|
|
217
|
+
view
|
|
218
|
+
returns (JBPeerChainValue memory)
|
|
219
|
+
{
|
|
220
|
+
// Read this sucker's raw snapshot: one context per distinct local currency the peer reported, plus the peer
|
|
221
|
+
// chain ID and the snapshot's freshness key.
|
|
222
|
+
(JBPeerChainContext[] memory contexts, uint256 chainId, uint256 snapshot) =
|
|
223
|
+
IJBSucker(sucker).peerChainContextsOf();
|
|
224
|
+
|
|
225
|
+
// Value each context's surplus out of the currency and decimals it was recorded in, into the requested
|
|
226
|
+
// `currency` and `decimals`, and sum across every context. A context already denominated in `currency` folds
|
|
227
|
+
// in at par; a cross-currency context is converted through the project's price feed.
|
|
228
|
+
uint256 value;
|
|
229
|
+
uint256 numContexts = contexts.length;
|
|
230
|
+
for (uint256 i; i < numContexts;) {
|
|
231
|
+
value += _valued({
|
|
232
|
+
amount: contexts[i].surplus,
|
|
233
|
+
fromCurrency: contexts[i].currency,
|
|
234
|
+
fromDecimals: contexts[i].decimals,
|
|
235
|
+
toCurrency: currency,
|
|
236
|
+
toDecimals: decimals,
|
|
237
|
+
projectId: projectId
|
|
238
|
+
});
|
|
239
|
+
unchecked {
|
|
240
|
+
++i;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Carry the peer chain ID and snapshot freshness alongside the summed value so the aggregator can deduplicate
|
|
245
|
+
// peers and keep only the freshest snapshot per chain.
|
|
246
|
+
return JBPeerChainValue({value: value, peerChainId: chainId, snapshotTimestamp: snapshot});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// @notice The cumulative total supply across all remote peer chains for a project.
|
|
250
|
+
/// @dev Includes deprecated suckers only when no active sucker answers for the same peer chain, to prevent
|
|
251
|
+
/// undercounting during migration windows without letting stale deprecated snapshots dominate live routes.
|
|
252
|
+
/// Silently skips suckers that revert.
|
|
253
|
+
/// @param projectId The ID of the project.
|
|
254
|
+
/// @return totalSupply The combined peer chain total supply.
|
|
255
|
+
function remoteTotalSupplyOf(uint256 projectId) external view override returns (uint256 totalSupply) {
|
|
256
|
+
address[] memory allSuckers = _suckersOf[projectId].keys();
|
|
257
|
+
uint256 len = allSuckers.length;
|
|
258
|
+
|
|
259
|
+
// Per-chain dedup arrays. The number of suckers per project is small (typically 1-5),
|
|
260
|
+
// so a linear scan is cheaper than a mapping.
|
|
261
|
+
PeerValueScratch memory scratch = _peerValueScratch(len);
|
|
262
|
+
|
|
263
|
+
for (uint256 i; i < len;) {
|
|
264
|
+
(, uint256 val) = _suckersOf[projectId].tryGet(allSuckers[i]);
|
|
265
|
+
// Include both active and deprecated suckers in aggregate economic views.
|
|
266
|
+
if (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED) {
|
|
267
|
+
// One call returns the value, peer chain ID, and snapshot freshness key together.
|
|
268
|
+
try IJBSucker(allSuckers[i]).peerChainTotalSupplyValue() returns (JBPeerChainValue memory read) {
|
|
269
|
+
scratch.chainCount = _recordPeerChainValue({
|
|
270
|
+
scratch: scratch, read: read, sucker: allSuckers[i], isActive: val == _SUCKER_EXISTS
|
|
271
|
+
});
|
|
272
|
+
} catch {}
|
|
273
|
+
}
|
|
274
|
+
unchecked {
|
|
275
|
+
++i;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Sum the per-chain selected values.
|
|
280
|
+
for (uint256 k; k < scratch.chainCount;) {
|
|
281
|
+
totalSupply += scratch.values[k];
|
|
282
|
+
unchecked {
|
|
283
|
+
++k;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
134
288
|
/// @notice All active (non-deprecated) suckers for a project, with their remote peer address and chain ID.
|
|
135
289
|
/// @param projectId The ID of the project to get the suckers of.
|
|
136
290
|
/// @return pairs The pairs of suckers and their metadata.
|
|
@@ -202,18 +356,20 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
202
356
|
}
|
|
203
357
|
}
|
|
204
358
|
|
|
205
|
-
/// @notice The cumulative balance across all remote peer chains for a project,
|
|
206
|
-
/// @dev
|
|
207
|
-
///
|
|
208
|
-
///
|
|
359
|
+
/// @notice The cumulative peer-chain balance across all remote peer chains for a project, valued into a currency.
|
|
360
|
+
/// @dev Dedups same-peer suckers by freshest snapshot, then sums each sucker's balance valued into `currency`.
|
|
361
|
+
/// Includes deprecated suckers only when no active sucker answers for the same peer chain, to prevent undercounting
|
|
362
|
+
/// during migration windows without letting stale deprecated snapshots dominate live routes. A context whose
|
|
363
|
+
/// currency already matches is taken at par (no feed); a missing cross-currency feed reverts and that sucker is
|
|
364
|
+
/// silently skipped (conservative, bias-low).
|
|
209
365
|
/// @param projectId The ID of the project.
|
|
366
|
+
/// @param currency The currency to value the combined balance into.
|
|
210
367
|
/// @param decimals The decimal precision for the returned value.
|
|
211
|
-
/// @param currency The currency to normalize to.
|
|
212
368
|
/// @return balance The combined peer chain balance.
|
|
213
|
-
function
|
|
369
|
+
function totalRemoteBalanceOf(
|
|
214
370
|
uint256 projectId,
|
|
215
|
-
uint256
|
|
216
|
-
uint256
|
|
371
|
+
uint256 currency,
|
|
372
|
+
uint256 decimals
|
|
217
373
|
)
|
|
218
374
|
external
|
|
219
375
|
view
|
|
@@ -231,8 +387,11 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
231
387
|
(, uint256 val) = _suckersOf[projectId].tryGet(allSuckers[i]);
|
|
232
388
|
// Include both active and deprecated suckers in aggregate economic views.
|
|
233
389
|
if (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED) {
|
|
234
|
-
//
|
|
235
|
-
|
|
390
|
+
// A registry self-call values the sucker's raw contexts so a missing feed reverts only this sucker
|
|
391
|
+
// (caught here), and returns the value, peer chain ID, and snapshot freshness key together.
|
|
392
|
+
try this.remoteBalanceOf({
|
|
393
|
+
sucker: allSuckers[i], projectId: projectId, currency: currency, decimals: decimals
|
|
394
|
+
}) returns (
|
|
236
395
|
JBPeerChainValue memory read
|
|
237
396
|
) {
|
|
238
397
|
scratch.chainCount = _recordPeerChainValue({
|
|
@@ -254,18 +413,20 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
254
413
|
}
|
|
255
414
|
}
|
|
256
415
|
|
|
257
|
-
/// @notice The cumulative surplus across all remote peer chains for a project,
|
|
258
|
-
/// @dev
|
|
259
|
-
///
|
|
260
|
-
///
|
|
416
|
+
/// @notice The cumulative peer-chain surplus across all remote peer chains for a project, valued into a currency.
|
|
417
|
+
/// @dev Dedups same-peer suckers by freshest snapshot, then sums each sucker's surplus valued into `currency`.
|
|
418
|
+
/// Includes deprecated suckers only when no active sucker answers for the same peer chain, to prevent undercounting
|
|
419
|
+
/// during migration windows without letting stale deprecated snapshots dominate live routes. A context whose
|
|
420
|
+
/// currency already matches is taken at par (no feed); a missing cross-currency feed reverts and that sucker is
|
|
421
|
+
/// silently skipped (conservative, bias-low).
|
|
261
422
|
/// @param projectId The ID of the project.
|
|
423
|
+
/// @param currency The currency to value the combined surplus into.
|
|
262
424
|
/// @param decimals The decimal precision for the returned value.
|
|
263
|
-
/// @param currency The currency to normalize to.
|
|
264
425
|
/// @return surplus The combined peer chain surplus.
|
|
265
|
-
function
|
|
426
|
+
function totalRemoteSurplusOf(
|
|
266
427
|
uint256 projectId,
|
|
267
|
-
uint256
|
|
268
|
-
uint256
|
|
428
|
+
uint256 currency,
|
|
429
|
+
uint256 decimals
|
|
269
430
|
)
|
|
270
431
|
external
|
|
271
432
|
view
|
|
@@ -283,8 +444,11 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
283
444
|
(, uint256 val) = _suckersOf[projectId].tryGet(allSuckers[i]);
|
|
284
445
|
// Include both active and deprecated suckers in aggregate economic views.
|
|
285
446
|
if (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED) {
|
|
286
|
-
//
|
|
287
|
-
|
|
447
|
+
// A registry self-call values the sucker's raw contexts so a missing feed reverts only this sucker
|
|
448
|
+
// (caught here), and returns the value, peer chain ID, and snapshot freshness key together.
|
|
449
|
+
try this.remoteSurplusOf({
|
|
450
|
+
sucker: allSuckers[i], projectId: projectId, currency: currency, decimals: decimals
|
|
451
|
+
}) returns (
|
|
288
452
|
JBPeerChainValue memory read
|
|
289
453
|
) {
|
|
290
454
|
scratch.chainCount = _recordPeerChainValue({
|
|
@@ -306,45 +470,6 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
306
470
|
}
|
|
307
471
|
}
|
|
308
472
|
|
|
309
|
-
/// @notice The cumulative total supply across all remote peer chains for a project.
|
|
310
|
-
/// @dev Includes deprecated suckers only when no active sucker answers for the same peer chain, to prevent
|
|
311
|
-
/// undercounting during migration windows without letting stale deprecated snapshots dominate live routes.
|
|
312
|
-
/// Silently skips suckers that revert.
|
|
313
|
-
/// @param projectId The ID of the project.
|
|
314
|
-
/// @return totalSupply The combined peer chain total supply.
|
|
315
|
-
function remoteTotalSupplyOf(uint256 projectId) external view override returns (uint256 totalSupply) {
|
|
316
|
-
address[] memory allSuckers = _suckersOf[projectId].keys();
|
|
317
|
-
uint256 len = allSuckers.length;
|
|
318
|
-
|
|
319
|
-
// Per-chain dedup arrays. The number of suckers per project is small (typically 1-5),
|
|
320
|
-
// so a linear scan is cheaper than a mapping.
|
|
321
|
-
PeerValueScratch memory scratch = _peerValueScratch(len);
|
|
322
|
-
|
|
323
|
-
for (uint256 i; i < len;) {
|
|
324
|
-
(, uint256 val) = _suckersOf[projectId].tryGet(allSuckers[i]);
|
|
325
|
-
// Include both active and deprecated suckers in aggregate economic views.
|
|
326
|
-
if (val == _SUCKER_EXISTS || val == _SUCKER_DEPRECATED) {
|
|
327
|
-
// One call returns the value, peer chain ID, and snapshot freshness key together.
|
|
328
|
-
try IJBSucker(allSuckers[i]).peerChainTotalSupplyValue() returns (JBPeerChainValue memory read) {
|
|
329
|
-
scratch.chainCount = _recordPeerChainValue({
|
|
330
|
-
scratch: scratch, read: read, sucker: allSuckers[i], isActive: val == _SUCKER_EXISTS
|
|
331
|
-
});
|
|
332
|
-
} catch {}
|
|
333
|
-
}
|
|
334
|
-
unchecked {
|
|
335
|
-
++i;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Sum the per-chain selected values.
|
|
340
|
-
for (uint256 k; k < scratch.chainCount;) {
|
|
341
|
-
totalSupply += scratch.values[k];
|
|
342
|
-
unchecked {
|
|
343
|
-
++k;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
473
|
//*********************************************************************//
|
|
349
474
|
// ------------------------ internal views --------------------------- //
|
|
350
475
|
//*********************************************************************//
|
|
@@ -477,6 +602,46 @@ contract JBSuckerRegistry is ERC2771Context, Ownable, JBPermissioned, IJBSuckerR
|
|
|
477
602
|
});
|
|
478
603
|
}
|
|
479
604
|
|
|
605
|
+
/// @notice Values an amount held in one currency/decimals into another, mirroring the terminal store.
|
|
606
|
+
/// @dev Adjusts decimals, then converts currency via the prices contract. Both steps short-circuit on identity, and
|
|
607
|
+
/// the currency step also short-circuits on a zero amount, so a same-currency context consults no feed. A missing
|
|
608
|
+
/// feed reverts (fail-closed), and the caller catches it to drop just the affected sucker.
|
|
609
|
+
/// @param amount The raw amount in `fromCurrency`/`fromDecimals`.
|
|
610
|
+
/// @param fromCurrency The currency the amount is held in.
|
|
611
|
+
/// @param fromDecimals The decimals the amount is held in.
|
|
612
|
+
/// @param toCurrency The currency to value into.
|
|
613
|
+
/// @param toDecimals The decimals to value into.
|
|
614
|
+
/// @param projectId The project whose price feeds to use.
|
|
615
|
+
/// @return The amount valued into `toCurrency`/`toDecimals`.
|
|
616
|
+
function _valued(
|
|
617
|
+
uint256 amount,
|
|
618
|
+
uint256 fromCurrency,
|
|
619
|
+
uint256 fromDecimals,
|
|
620
|
+
uint256 toCurrency,
|
|
621
|
+
uint256 toDecimals,
|
|
622
|
+
uint256 projectId
|
|
623
|
+
)
|
|
624
|
+
internal
|
|
625
|
+
view
|
|
626
|
+
returns (uint256)
|
|
627
|
+
{
|
|
628
|
+
// Step 1: adjust decimals.
|
|
629
|
+
uint256 value = fromDecimals == toDecimals
|
|
630
|
+
? amount
|
|
631
|
+
: JBFixedPointNumber.adjustDecimals({value: amount, decimals: fromDecimals, targetDecimals: toDecimals});
|
|
632
|
+
|
|
633
|
+
// Step 2: convert currency. The price is the denominator: pricePerUnitOf returns the `fromCurrency` price of
|
|
634
|
+
// one `toCurrency`, so dividing the amount by it yields the amount in `toCurrency`.
|
|
635
|
+
if (value == 0 || fromCurrency == toCurrency) return value;
|
|
636
|
+
return mulDiv({
|
|
637
|
+
x: value,
|
|
638
|
+
y: 10 ** _PRICE_FIDELITY,
|
|
639
|
+
denominator: PRICES.pricePerUnitOf({
|
|
640
|
+
projectId: projectId, pricingCurrency: fromCurrency, unitCurrency: toCurrency, decimals: _PRICE_FIDELITY
|
|
641
|
+
})
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
480
645
|
//*********************************************************************//
|
|
481
646
|
// ---------------------- public transactions ----------------------- //
|
|
482
647
|
//*********************************************************************//
|
|
@@ -3,7 +3,6 @@ pragma solidity 0.8.28;
|
|
|
3
3
|
|
|
4
4
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
5
5
|
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
6
|
-
import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
|
|
7
6
|
import {IJBTerminal} from "@bananapus/core-v6/src/interfaces/IJBTerminal.sol";
|
|
8
7
|
import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
|
|
9
8
|
import {JBConstants} from "@bananapus/core-v6/src/libraries/JBConstants.sol";
|
|
@@ -38,19 +37,17 @@ contract JBCeloSucker is JBOptimismSucker {
|
|
|
38
37
|
/// @param deployer A contract that deploys clones of this contract.
|
|
39
38
|
/// @param directory A contract storing directories of terminals and controllers for each project.
|
|
40
39
|
/// @param permissions A contract storing permissions.
|
|
41
|
-
/// @param prices The price oracle used to convert peer-chain balances and surplus.
|
|
42
40
|
/// @param tokens A contract that manages token minting and burning.
|
|
43
41
|
constructor(
|
|
44
42
|
JBCeloSuckerDeployer deployer,
|
|
45
43
|
IJBDirectory directory,
|
|
46
44
|
IJBPermissions permissions,
|
|
47
|
-
IJBPrices prices,
|
|
48
45
|
IJBTokens tokens,
|
|
49
46
|
uint256 feeProjectId,
|
|
50
47
|
IJBSuckerRegistry registry,
|
|
51
48
|
address trustedForwarder
|
|
52
49
|
)
|
|
53
|
-
JBOptimismSucker(deployer, directory, permissions,
|
|
50
|
+
JBOptimismSucker(deployer, directory, permissions, tokens, feeProjectId, registry, trustedForwarder)
|
|
54
51
|
{
|
|
55
52
|
// Fetch the wrapped native token by doing a callback to the deployer contract.
|
|
56
53
|
WRAPPED_NATIVE_TOKEN = JBCeloSuckerDeployer(deployer).wrappedNative();
|
|
@@ -4,7 +4,6 @@ pragma solidity 0.8.28;
|
|
|
4
4
|
// Core JB imports.
|
|
5
5
|
import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
6
6
|
import {IJBPermissions} from "@bananapus/core-v6/src/interfaces/IJBPermissions.sol";
|
|
7
|
-
import {IJBPrices} from "@bananapus/core-v6/src/interfaces/IJBPrices.sol";
|
|
8
7
|
import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
|
|
9
8
|
// CCIP imports.
|
|
10
9
|
import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol";
|
|
@@ -204,7 +203,6 @@ contract JBSwapCCIPSucker is JBCCIPSucker, IUnlockCallback, IUniswapV3SwapCallba
|
|
|
204
203
|
/// @param deployer The deployer that stores chain-specific configuration.
|
|
205
204
|
/// @param directory The directory of terminals and controllers for projects.
|
|
206
205
|
/// @param permissions The permissions contract.
|
|
207
|
-
/// @param prices The price oracle used to convert peer-chain balances and surplus.
|
|
208
206
|
/// @param tokens The contract that manages token minting and burning.
|
|
209
207
|
/// @param feeProjectId The project ID that receives bridge fees.
|
|
210
208
|
/// @param registry The sucker registry.
|
|
@@ -213,13 +211,12 @@ contract JBSwapCCIPSucker is JBCCIPSucker, IUnlockCallback, IUniswapV3SwapCallba
|
|
|
213
211
|
JBSwapCCIPSuckerDeployer deployer,
|
|
214
212
|
IJBDirectory directory,
|
|
215
213
|
IJBPermissions permissions,
|
|
216
|
-
IJBPrices prices,
|
|
217
214
|
IJBTokens tokens,
|
|
218
215
|
uint256 feeProjectId,
|
|
219
216
|
IJBSuckerRegistry registry,
|
|
220
217
|
address trustedForwarder
|
|
221
218
|
)
|
|
222
|
-
JBCCIPSucker(deployer, directory, permissions,
|
|
219
|
+
JBCCIPSucker(deployer, directory, permissions, tokens, feeProjectId, registry, trustedForwarder)
|
|
223
220
|
{
|
|
224
221
|
IJBSwapCCIPSuckerDeployer swapDeployer = IJBSwapCCIPSuckerDeployer(address(deployer));
|
|
225
222
|
BRIDGE_TOKEN = swapDeployer.bridgeToken();
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
2
|
pragma solidity ^0.8.0;
|
|
3
3
|
|
|
4
|
+
import {JBSourceContext} from "../structs/JBSourceContext.sol";
|
|
5
|
+
|
|
4
6
|
/// @notice Optional data-hook interface for adding project-specific adjusted accounts to peer-chain snapshots.
|
|
5
7
|
interface IJBPeerChainAdjustedAccounts {
|
|
6
|
-
/// @notice Extra supply
|
|
8
|
+
/// @notice Extra project token supply and per-context surplus/balance to include in cross-chain peer snapshots.
|
|
9
|
+
/// @dev The hook reports off-terminal surplus and balance per accounting context in each context's own currency,
|
|
10
|
+
/// un-valued — exactly like the terminal contexts. The receiving chain folds each one into its same-asset local
|
|
11
|
+
/// context at par, so no price oracle is consulted for the hook's contribution either.
|
|
7
12
|
/// @param projectId The ID of the project to snapshot.
|
|
8
|
-
/// @
|
|
9
|
-
/// @
|
|
10
|
-
|
|
11
|
-
/// @return surplus The extra surplus to include in `sourceSurplus`.
|
|
12
|
-
/// @return balance The extra balance to include in `sourceBalance`.
|
|
13
|
-
function peerChainAdjustedAccountsOf(
|
|
14
|
-
uint256 projectId,
|
|
15
|
-
uint256 decimals,
|
|
16
|
-
uint256 currency
|
|
17
|
-
)
|
|
13
|
+
/// @return supply The extra project token supply to include in `sourceTotalSupply`.
|
|
14
|
+
/// @return contexts The extra per-context surplus and balance to include in the snapshot, un-valued.
|
|
15
|
+
function peerChainAdjustedAccountsOf(uint256 projectId)
|
|
18
16
|
external
|
|
19
17
|
view
|
|
20
|
-
returns (uint256 supply,
|
|
18
|
+
returns (uint256 supply, JBSourceContext[] memory contexts);
|
|
21
19
|
}
|
|
@@ -6,9 +6,9 @@ import {IJBDirectory} from "@bananapus/core-v6/src/interfaces/IJBDirectory.sol";
|
|
|
6
6
|
import {IJBProjects} from "@bananapus/core-v6/src/interfaces/IJBProjects.sol";
|
|
7
7
|
import {IJBTokens} from "@bananapus/core-v6/src/interfaces/IJBTokens.sol";
|
|
8
8
|
import {JBClaim} from "../structs/JBClaim.sol";
|
|
9
|
-
import {JBDenominatedAmount} from "../structs/JBDenominatedAmount.sol";
|
|
10
9
|
import {JBInboxTreeRoot} from "../structs/JBInboxTreeRoot.sol";
|
|
11
10
|
import {JBOutboxTree} from "../structs/JBOutboxTree.sol";
|
|
11
|
+
import {JBPeerChainContext} from "../structs/JBPeerChainContext.sol";
|
|
12
12
|
import {JBPeerChainValue} from "../structs/JBPeerChainValue.sol";
|
|
13
13
|
import {JBRemoteToken} from "../structs/JBRemoteToken.sol";
|
|
14
14
|
import {JBSuckerState} from "../enums/JBSuckerState.sol";
|
|
@@ -153,37 +153,17 @@ interface IJBSucker is IERC165 {
|
|
|
153
153
|
/// @return chainId The remote chain ID.
|
|
154
154
|
function peerChainId() external view returns (uint256 chainId);
|
|
155
155
|
|
|
156
|
-
/// @notice The
|
|
157
|
-
///
|
|
158
|
-
///
|
|
159
|
-
///
|
|
160
|
-
/// @
|
|
161
|
-
/// @return
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/// @param decimals The decimal precision for the returned value.
|
|
168
|
-
/// @param currency The currency to normalize to.
|
|
169
|
-
/// @return A `JBPeerChainValue` with the converted balance, peer chain ID, and snapshot freshness key.
|
|
170
|
-
function peerChainBalanceValueOf(uint256 decimals, uint256 currency) external view returns (JBPeerChainValue memory);
|
|
171
|
-
|
|
172
|
-
/// @notice The aggregate peer chain surplus, normalized to a desired currency and decimal precision using JBPrices.
|
|
173
|
-
/// @dev The surplus is stored as ETH-denominated (18 decimals) and converted to the requested currency/decimals
|
|
174
|
-
/// using the local JBPrices oracle.
|
|
175
|
-
/// @param decimals The decimal precision for the returned value.
|
|
176
|
-
/// @param currency The currency to normalize to.
|
|
177
|
-
/// @return A `JBDenominatedAmount` with the converted value.
|
|
178
|
-
function peerChainSurplusOf(uint256 decimals, uint256 currency) external view returns (JBDenominatedAmount memory);
|
|
179
|
-
|
|
180
|
-
/// @notice The peer chain surplus bundled with the peer chain ID and snapshot freshness key.
|
|
181
|
-
/// @dev Lets aggregators read the value, the peer chain it belongs to, and its freshness in one call. The
|
|
182
|
-
/// `value` matches `peerChainSurplusOf`.
|
|
183
|
-
/// @param decimals The decimal precision for the returned value.
|
|
184
|
-
/// @param currency The currency to normalize to.
|
|
185
|
-
/// @return A `JBPeerChainValue` with the converted surplus, peer chain ID, and snapshot freshness key.
|
|
186
|
-
function peerChainSurplusValueOf(uint256 decimals, uint256 currency) external view returns (JBPeerChainValue memory);
|
|
156
|
+
/// @notice The peer chain's raw per-context surplus and balance from the latest snapshot, bundled with the peer
|
|
157
|
+
/// chain ID and snapshot freshness key.
|
|
158
|
+
/// @dev Un-valued — each context is in its own currency and decimals. The registry dedups same-peer suckers by
|
|
159
|
+
/// freshness, then values each context into a requested currency. The sucker consults no price oracle.
|
|
160
|
+
/// @return contexts The per-currency surplus and balance from the latest snapshot.
|
|
161
|
+
/// @return chainId The peer chain these contexts belong to.
|
|
162
|
+
/// @return snapshot The source freshness key of the latest snapshot.
|
|
163
|
+
function peerChainContextsOf()
|
|
164
|
+
external
|
|
165
|
+
view
|
|
166
|
+
returns (JBPeerChainContext[] memory contexts, uint256 chainId, uint256 snapshot);
|
|
187
167
|
|
|
188
168
|
/// @notice The last known total token supply on the peer chain, updated each time a bridge message is received.
|
|
189
169
|
/// @dev Used by data hooks to compute `effectiveTotalSupply = localSupply + sum(peerChainTotalSupply)` across all
|
|
@@ -69,6 +69,13 @@ interface IJBSuckerRegistry {
|
|
|
69
69
|
/// @return Whether the sucker belongs to the project.
|
|
70
70
|
function isSuckerOf(uint256 projectId, address addr) external view returns (bool);
|
|
71
71
|
|
|
72
|
+
/// @notice The cumulative total supply across all remote peer chains for a project.
|
|
73
|
+
/// @dev Dedupes same-peer active suckers by freshest snapshot, then sums peer-chain values. Silently skips suckers
|
|
74
|
+
/// that revert.
|
|
75
|
+
/// @param projectId The ID of the project.
|
|
76
|
+
/// @return totalSupply The combined peer chain total supply.
|
|
77
|
+
function remoteTotalSupplyOf(uint256 projectId) external view returns (uint256 totalSupply);
|
|
78
|
+
|
|
72
79
|
/// @notice Whether the specified sucker deployer is approved by this registry.
|
|
73
80
|
/// @param deployer The address of the deployer to check.
|
|
74
81
|
/// @return Whether the deployer is allowed.
|
|
@@ -84,49 +91,44 @@ interface IJBSuckerRegistry {
|
|
|
84
91
|
/// @return The addresses of the suckers.
|
|
85
92
|
function suckersOf(uint256 projectId) external view returns (address[] memory);
|
|
86
93
|
|
|
87
|
-
/// @notice The
|
|
88
|
-
/// @
|
|
89
|
-
|
|
90
|
-
/// @param projectId The ID of the project.
|
|
91
|
-
/// @return totalSupply The combined peer chain total supply.
|
|
92
|
-
function remoteTotalSupplyOf(uint256 projectId) external view returns (uint256 totalSupply);
|
|
94
|
+
/// @notice The ETH fee (in wei) paid into the fee project on each toRemote() call.
|
|
95
|
+
/// @return The current fee.
|
|
96
|
+
function toRemoteFee() external view returns (uint256);
|
|
93
97
|
|
|
94
|
-
/// @notice The cumulative balance across all remote peer chains for a project,
|
|
95
|
-
/// @dev
|
|
96
|
-
///
|
|
98
|
+
/// @notice The cumulative peer-chain balance across all remote peer chains for a project, valued into a currency.
|
|
99
|
+
/// @dev Dedups same-peer active suckers by freshest snapshot, then sums each sucker's balance valued into
|
|
100
|
+
/// `currency`. A context whose currency already matches is taken at par (no feed); a missing cross-currency feed
|
|
101
|
+
/// reverts and that sucker is silently skipped (conservative, bias-low).
|
|
97
102
|
/// @param projectId The ID of the project.
|
|
103
|
+
/// @param currency The currency to value the combined balance into.
|
|
98
104
|
/// @param decimals The decimal precision for the returned value.
|
|
99
|
-
/// @param currency The currency to normalize to.
|
|
100
105
|
/// @return balance The combined peer chain balance.
|
|
101
|
-
function
|
|
106
|
+
function totalRemoteBalanceOf(
|
|
102
107
|
uint256 projectId,
|
|
103
|
-
uint256
|
|
104
|
-
uint256
|
|
108
|
+
uint256 currency,
|
|
109
|
+
uint256 decimals
|
|
105
110
|
)
|
|
106
111
|
external
|
|
107
112
|
view
|
|
108
113
|
returns (uint256 balance);
|
|
109
114
|
|
|
110
|
-
/// @notice The cumulative surplus across all remote peer chains for a project,
|
|
111
|
-
/// @dev
|
|
112
|
-
///
|
|
115
|
+
/// @notice The cumulative peer-chain surplus across all remote peer chains for a project, valued into a currency.
|
|
116
|
+
/// @dev Dedups same-peer active suckers by freshest snapshot, then sums each sucker's surplus valued into
|
|
117
|
+
/// `currency`. A context whose currency already matches is taken at par (no feed); a missing cross-currency feed
|
|
118
|
+
/// reverts and that sucker is silently skipped (conservative, bias-low).
|
|
113
119
|
/// @param projectId The ID of the project.
|
|
120
|
+
/// @param currency The currency to value the combined surplus into.
|
|
114
121
|
/// @param decimals The decimal precision for the returned value.
|
|
115
|
-
/// @param currency The currency to normalize to.
|
|
116
122
|
/// @return surplus The combined peer chain surplus.
|
|
117
|
-
function
|
|
123
|
+
function totalRemoteSurplusOf(
|
|
118
124
|
uint256 projectId,
|
|
119
|
-
uint256
|
|
120
|
-
uint256
|
|
125
|
+
uint256 currency,
|
|
126
|
+
uint256 decimals
|
|
121
127
|
)
|
|
122
128
|
external
|
|
123
129
|
view
|
|
124
130
|
returns (uint256 surplus);
|
|
125
131
|
|
|
126
|
-
/// @notice The ETH fee (in wei) paid into the fee project on each toRemote() call.
|
|
127
|
-
/// @return The current fee.
|
|
128
|
-
function toRemoteFee() external view returns (uint256);
|
|
129
|
-
|
|
130
132
|
// State-changing functions
|
|
131
133
|
|
|
132
134
|
/// @notice Add a sucker deployer to the allowlist.
|