@bananapus/nana-sdk-core 2.25.0 → 2.26.0

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.
@@ -1,13 +1,57 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.STICKY_MAX_CRITERIA_WEEKS = exports.STICKY_CRITERIA_BASE = exports.STICKY_DEFAULT_GROUP_ID = void 0;
36
+ exports.STICKY_SOURCE_COLLECTOR_DEPLOYMENTS = exports.stickySourceCollectorAbi = exports.STICKY_MAX_CRITERIA_WEEKS = exports.STICKY_CRITERIA_BASE = exports.STICKY_DEFAULT_GROUP_ID = void 0;
4
37
  exports.stickyDistributorAddress = stickyDistributorAddress;
5
38
  exports.isStickySplit = isStickySplit;
6
39
  exports.validateStickyGroupId = validateStickyGroupId;
7
40
  exports.stickyGroupId = stickyGroupId;
8
41
  exports.decodeStickyGroupId = decodeStickyGroupId;
9
42
  exports.describeStickySplit = describeStickySplit;
43
+ exports.stickySourceCollectorDeployment = stickySourceCollectorDeployment;
44
+ exports.stickySourceCollectorAt = stickySourceCollectorAt;
45
+ exports.buildStickyReservedSplit = buildStickyReservedSplit;
46
+ exports.getStickyCollectorPending = getStickyCollectorPending;
47
+ exports.buildStickyCollectorSendTx = buildStickyCollectorSendTx;
48
+ exports.buildStickyCollectorSettleTx = buildStickyCollectorSettleTx;
49
+ exports.verifyStickySourceCollector = verifyStickySourceCollector;
50
+ exports.verifyStickyCollectorRoute = verifyStickyCollectorRoute;
10
51
  const viem_1 = require("viem");
52
+ const juicebox_js_1 = require("../generated/juicebox.js");
53
+ const pureConstants_js_1 = require("../pureConstants.js");
54
+ const splits_js_1 = require("./splits.js");
11
55
  const types_js_1 = require("./types.js");
12
56
  /**
13
57
  * A split routes funds to Sticky holders when its `hook` is the chain's
@@ -129,4 +173,786 @@ function describeStickySplit(split) {
129
173
  }
130
174
  return `Sticky holders stuck ${group.minWeeks} to ${group.maxWeeks} weeks`;
131
175
  }
176
+ /** The collector's public delivery, accounting and immutable identity surface. */
177
+ exports.stickySourceCollectorAbi = [
178
+ {
179
+ name: "DESTINATION_CHAIN_ID",
180
+ type: "function",
181
+ stateMutability: "view",
182
+ inputs: [],
183
+ outputs: [
184
+ {
185
+ type: "uint256",
186
+ },
187
+ ],
188
+ },
189
+ {
190
+ name: "DIRECTORY",
191
+ type: "function",
192
+ stateMutability: "view",
193
+ inputs: [],
194
+ outputs: [
195
+ {
196
+ type: "address",
197
+ },
198
+ ],
199
+ },
200
+ {
201
+ name: "FEE_PAYER",
202
+ type: "function",
203
+ stateMutability: "view",
204
+ inputs: [],
205
+ outputs: [
206
+ {
207
+ type: "address",
208
+ },
209
+ ],
210
+ },
211
+ {
212
+ name: "RECEIVER_FACTORY",
213
+ type: "function",
214
+ stateMutability: "view",
215
+ inputs: [],
216
+ outputs: [
217
+ {
218
+ type: "address",
219
+ },
220
+ ],
221
+ },
222
+ {
223
+ name: "REGISTRY",
224
+ type: "function",
225
+ stateMutability: "view",
226
+ inputs: [],
227
+ outputs: [
228
+ {
229
+ type: "address",
230
+ },
231
+ ],
232
+ },
233
+ {
234
+ name: "TOKENS",
235
+ type: "function",
236
+ stateMutability: "view",
237
+ inputs: [],
238
+ outputs: [
239
+ {
240
+ type: "address",
241
+ },
242
+ ],
243
+ },
244
+ {
245
+ name: "pendingOf",
246
+ type: "function",
247
+ stateMutability: "view",
248
+ inputs: [
249
+ {
250
+ type: "uint256",
251
+ name: "sourceProjectId",
252
+ },
253
+ {
254
+ type: "address",
255
+ name: "stickyToken",
256
+ },
257
+ {
258
+ type: "uint256",
259
+ name: "groupId",
260
+ },
261
+ ],
262
+ outputs: [
263
+ {
264
+ type: "uint256",
265
+ },
266
+ ],
267
+ },
268
+ {
269
+ name: "totalPendingOf",
270
+ type: "function",
271
+ stateMutability: "view",
272
+ inputs: [
273
+ {
274
+ type: "uint256",
275
+ name: "sourceProjectId",
276
+ },
277
+ ],
278
+ outputs: [
279
+ {
280
+ type: "uint256",
281
+ },
282
+ ],
283
+ },
284
+ {
285
+ name: "send",
286
+ type: "function",
287
+ stateMutability: "payable",
288
+ inputs: [
289
+ {
290
+ type: "uint256",
291
+ name: "sourceProjectId",
292
+ },
293
+ {
294
+ type: "address",
295
+ name: "stickyToken",
296
+ },
297
+ {
298
+ type: "uint256",
299
+ name: "groupId",
300
+ },
301
+ {
302
+ type: "uint256",
303
+ name: "amount",
304
+ },
305
+ {
306
+ type: "address",
307
+ name: "sucker",
308
+ },
309
+ {
310
+ type: "address",
311
+ name: "backingToken",
312
+ },
313
+ ],
314
+ outputs: [
315
+ {
316
+ type: "uint256",
317
+ name: "leafIndex",
318
+ },
319
+ ],
320
+ },
321
+ {
322
+ name: "settle",
323
+ type: "function",
324
+ stateMutability: "nonpayable",
325
+ inputs: [
326
+ {
327
+ type: "uint256",
328
+ name: "sourceProjectId",
329
+ },
330
+ {
331
+ type: "address",
332
+ name: "stickyToken",
333
+ },
334
+ {
335
+ type: "uint256",
336
+ name: "groupId",
337
+ },
338
+ {
339
+ type: "uint256",
340
+ name: "amount",
341
+ },
342
+ ],
343
+ outputs: [
344
+ {
345
+ type: "uint256",
346
+ name: "settled",
347
+ },
348
+ ],
349
+ },
350
+ {
351
+ name: "Queue",
352
+ type: "event",
353
+ inputs: [
354
+ {
355
+ type: "uint256",
356
+ name: "sourceProjectId",
357
+ indexed: true,
358
+ },
359
+ {
360
+ type: "address",
361
+ name: "stickyToken",
362
+ indexed: true,
363
+ },
364
+ {
365
+ type: "uint256",
366
+ name: "groupId",
367
+ indexed: true,
368
+ },
369
+ {
370
+ type: "address",
371
+ name: "receiver",
372
+ },
373
+ {
374
+ type: "uint256",
375
+ name: "amount",
376
+ },
377
+ {
378
+ type: "address",
379
+ name: "caller",
380
+ },
381
+ ],
382
+ },
383
+ {
384
+ name: "Send",
385
+ type: "event",
386
+ inputs: [
387
+ {
388
+ type: "uint256",
389
+ name: "sourceProjectId",
390
+ indexed: true,
391
+ },
392
+ {
393
+ type: "address",
394
+ name: "stickyToken",
395
+ indexed: true,
396
+ },
397
+ {
398
+ type: "uint256",
399
+ name: "groupId",
400
+ indexed: true,
401
+ },
402
+ {
403
+ type: "address",
404
+ name: "sucker",
405
+ },
406
+ {
407
+ type: "address",
408
+ name: "backingToken",
409
+ },
410
+ {
411
+ type: "uint256",
412
+ name: "index",
413
+ },
414
+ {
415
+ type: "uint256",
416
+ name: "projectTokenCount",
417
+ },
418
+ {
419
+ type: "uint256",
420
+ name: "minimumReclaimed",
421
+ },
422
+ {
423
+ type: "uint256",
424
+ name: "feeTokenCount",
425
+ },
426
+ {
427
+ type: "uint256",
428
+ name: "refundedFee",
429
+ },
430
+ {
431
+ type: "uint256",
432
+ name: "refundedTransportPayment",
433
+ },
434
+ {
435
+ type: "address",
436
+ name: "caller",
437
+ },
438
+ ],
439
+ },
440
+ {
441
+ name: "Settle",
442
+ type: "event",
443
+ inputs: [
444
+ {
445
+ type: "uint256",
446
+ name: "sourceProjectId",
447
+ indexed: true,
448
+ },
449
+ {
450
+ type: "address",
451
+ name: "stickyToken",
452
+ indexed: true,
453
+ },
454
+ {
455
+ type: "uint256",
456
+ name: "groupId",
457
+ indexed: true,
458
+ },
459
+ {
460
+ type: "uint256",
461
+ name: "amount",
462
+ },
463
+ {
464
+ type: "uint256",
465
+ name: "settled",
466
+ },
467
+ {
468
+ type: "address",
469
+ name: "caller",
470
+ },
471
+ ],
472
+ },
473
+ ];
474
+ const stickyFeePayerIdentityAbi = [
475
+ {
476
+ name: "COLLECTOR",
477
+ type: "function",
478
+ stateMutability: "view",
479
+ inputs: [],
480
+ outputs: [
481
+ {
482
+ type: "address",
483
+ },
484
+ ],
485
+ },
486
+ ];
487
+ const stickyTokenIdentityAbi = [
488
+ {
489
+ name: "PROJECT_ID",
490
+ type: "function",
491
+ stateMutability: "view",
492
+ inputs: [],
493
+ outputs: [
494
+ {
495
+ type: "uint256",
496
+ },
497
+ ],
498
+ },
499
+ ];
500
+ const stickySuckerIdentityAbi = [
501
+ {
502
+ name: "DIRECTORY",
503
+ type: "function",
504
+ stateMutability: "view",
505
+ inputs: [],
506
+ outputs: [
507
+ {
508
+ type: "address",
509
+ },
510
+ ],
511
+ },
512
+ {
513
+ name: "REGISTRY",
514
+ type: "function",
515
+ stateMutability: "view",
516
+ inputs: [],
517
+ outputs: [
518
+ {
519
+ type: "address",
520
+ },
521
+ ],
522
+ },
523
+ {
524
+ name: "TOKENS",
525
+ type: "function",
526
+ stateMutability: "view",
527
+ inputs: [],
528
+ outputs: [
529
+ {
530
+ type: "address",
531
+ },
532
+ ],
533
+ },
534
+ {
535
+ name: "state",
536
+ type: "function",
537
+ stateMutability: "view",
538
+ inputs: [],
539
+ outputs: [
540
+ {
541
+ type: "uint8",
542
+ },
543
+ ],
544
+ },
545
+ ];
546
+ /** No new collector family has been published as a verified live deployment yet. */
547
+ exports.STICKY_SOURCE_COLLECTOR_DEPLOYMENTS = [];
548
+ /**
549
+ * Find a deployed source/home pair. Unknown or conflicting family records fail
550
+ * closed, including different addresses for the same destination on other sources.
551
+ */
552
+ function stickySourceCollectorDeployment(sourceChainId, destinationChainId, deployments = exports.STICKY_SOURCE_COLLECTOR_DEPLOYMENTS) {
553
+ const family = deployments.filter((item) => item.destinationChainId === destinationChainId);
554
+ const matches = family.filter((item) => item.sourceChainId === sourceChainId);
555
+ if (matches.length !== 1)
556
+ return undefined;
557
+ const found = matches[0];
558
+ if (family.some((item) => !(0, viem_1.isAddressEqual)(item.address, found.address) ||
559
+ item.runtimeCodeHash.toLowerCase() !==
560
+ found.runtimeCodeHash.toLowerCase()))
561
+ return undefined;
562
+ return found;
563
+ }
564
+ /** Recognize only an unambiguous deployed collector on this particular chain. */
565
+ function stickySourceCollectorAt(sourceChainId, address, deployments = exports.STICKY_SOURCE_COLLECTOR_DEPLOYMENTS) {
566
+ if (!(0, viem_1.isAddress)(address, { strict: false }))
567
+ return undefined;
568
+ const matches = deployments.filter((item) => item.sourceChainId === sourceChainId &&
569
+ (0, viem_1.isAddressEqual)(item.address, address));
570
+ if (matches.length !== 1)
571
+ return undefined;
572
+ return stickySourceCollectorDeployment(sourceChainId, matches[0].destinationChainId, deployments);
573
+ }
574
+ function assertStickyAllocation(args) {
575
+ if (args.sourceProjectId <= 0n ||
576
+ (0, viem_1.isAddressEqual)(args.stickyToken, viem_1.zeroAddress))
577
+ throw new Error("Sticky source project and share token must be nonzero.");
578
+ const reason = validateStickyGroupId(args.groupId);
579
+ if (reason)
580
+ throw new Error(reason);
581
+ }
582
+ /**
583
+ * Build one reserved-token split. Place it in RESERVED_TOKEN_SPLIT_GROUP_ID (1).
584
+ * The split projectId remains the existing reward group, not a chain encoding.
585
+ * Call verifyStickyCollectorRoute before configuring it; this pure builder cannot
586
+ * establish deployment, destination readiness or an actually usable transport lane.
587
+ */
588
+ function buildStickyReservedSplit(args) {
589
+ assertStickyAllocation(args);
590
+ if (!Number.isInteger(args.percent) ||
591
+ args.percent < 0 ||
592
+ args.percent > pureConstants_js_1.SPLITS_TOTAL_PERCENT)
593
+ throw new Error("Sticky split percent must be an integer from 0 to 1e9.");
594
+ return (0, splits_js_1.buildSplit)({
595
+ beneficiary: args.stickyToken,
596
+ hook: args.deployment.address,
597
+ projectId: args.groupId,
598
+ percent: args.percent,
599
+ lockedUntil: args.lockedUntil,
600
+ });
601
+ }
602
+ /** Read the queued amount, in source project-token atoms, without initiating delivery. */
603
+ async function getStickyCollectorPending(client, args) {
604
+ assertStickyAllocation(args);
605
+ await assertStickyChain(client, args.deployment.sourceChainId);
606
+ return client.readContract({
607
+ address: args.deployment.address,
608
+ abi: exports.stickySourceCollectorAbi,
609
+ functionName: "pendingOf",
610
+ args: [args.sourceProjectId, args.stickyToken, args.groupId],
611
+ });
612
+ }
613
+ function assertStickyDelivery(args) {
614
+ assertStickyAllocation(args);
615
+ if (args.amount <= 0n)
616
+ throw new Error("Sticky delivery amount must be positive.");
617
+ }
618
+ /**
619
+ * Prepare permissionless source submission, not final destination settlement.
620
+ * Reverify identity/route and pending custody before wallet simulation. Value pays
621
+ * the registry fee plus any native transport budget; this builder does not quote it.
622
+ */
623
+ function buildStickyCollectorSendTx(args) {
624
+ assertStickyDelivery(args);
625
+ if (args.deployment.sourceChainId === args.deployment.destinationChainId)
626
+ throw new Error("Use settle on the Sticky pool's home chain.");
627
+ if ((0, viem_1.isAddressEqual)(args.sucker, viem_1.zeroAddress) ||
628
+ (0, viem_1.isAddressEqual)(args.backingToken, viem_1.zeroAddress) ||
629
+ args.value < 0n)
630
+ throw new Error("Sticky send requires a route, backing token and nonnegative native budget.");
631
+ return {
632
+ chainId: args.deployment.sourceChainId,
633
+ address: args.deployment.address,
634
+ abi: exports.stickySourceCollectorAbi,
635
+ functionName: "send",
636
+ args: [
637
+ args.sourceProjectId,
638
+ args.stickyToken,
639
+ args.groupId,
640
+ args.amount,
641
+ args.sucker,
642
+ args.backingToken,
643
+ ],
644
+ value: args.value,
645
+ };
646
+ }
647
+ /** Prepare permissionless local settlement; the source must be the bound home chain. */
648
+ function buildStickyCollectorSettleTx(args) {
649
+ assertStickyDelivery(args);
650
+ if (args.deployment.sourceChainId !== args.deployment.destinationChainId)
651
+ throw new Error("Sticky settlement must execute on the pool's home chain.");
652
+ return {
653
+ chainId: args.deployment.sourceChainId,
654
+ address: args.deployment.address,
655
+ abi: exports.stickySourceCollectorAbi,
656
+ functionName: "settle",
657
+ args: [
658
+ args.sourceProjectId,
659
+ args.stickyToken,
660
+ args.groupId,
661
+ args.amount,
662
+ ],
663
+ };
664
+ }
665
+ async function assertStickyChain(client, chainId) {
666
+ if ((await client.getChainId()) !== chainId)
667
+ throw new Error("Sticky RPC chain does not match the configured chain.");
668
+ }
669
+ async function requireStickyCode(client, address) {
670
+ const code = await client.getCode({ address });
671
+ if (!code || code === "0x")
672
+ throw new Error(`Sticky requires deployed code at ${address}.`);
673
+ return code;
674
+ }
675
+ /** A positive-backed claim needs a live controller and a terminal accepting that exact asset. */
676
+ async function stickyBackingContext(client, chainId, projectId, token) {
677
+ const [controller, terminal] = await Promise.all([
678
+ client.readContract({
679
+ address: (0, types_js_1.v6Address)("JBDirectory", chainId),
680
+ abi: juicebox_js_1.jbDirectoryAbi,
681
+ functionName: "controllerOf",
682
+ args: [projectId],
683
+ }),
684
+ client.readContract({
685
+ address: (0, types_js_1.v6Address)("JBDirectory", chainId),
686
+ abi: juicebox_js_1.jbDirectoryAbi,
687
+ functionName: "primaryTerminalOf",
688
+ args: [projectId, token],
689
+ }),
690
+ ]);
691
+ if ((0, viem_1.isAddressEqual)(controller, viem_1.zeroAddress) ||
692
+ (0, viem_1.isAddressEqual)(terminal, viem_1.zeroAddress))
693
+ throw new Error("Sticky reward route needs a controller and backing terminal on both chains.");
694
+ await Promise.all([
695
+ requireStickyCode(client, controller),
696
+ requireStickyCode(client, terminal),
697
+ ]);
698
+ const context = await client.readContract({
699
+ address: terminal,
700
+ abi: juicebox_js_1.jbMultiTerminalAbi,
701
+ functionName: "accountingContextForTokenOf",
702
+ args: [projectId, token],
703
+ });
704
+ if (!(0, viem_1.isAddressEqual)(context.token, token))
705
+ throw new Error("Sticky backing terminal does not accept the mapped asset.");
706
+ return { ...context, controller };
707
+ }
708
+ /**
709
+ * Verify reviewed runtime fingerprints and immutable bindings on the actual source
710
+ * chain. This is read-only evidence at the time of the call, not execution authority.
711
+ */
712
+ async function verifyStickySourceCollector(client, deployment) {
713
+ await assertStickyChain(client, deployment.sourceChainId);
714
+ const [collectorCode, feeCode] = await Promise.all([
715
+ requireStickyCode(client, deployment.address),
716
+ requireStickyCode(client, deployment.feePayer),
717
+ ]);
718
+ if ((0, viem_1.keccak256)(collectorCode).toLowerCase() !==
719
+ deployment.runtimeCodeHash.toLowerCase() ||
720
+ (0, viem_1.keccak256)(feeCode).toLowerCase() !==
721
+ deployment.feePayerRuntimeCodeHash.toLowerCase())
722
+ throw new Error("Sticky collector runtime does not match the reviewed deployment.");
723
+ const bindings = [
724
+ ["DIRECTORY", deployment.directory, "JBDirectory"],
725
+ ["REGISTRY", deployment.registry, "JBSuckerRegistry"],
726
+ ["TOKENS", deployment.tokens, "JBTokens"],
727
+ [
728
+ "RECEIVER_FACTORY",
729
+ deployment.receiverFactory,
730
+ "StickyRewardReceiverFactory",
731
+ ],
732
+ ];
733
+ for (const [name, expected, canonical] of bindings) {
734
+ if (!(0, viem_1.isAddressEqual)(expected, (0, types_js_1.v6Address)(canonical, deployment.sourceChainId)))
735
+ throw new Error(`Sticky ${name} is not the canonical V6 binding.`);
736
+ const actual = await client.readContract({
737
+ address: deployment.address,
738
+ abi: exports.stickySourceCollectorAbi,
739
+ functionName: name,
740
+ });
741
+ if (!(0, viem_1.isAddressEqual)(actual, expected))
742
+ throw new Error(`Sticky collector ${name} binding changed.`);
743
+ }
744
+ const [destination, feePayer, collector] = await Promise.all([
745
+ client.readContract({
746
+ address: deployment.address,
747
+ abi: exports.stickySourceCollectorAbi,
748
+ functionName: "DESTINATION_CHAIN_ID",
749
+ }),
750
+ client.readContract({
751
+ address: deployment.address,
752
+ abi: exports.stickySourceCollectorAbi,
753
+ functionName: "FEE_PAYER",
754
+ }),
755
+ client.readContract({
756
+ address: deployment.feePayer,
757
+ abi: stickyFeePayerIdentityAbi,
758
+ functionName: "COLLECTOR",
759
+ }),
760
+ ]);
761
+ if (destination !== BigInt(deployment.destinationChainId) ||
762
+ !(0, viem_1.isAddressEqual)(feePayer, deployment.feePayer) ||
763
+ !(0, viem_1.isAddressEqual)(collector, deployment.address))
764
+ throw new Error("Sticky collector destination or fee-child binding changed.");
765
+ }
766
+ /**
767
+ * Freshly qualify one local or direct remote lane before configuring a split or
768
+ * sending. Source credits may queue before their ERC-20 exists; the home-chain
769
+ * reward ERC-20 and registered Sticky pool must already exist. The canonical
770
+ * registered peer determines the destination reward project, never address parity.
771
+ * Re-run through the reviewed-write reverify boundary before simulation/submission.
772
+ */
773
+ async function verifyStickyCollectorRoute(sourceClient, destinationClient, args) {
774
+ assertStickyAllocation(args);
775
+ const { deployment, sourceProjectId, stickyToken, groupId } = args;
776
+ const home = deployment.destinationChainId;
777
+ await Promise.all([
778
+ verifyStickySourceCollector(sourceClient, deployment),
779
+ assertStickyChain(destinationClient, home),
780
+ ]);
781
+ await requireStickyCode(destinationClient, stickyToken);
782
+ const stickyProjectId = await destinationClient.readContract({
783
+ address: stickyToken,
784
+ abi: stickyTokenIdentityAbi,
785
+ functionName: "PROJECT_ID",
786
+ });
787
+ const [registered, projectToken] = await Promise.all([
788
+ destinationClient.readContract({
789
+ address: (0, types_js_1.v6Address)("StickyHook", home),
790
+ abi: juicebox_js_1.stickyHookAbi,
791
+ functionName: "tokenOf",
792
+ args: [stickyProjectId],
793
+ }),
794
+ destinationClient.readContract({
795
+ address: (0, types_js_1.v6Address)("JBTokens", home),
796
+ abi: juicebox_js_1.jbTokensAbi,
797
+ functionName: "tokenOf",
798
+ args: [stickyProjectId],
799
+ }),
800
+ ]);
801
+ if (!(0, viem_1.isAddressEqual)(registered, stickyToken) ||
802
+ !(0, viem_1.isAddressEqual)(projectToken, stickyToken))
803
+ throw new Error("Sticky share token is not the registered home-chain pool.");
804
+ const destinationFactory = (0, types_js_1.v6Address)("StickyRewardReceiverFactory", home);
805
+ const [sourceReceiver, receiver, distributor] = await Promise.all([
806
+ sourceClient.readContract({
807
+ address: deployment.receiverFactory,
808
+ abi: juicebox_js_1.stickyRewardReceiverFactoryAbi,
809
+ functionName: "predictReceiverOf",
810
+ args: [stickyToken, groupId],
811
+ }),
812
+ destinationClient.readContract({
813
+ address: destinationFactory,
814
+ abi: juicebox_js_1.stickyRewardReceiverFactoryAbi,
815
+ functionName: "predictReceiverOf",
816
+ args: [stickyToken, groupId],
817
+ }),
818
+ destinationClient.readContract({
819
+ address: destinationFactory,
820
+ abi: juicebox_js_1.stickyRewardReceiverFactoryAbi,
821
+ functionName: "DISTRIBUTOR",
822
+ }),
823
+ ]);
824
+ if (!(0, viem_1.isAddressEqual)(sourceReceiver, receiver) ||
825
+ !(0, viem_1.isAddressEqual)(distributor, (0, types_js_1.v6Address)("StickyDistributor", home)))
826
+ throw new Error("Sticky receiver identity differs between source and home chain.");
827
+ let destinationProjectId = sourceProjectId;
828
+ if (deployment.sourceChainId !== home) {
829
+ const { jbSuckerV6ViewAbi, suckerBytes32ToAddress } = await Promise.resolve().then(() => __importStar(require("./suckers.js")));
830
+ const { sucker, backingToken } = args;
831
+ if (!sucker || !backingToken)
832
+ throw new Error("A direct Sticky source-to-home route is required.");
833
+ // Membership is anchored before any candidate getters are trusted.
834
+ if (!(await sourceClient.readContract({
835
+ address: deployment.registry,
836
+ abi: juicebox_js_1.jbSuckerRegistryAbi,
837
+ functionName: "isSuckerOf",
838
+ args: [sourceProjectId, sucker],
839
+ })))
840
+ throw new Error("Sticky source route is not registered for this project.");
841
+ const [projectId, peerChainId, peer, state, mapping, registry, tokens, directory,] = await Promise.all([
842
+ sourceClient.readContract({
843
+ address: sucker,
844
+ abi: jbSuckerV6ViewAbi,
845
+ functionName: "projectId",
846
+ }),
847
+ sourceClient.readContract({
848
+ address: sucker,
849
+ abi: jbSuckerV6ViewAbi,
850
+ functionName: "peerChainId",
851
+ }),
852
+ sourceClient.readContract({
853
+ address: sucker,
854
+ abi: jbSuckerV6ViewAbi,
855
+ functionName: "peer",
856
+ }),
857
+ sourceClient.readContract({
858
+ address: sucker,
859
+ abi: stickySuckerIdentityAbi,
860
+ functionName: "state",
861
+ }),
862
+ sourceClient.readContract({
863
+ address: sucker,
864
+ abi: jbSuckerV6ViewAbi,
865
+ functionName: "remoteTokenFor",
866
+ args: [backingToken],
867
+ }),
868
+ sourceClient.readContract({
869
+ address: sucker,
870
+ abi: stickySuckerIdentityAbi,
871
+ functionName: "REGISTRY",
872
+ }),
873
+ sourceClient.readContract({
874
+ address: sucker,
875
+ abi: stickySuckerIdentityAbi,
876
+ functionName: "TOKENS",
877
+ }),
878
+ sourceClient.readContract({
879
+ address: sucker,
880
+ abi: stickySuckerIdentityAbi,
881
+ functionName: "DIRECTORY",
882
+ }),
883
+ ]);
884
+ if (projectId !== sourceProjectId ||
885
+ peerChainId !== BigInt(home) ||
886
+ peer === viem_1.zeroHash ||
887
+ !(0, viem_1.isAddressEqual)(registry, deployment.registry) ||
888
+ !(0, viem_1.isAddressEqual)(tokens, deployment.tokens) ||
889
+ !(0, viem_1.isAddressEqual)(directory, deployment.directory))
890
+ throw new Error("Sticky route does not bind this source project to the selected home chain.");
891
+ // JBSuckerState: ENABLED=0, DEPRECATION_PENDING=1; other states cannot send.
892
+ if (state !== 0 && state !== 1)
893
+ throw new Error("Sticky source route no longer permits sending.");
894
+ if (!mapping.enabled || mapping.emergencyHatch || mapping.addr === viem_1.zeroHash)
895
+ throw new Error("Sticky source backing mapping is unavailable.");
896
+ const peerAddress = suckerBytes32ToAddress(peer);
897
+ destinationProjectId = await destinationClient.readContract({
898
+ address: peerAddress,
899
+ abi: jbSuckerV6ViewAbi,
900
+ functionName: "projectId",
901
+ });
902
+ if (!(await destinationClient.readContract({
903
+ address: (0, types_js_1.v6Address)("JBSuckerRegistry", home),
904
+ abi: juicebox_js_1.jbSuckerRegistryAbi,
905
+ functionName: "isSuckerOf",
906
+ args: [destinationProjectId, peerAddress],
907
+ })))
908
+ throw new Error("Sticky destination route is not registered.");
909
+ const [returnChain, returnPeer] = await Promise.all([
910
+ destinationClient.readContract({
911
+ address: peerAddress,
912
+ abi: jbSuckerV6ViewAbi,
913
+ functionName: "peerChainId",
914
+ }),
915
+ destinationClient.readContract({
916
+ address: peerAddress,
917
+ abi: jbSuckerV6ViewAbi,
918
+ functionName: "peer",
919
+ }),
920
+ ]);
921
+ if (returnChain !== BigInt(deployment.sourceChainId) ||
922
+ !(0, viem_1.isAddressEqual)(suckerBytes32ToAddress(returnPeer), sucker))
923
+ throw new Error("Sticky destination peer does not match the source route.");
924
+ const remoteBackingToken = suckerBytes32ToAddress(mapping.addr);
925
+ const [sourceContext, destinationContext] = await Promise.all([
926
+ stickyBackingContext(sourceClient, deployment.sourceChainId, sourceProjectId, backingToken),
927
+ stickyBackingContext(destinationClient, home, destinationProjectId, remoteBackingToken),
928
+ ]);
929
+ if (sourceContext.decimals !== destinationContext.decimals)
930
+ throw new Error("Sticky backing decimals differ between source and home chain.");
931
+ // Registration survives some ruleset changes that can revoke mint authority.
932
+ // Probe the actual current controller as the peer; this eth_call mints no live tokens.
933
+ await destinationClient.simulateContract({
934
+ address: destinationContext.controller,
935
+ abi: juicebox_js_1.jbControllerAbi,
936
+ functionName: "mintTokensOf",
937
+ args: [destinationProjectId, 1n, receiver, "", false],
938
+ account: peerAddress,
939
+ });
940
+ }
941
+ const [sourceToken, rewardToken] = await Promise.all([
942
+ sourceClient.readContract({
943
+ address: deployment.tokens,
944
+ abi: juicebox_js_1.jbTokensAbi,
945
+ functionName: "tokenOf",
946
+ args: [sourceProjectId],
947
+ }),
948
+ destinationClient.readContract({
949
+ address: (0, types_js_1.v6Address)("JBTokens", home),
950
+ abi: juicebox_js_1.jbTokensAbi,
951
+ functionName: "tokenOf",
952
+ args: [destinationProjectId],
953
+ }),
954
+ ]);
955
+ await requireStickyCode(destinationClient, rewardToken);
956
+ return { receiver, sourceToken, rewardToken, destinationProjectId };
957
+ }
132
958
  //# sourceMappingURL=sticky.js.map