@plasius/economy 0.6.0 → 0.8.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.
- package/README.md +85 -0
- package/dist/index.cjs +1619 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +417 -2
- package/dist/index.d.ts +417 -2
- package/dist/index.js +1588 -73
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -501,6 +501,1155 @@ function mapBitLabsConversionState(state) {
|
|
|
501
501
|
return transition;
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// src/admin-reporting.ts
|
|
505
|
+
var ADMIN_TOKEN_DEFAULT_WINDOW_DAYS = 30;
|
|
506
|
+
var ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS = 365;
|
|
507
|
+
var ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS = 31;
|
|
508
|
+
var ADMIN_TOKEN_MAXIMUM_PAGE_SIZE = 100;
|
|
509
|
+
var ADMIN_TOKEN_MAXIMUM_TREND_POINTS = ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS * 24 * 5;
|
|
510
|
+
var ADMIN_TOKEN_MINIMUM_COHORT_SIZE = 5;
|
|
511
|
+
var ADMIN_TOKEN_ANOMALY_BASELINE_DAYS = 28;
|
|
512
|
+
var DAY_MILLISECONDS = 864e5;
|
|
513
|
+
var HOUR_MILLISECONDS = 36e5;
|
|
514
|
+
var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
515
|
+
"acquisition",
|
|
516
|
+
"spend",
|
|
517
|
+
"reversal",
|
|
518
|
+
"hold",
|
|
519
|
+
"failure"
|
|
520
|
+
]);
|
|
521
|
+
var ACTIVITY_STATUSES = /* @__PURE__ */ new Set([
|
|
522
|
+
"pending",
|
|
523
|
+
"held",
|
|
524
|
+
"settled",
|
|
525
|
+
"reversed",
|
|
526
|
+
"failed"
|
|
527
|
+
]);
|
|
528
|
+
var ACTIVITY_SOURCES = /* @__PURE__ */ new Set([
|
|
529
|
+
"paid-purchase",
|
|
530
|
+
"subscription",
|
|
531
|
+
"rewarded-activity",
|
|
532
|
+
"gameplay",
|
|
533
|
+
"system-adjustment",
|
|
534
|
+
"unknown"
|
|
535
|
+
]);
|
|
536
|
+
var SAFE_LABELS = /* @__PURE__ */ new Set([
|
|
537
|
+
"token-acquisition",
|
|
538
|
+
"token-spend",
|
|
539
|
+
"token-reversal",
|
|
540
|
+
"token-hold",
|
|
541
|
+
"token-activity-failed",
|
|
542
|
+
"token-system-adjustment",
|
|
543
|
+
"token-activity-unclassified"
|
|
544
|
+
]);
|
|
545
|
+
var SAFE_LABELS_BY_ACTIVITY_TYPE = {
|
|
546
|
+
acquisition: /* @__PURE__ */ new Set([
|
|
547
|
+
"token-acquisition",
|
|
548
|
+
"token-system-adjustment",
|
|
549
|
+
"token-activity-unclassified"
|
|
550
|
+
]),
|
|
551
|
+
spend: /* @__PURE__ */ new Set([
|
|
552
|
+
"token-spend",
|
|
553
|
+
"token-system-adjustment",
|
|
554
|
+
"token-activity-unclassified"
|
|
555
|
+
]),
|
|
556
|
+
reversal: /* @__PURE__ */ new Set([
|
|
557
|
+
"token-reversal",
|
|
558
|
+
"token-system-adjustment",
|
|
559
|
+
"token-activity-unclassified"
|
|
560
|
+
]),
|
|
561
|
+
hold: /* @__PURE__ */ new Set([
|
|
562
|
+
"token-hold",
|
|
563
|
+
"token-system-adjustment",
|
|
564
|
+
"token-activity-unclassified"
|
|
565
|
+
]),
|
|
566
|
+
failure: /* @__PURE__ */ new Set([
|
|
567
|
+
"token-activity-failed",
|
|
568
|
+
"token-activity-unclassified"
|
|
569
|
+
])
|
|
570
|
+
};
|
|
571
|
+
var ACTIVITY_SORTS = /* @__PURE__ */ new Set([
|
|
572
|
+
"occurred-at-desc",
|
|
573
|
+
"amount-absolute-desc"
|
|
574
|
+
]);
|
|
575
|
+
var PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
576
|
+
"admin-token-activity",
|
|
577
|
+
"mcp-token-activity"
|
|
578
|
+
]);
|
|
579
|
+
var BALANCE_PSEUDONYM_AUDIENCES = /* @__PURE__ */ new Set([
|
|
580
|
+
"admin-token-balances",
|
|
581
|
+
"mcp-token-balances"
|
|
582
|
+
]);
|
|
583
|
+
var WALLET_COMPONENTS = /* @__PURE__ */ new Set([
|
|
584
|
+
"household",
|
|
585
|
+
"personal",
|
|
586
|
+
"gameplay-allocation"
|
|
587
|
+
]);
|
|
588
|
+
var WALLET_STATUSES = /* @__PURE__ */ new Set([
|
|
589
|
+
"active",
|
|
590
|
+
"closed"
|
|
591
|
+
]);
|
|
592
|
+
var WALLET_BALANCE_SORTS = /* @__PURE__ */ new Set([
|
|
593
|
+
"available-desc",
|
|
594
|
+
"updated-at-desc"
|
|
595
|
+
]);
|
|
596
|
+
var TREND_GRANULARITIES = /* @__PURE__ */ new Set([
|
|
597
|
+
"hour",
|
|
598
|
+
"day"
|
|
599
|
+
]);
|
|
600
|
+
var ALIAS = /^[A-Za-z0-9_-]{16,96}$/u;
|
|
601
|
+
var OPAQUE_CURSOR = /^c1\.[A-Za-z0-9_-]{32,480}$/u;
|
|
602
|
+
var PSEUDONYM_VERSION = /^[A-Za-z0-9][A-Za-z0-9._-]{0,31}$/u;
|
|
603
|
+
var EXACT_STATISTIC_INTEGER = /^(?:0|-?[1-9][0-9]*)$/u;
|
|
604
|
+
var POSITIVE_UNSIGNED_INTEGER = /^[1-9][0-9]*$/u;
|
|
605
|
+
var MAXIMUM_STATISTIC_HALF_SUBUNITS = (TOKEN_SUBUNITS_MAX - TOKEN_SUBUNITS_MIN) * 2n;
|
|
606
|
+
var ANOMALY_UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
|
|
607
|
+
"insufficient-history",
|
|
608
|
+
"privacy-suppressed-baseline"
|
|
609
|
+
]);
|
|
610
|
+
function assertPlainObject(value, label) {
|
|
611
|
+
economyAssert(
|
|
612
|
+
typeof value === "object" && value !== null && !Array.isArray(value),
|
|
613
|
+
"INVALID_CONTRACT",
|
|
614
|
+
`${label} must be an object`
|
|
615
|
+
);
|
|
616
|
+
const prototype = Object.getPrototypeOf(value);
|
|
617
|
+
economyAssert(
|
|
618
|
+
(prototype === Object.prototype || prototype === null) && !Reflect.has(value, "toJSON"),
|
|
619
|
+
"INVALID_CONTRACT",
|
|
620
|
+
`${label} must be a plain data object without serialization hooks`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function assertExactKeys(value, allowedKeys, label) {
|
|
624
|
+
assertPlainObject(value, label);
|
|
625
|
+
const allowed = new Set(allowedKeys);
|
|
626
|
+
const keys = Reflect.ownKeys(value);
|
|
627
|
+
economyAssert(
|
|
628
|
+
allowedKeys.every(
|
|
629
|
+
(key) => !Reflect.has(value, key) || Object.hasOwn(value, key)
|
|
630
|
+
) && keys.every((key) => {
|
|
631
|
+
if (typeof key !== "string" || !allowed.has(key)) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
635
|
+
return descriptor !== void 0 && descriptor.enumerable && "value" in descriptor;
|
|
636
|
+
}),
|
|
637
|
+
"INVALID_CONTRACT",
|
|
638
|
+
`${label} contains an unsupported, identifying, or non-data property`
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
function assertAlias(value, label) {
|
|
642
|
+
economyAssert(
|
|
643
|
+
typeof value === "string" && ALIAS.test(value),
|
|
644
|
+
"INVALID_CONTRACT",
|
|
645
|
+
`${label} must be an opaque pseudonymous alias`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
function assertOpaqueCursor(value) {
|
|
649
|
+
economyAssert(
|
|
650
|
+
typeof value === "string" && OPAQUE_CURSOR.test(value),
|
|
651
|
+
"INVALID_CONTRACT",
|
|
652
|
+
"Admin Token cursor must be a bounded confidentiality-protected opaque value"
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
function assertUniqueValues(values, allowed, label) {
|
|
656
|
+
economyAssert(
|
|
657
|
+
Array.isArray(values),
|
|
658
|
+
"INVALID_CONTRACT",
|
|
659
|
+
`${label} must be a list`
|
|
660
|
+
);
|
|
661
|
+
const unique = new Set(values);
|
|
662
|
+
economyAssert(
|
|
663
|
+
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
664
|
+
"INVALID_CONTRACT",
|
|
665
|
+
`${label} must contain unique supported values`
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
function absolute(value) {
|
|
669
|
+
return value < 0n ? -value : value;
|
|
670
|
+
}
|
|
671
|
+
function compareTextDescending(left, right) {
|
|
672
|
+
if (left === right) {
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
return left > right ? -1 : 1;
|
|
676
|
+
}
|
|
677
|
+
function assertReportingWindow(window, maximumDays = ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS) {
|
|
678
|
+
assertExactKeys(
|
|
679
|
+
window,
|
|
680
|
+
["fromInclusive", "toExclusive"],
|
|
681
|
+
"Admin Token reporting window"
|
|
682
|
+
);
|
|
683
|
+
const from = parseIsoTimestamp(window.fromInclusive);
|
|
684
|
+
const to = parseIsoTimestamp(window.toExclusive);
|
|
685
|
+
economyAssert(
|
|
686
|
+
from < to && to - from <= maximumDays * DAY_MILLISECONDS,
|
|
687
|
+
"INVALID_TIME_WINDOW",
|
|
688
|
+
`Admin Token reporting window must be positive and no longer than ${maximumDays} days`
|
|
689
|
+
);
|
|
690
|
+
return { from, to };
|
|
691
|
+
}
|
|
692
|
+
function createDefaultAdminTokenReportingWindow(asOf) {
|
|
693
|
+
const to = parseIsoTimestamp(asOf);
|
|
694
|
+
return {
|
|
695
|
+
fromInclusive: new Date(
|
|
696
|
+
to - ADMIN_TOKEN_DEFAULT_WINDOW_DAYS * DAY_MILLISECONDS
|
|
697
|
+
).toISOString(),
|
|
698
|
+
toExclusive: new Date(to).toISOString()
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function assertNonNegativeTokenAmounts(amounts, label) {
|
|
702
|
+
economyAssert(
|
|
703
|
+
amounts.every((amount) => parseTokenSubunits(amount) >= 0n),
|
|
704
|
+
"INVALID_AMOUNT",
|
|
705
|
+
`${label} cannot contain a negative amount`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function assertPositiveAuthoritySequence(sequence, label) {
|
|
709
|
+
economyAssert(
|
|
710
|
+
typeof sequence === "string" && POSITIVE_UNSIGNED_INTEGER.test(sequence),
|
|
711
|
+
"INVALID_CONTRACT",
|
|
712
|
+
`${label} must be a canonical positive integer`
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
function assertAdminTokenEconomySummary(summary) {
|
|
716
|
+
assertExactKeys(
|
|
717
|
+
summary,
|
|
718
|
+
[
|
|
719
|
+
"schemaVersion",
|
|
720
|
+
"generatedAt",
|
|
721
|
+
"projectionAsOf",
|
|
722
|
+
"authoritySequence",
|
|
723
|
+
"walletCount",
|
|
724
|
+
"activeWalletCount",
|
|
725
|
+
"balances",
|
|
726
|
+
"lifetime",
|
|
727
|
+
"rawIdentifiersIncluded"
|
|
728
|
+
],
|
|
729
|
+
"Admin Token economy summary"
|
|
730
|
+
);
|
|
731
|
+
assertExactKeys(
|
|
732
|
+
summary.balances,
|
|
733
|
+
["schemaVersion", "available", "reserved", "held", "rewardProgress"],
|
|
734
|
+
"Admin Token aggregate balances"
|
|
735
|
+
);
|
|
736
|
+
assertExactKeys(
|
|
737
|
+
summary.lifetime,
|
|
738
|
+
[
|
|
739
|
+
"schemaVersion",
|
|
740
|
+
"bought",
|
|
741
|
+
"earned",
|
|
742
|
+
"allocated",
|
|
743
|
+
"reclaimed",
|
|
744
|
+
"spent",
|
|
745
|
+
"reversed"
|
|
746
|
+
],
|
|
747
|
+
"Admin Token aggregate lifetime"
|
|
748
|
+
);
|
|
749
|
+
economyAssert(
|
|
750
|
+
summary.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.balances.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.lifetime.schemaVersion === ECONOMY_CONTRACT_VERSION && summary.rawIdentifiersIncluded === false && Number.isSafeInteger(summary.walletCount) && summary.walletCount >= 0 && Number.isSafeInteger(summary.activeWalletCount) && summary.activeWalletCount >= 0 && summary.activeWalletCount <= summary.walletCount,
|
|
751
|
+
"INVALID_CONTRACT",
|
|
752
|
+
"Admin Token economy summary metadata is invalid"
|
|
753
|
+
);
|
|
754
|
+
const generatedAt = parseIsoTimestamp(summary.generatedAt);
|
|
755
|
+
const projectionAsOf = parseIsoTimestamp(summary.projectionAsOf);
|
|
756
|
+
economyAssert(
|
|
757
|
+
projectionAsOf <= generatedAt,
|
|
758
|
+
"INVALID_TIME_WINDOW",
|
|
759
|
+
"Admin Token projection cannot be newer than its generated result"
|
|
760
|
+
);
|
|
761
|
+
assertPositiveAuthoritySequence(
|
|
762
|
+
summary.authoritySequence,
|
|
763
|
+
"Admin Token summary authority sequence"
|
|
764
|
+
);
|
|
765
|
+
assertNonNegativeTokenAmounts(
|
|
766
|
+
[
|
|
767
|
+
summary.balances.available,
|
|
768
|
+
summary.balances.reserved,
|
|
769
|
+
summary.balances.held,
|
|
770
|
+
summary.balances.rewardProgress,
|
|
771
|
+
summary.lifetime.bought,
|
|
772
|
+
summary.lifetime.earned,
|
|
773
|
+
summary.lifetime.allocated,
|
|
774
|
+
summary.lifetime.reclaimed,
|
|
775
|
+
summary.lifetime.spent,
|
|
776
|
+
summary.lifetime.reversed
|
|
777
|
+
],
|
|
778
|
+
"Admin Token economy summary"
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
function assertAdminTokenWalletBalanceFilter(filter) {
|
|
782
|
+
assertExactKeys(
|
|
783
|
+
filter,
|
|
784
|
+
["components", "statuses", "subjectAlias"],
|
|
785
|
+
"Admin Token wallet balance filter"
|
|
786
|
+
);
|
|
787
|
+
if (filter.components !== void 0) {
|
|
788
|
+
assertUniqueValues(
|
|
789
|
+
filter.components,
|
|
790
|
+
WALLET_COMPONENTS,
|
|
791
|
+
"Admin Token wallet components"
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
if (filter.statuses !== void 0) {
|
|
795
|
+
assertUniqueValues(
|
|
796
|
+
filter.statuses,
|
|
797
|
+
WALLET_STATUSES,
|
|
798
|
+
"Admin Token wallet statuses"
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
if (filter.subjectAlias !== void 0) {
|
|
802
|
+
assertAlias(filter.subjectAlias, "Wallet subject alias filter");
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function sameWalletBalanceFilter(left, right) {
|
|
806
|
+
if (left === void 0 || right === void 0) {
|
|
807
|
+
return left === right;
|
|
808
|
+
}
|
|
809
|
+
return sameOptionalValues(left.components, right.components) && sameOptionalValues(left.statuses, right.statuses) && left.subjectAlias === right.subjectAlias;
|
|
810
|
+
}
|
|
811
|
+
function assertAdminTokenWalletBalanceCursorBinding(binding) {
|
|
812
|
+
assertExactKeys(
|
|
813
|
+
binding,
|
|
814
|
+
[
|
|
815
|
+
"schemaVersion",
|
|
816
|
+
"sort",
|
|
817
|
+
"filter",
|
|
818
|
+
"audience",
|
|
819
|
+
"pseudonymVersion"
|
|
820
|
+
],
|
|
821
|
+
"Admin Token wallet balance cursor binding"
|
|
822
|
+
);
|
|
823
|
+
economyAssert(
|
|
824
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_BALANCE_SORTS.has(binding.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
825
|
+
"INVALID_CONTRACT",
|
|
826
|
+
"Unsupported Admin Token wallet balance cursor binding"
|
|
827
|
+
);
|
|
828
|
+
if (binding.filter !== void 0) {
|
|
829
|
+
assertAdminTokenWalletBalanceFilter(binding.filter);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function assertAdminTokenWalletBalancePageRequest(request) {
|
|
833
|
+
assertExactKeys(
|
|
834
|
+
request,
|
|
835
|
+
[
|
|
836
|
+
"schemaVersion",
|
|
837
|
+
"limit",
|
|
838
|
+
"cursor",
|
|
839
|
+
"cursorBinding",
|
|
840
|
+
"sort",
|
|
841
|
+
"filter",
|
|
842
|
+
"audience",
|
|
843
|
+
"pseudonymVersion"
|
|
844
|
+
],
|
|
845
|
+
"Admin Token wallet balance request"
|
|
846
|
+
);
|
|
847
|
+
economyAssert(
|
|
848
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && Number.isSafeInteger(request.limit) && request.limit >= 1 && request.limit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && WALLET_BALANCE_SORTS.has(request.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(request.audience) && PSEUDONYM_VERSION.test(request.pseudonymVersion),
|
|
849
|
+
"INVALID_CONTRACT",
|
|
850
|
+
"Unsupported or unbounded Admin Token wallet balance request"
|
|
851
|
+
);
|
|
852
|
+
if (request.filter !== void 0) {
|
|
853
|
+
assertAdminTokenWalletBalanceFilter(request.filter);
|
|
854
|
+
}
|
|
855
|
+
economyAssert(
|
|
856
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
857
|
+
"INVALID_CONTRACT",
|
|
858
|
+
"Admin Token wallet balance cursor and binding must be provided together"
|
|
859
|
+
);
|
|
860
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
assertOpaqueCursor(request.cursor);
|
|
864
|
+
assertAdminTokenWalletBalanceCursorBinding(request.cursorBinding);
|
|
865
|
+
economyAssert(
|
|
866
|
+
request.cursorBinding.sort === request.sort && request.cursorBinding.audience === request.audience && request.cursorBinding.pseudonymVersion === request.pseudonymVersion && sameWalletBalanceFilter(request.cursorBinding.filter, request.filter),
|
|
867
|
+
"INVALID_CONTRACT",
|
|
868
|
+
"Admin Token wallet balance cursor is not bound to the normalized query"
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
function assertAdminTokenWalletBalanceEntry(entry) {
|
|
872
|
+
assertExactKeys(
|
|
873
|
+
entry,
|
|
874
|
+
[
|
|
875
|
+
"schemaVersion",
|
|
876
|
+
"walletAlias",
|
|
877
|
+
"subjectAlias",
|
|
878
|
+
"component",
|
|
879
|
+
"status",
|
|
880
|
+
"available",
|
|
881
|
+
"reserved",
|
|
882
|
+
"held",
|
|
883
|
+
"rewardProgress",
|
|
884
|
+
"updatedAt",
|
|
885
|
+
"authoritySequence"
|
|
886
|
+
],
|
|
887
|
+
"Admin Token wallet balance entry"
|
|
888
|
+
);
|
|
889
|
+
economyAssert(
|
|
890
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && WALLET_COMPONENTS.has(entry.component) && WALLET_STATUSES.has(entry.status),
|
|
891
|
+
"INVALID_CONTRACT",
|
|
892
|
+
"Unsupported Admin Token wallet balance entry"
|
|
893
|
+
);
|
|
894
|
+
assertAlias(entry.walletAlias, "Wallet alias");
|
|
895
|
+
assertAlias(entry.subjectAlias, "Wallet subject alias");
|
|
896
|
+
economyAssert(
|
|
897
|
+
entry.walletAlias !== entry.subjectAlias,
|
|
898
|
+
"INVALID_CONTRACT",
|
|
899
|
+
"Wallet and subject aliases must use separate pseudonym domains"
|
|
900
|
+
);
|
|
901
|
+
assertNonNegativeTokenAmounts(
|
|
902
|
+
[entry.available, entry.reserved, entry.held, entry.rewardProgress],
|
|
903
|
+
"Admin Token wallet balance entry"
|
|
904
|
+
);
|
|
905
|
+
parseIsoTimestamp(entry.updatedAt);
|
|
906
|
+
assertPositiveAuthoritySequence(
|
|
907
|
+
entry.authoritySequence,
|
|
908
|
+
"Admin Token wallet balance authority sequence"
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
function compareWalletBalanceEntries(left, right, sort) {
|
|
912
|
+
if (sort === "available-desc") {
|
|
913
|
+
const leftAvailable = parseTokenSubunits(left.available);
|
|
914
|
+
const rightAvailable = parseTokenSubunits(right.available);
|
|
915
|
+
if (leftAvailable !== rightAvailable) {
|
|
916
|
+
return leftAvailable > rightAvailable ? -1 : 1;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
const leftUpdatedAt = parseIsoTimestamp(left.updatedAt);
|
|
920
|
+
const rightUpdatedAt = parseIsoTimestamp(right.updatedAt);
|
|
921
|
+
if (leftUpdatedAt !== rightUpdatedAt) {
|
|
922
|
+
return leftUpdatedAt > rightUpdatedAt ? -1 : 1;
|
|
923
|
+
}
|
|
924
|
+
return compareTextDescending(left.walletAlias, right.walletAlias);
|
|
925
|
+
}
|
|
926
|
+
function assertAdminTokenWalletBalancePage(page) {
|
|
927
|
+
assertExactKeys(
|
|
928
|
+
page,
|
|
929
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
930
|
+
"Admin Token wallet balance page"
|
|
931
|
+
);
|
|
932
|
+
assertExactKeys(
|
|
933
|
+
page.metadata,
|
|
934
|
+
[
|
|
935
|
+
"schemaVersion",
|
|
936
|
+
"generatedAt",
|
|
937
|
+
"sort",
|
|
938
|
+
"filter",
|
|
939
|
+
"pageLimit",
|
|
940
|
+
"audience",
|
|
941
|
+
"pseudonymVersion",
|
|
942
|
+
"rawIdentifiersIncluded"
|
|
943
|
+
],
|
|
944
|
+
"Admin Token wallet balance metadata"
|
|
945
|
+
);
|
|
946
|
+
economyAssert(
|
|
947
|
+
page.schemaVersion === ECONOMY_CONTRACT_VERSION && page.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && typeof page.hasMore === "boolean" && page.metadata.rawIdentifiersIncluded === false && WALLET_BALANCE_SORTS.has(page.metadata.sort) && BALANCE_PSEUDONYM_AUDIENCES.has(page.metadata.audience) && PSEUDONYM_VERSION.test(page.metadata.pseudonymVersion) && Number.isSafeInteger(page.metadata.pageLimit) && page.metadata.pageLimit >= 1 && page.metadata.pageLimit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && Array.isArray(page.entries) && page.entries.length <= page.metadata.pageLimit && page.hasMore === (page.nextCursor !== void 0) && (!page.hasMore || page.entries.length > 0),
|
|
948
|
+
"INVALID_CONTRACT",
|
|
949
|
+
"Unsupported or unbounded Admin Token wallet balance page"
|
|
950
|
+
);
|
|
951
|
+
if (page.metadata.filter !== void 0) {
|
|
952
|
+
assertAdminTokenWalletBalanceFilter(page.metadata.filter);
|
|
953
|
+
}
|
|
954
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
955
|
+
if (page.nextCursor !== void 0) {
|
|
956
|
+
assertOpaqueCursor(page.nextCursor);
|
|
957
|
+
}
|
|
958
|
+
const walletAliases = /* @__PURE__ */ new Set();
|
|
959
|
+
let previous;
|
|
960
|
+
for (const entry of page.entries) {
|
|
961
|
+
assertAdminTokenWalletBalanceEntry(entry);
|
|
962
|
+
const filter = page.metadata.filter;
|
|
963
|
+
economyAssert(
|
|
964
|
+
filter === void 0 || (filter.components === void 0 || filter.components.includes(entry.component)) && (filter.statuses === void 0 || filter.statuses.includes(entry.status)) && (filter.subjectAlias === void 0 || filter.subjectAlias === entry.subjectAlias),
|
|
965
|
+
"INVALID_CONTRACT",
|
|
966
|
+
"Admin Token wallet balance result contains an unrequested row"
|
|
967
|
+
);
|
|
968
|
+
economyAssert(
|
|
969
|
+
!walletAliases.has(entry.walletAlias),
|
|
970
|
+
"DUPLICATE_IDENTIFIER",
|
|
971
|
+
"Admin Token wallet balance page cannot repeat a wallet alias"
|
|
972
|
+
);
|
|
973
|
+
walletAliases.add(entry.walletAlias);
|
|
974
|
+
if (previous !== void 0) {
|
|
975
|
+
economyAssert(
|
|
976
|
+
compareWalletBalanceEntries(previous, entry, page.metadata.sort) < 0,
|
|
977
|
+
"INVALID_CONTRACT",
|
|
978
|
+
"Admin Token wallet balance page does not use its declared stable sort"
|
|
979
|
+
);
|
|
980
|
+
}
|
|
981
|
+
previous = entry;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function assertAdminTokenWalletBalancePageForRequest(page, request) {
|
|
985
|
+
assertAdminTokenWalletBalancePageRequest(request);
|
|
986
|
+
assertAdminTokenWalletBalancePage(page);
|
|
987
|
+
economyAssert(
|
|
988
|
+
page.metadata.sort === request.sort && sameWalletBalanceFilter(page.metadata.filter, request.filter) && page.metadata.pageLimit === request.limit && page.metadata.audience === request.audience && page.metadata.pseudonymVersion === request.pseudonymVersion,
|
|
989
|
+
"INVALID_CONTRACT",
|
|
990
|
+
"Admin Token wallet balance result does not match its normalized request"
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
function assertAdminTokenActivityEntry(entry) {
|
|
994
|
+
assertExactKeys(
|
|
995
|
+
entry,
|
|
996
|
+
[
|
|
997
|
+
"schemaVersion",
|
|
998
|
+
"occurredAt",
|
|
999
|
+
"activityType",
|
|
1000
|
+
"status",
|
|
1001
|
+
"source",
|
|
1002
|
+
"amount",
|
|
1003
|
+
"safeLabel",
|
|
1004
|
+
"rowAlias",
|
|
1005
|
+
"subjectAlias"
|
|
1006
|
+
],
|
|
1007
|
+
"Admin Token activity entry"
|
|
1008
|
+
);
|
|
1009
|
+
economyAssert(
|
|
1010
|
+
entry.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(entry.activityType) && ACTIVITY_STATUSES.has(entry.status) && ACTIVITY_SOURCES.has(entry.source),
|
|
1011
|
+
"INVALID_CONTRACT",
|
|
1012
|
+
"Unsupported Admin Token activity contract"
|
|
1013
|
+
);
|
|
1014
|
+
parseIsoTimestamp(entry.occurredAt);
|
|
1015
|
+
const amount = parseTokenSubunits(entry.amount);
|
|
1016
|
+
economyAssert(
|
|
1017
|
+
(amount !== 0n || entry.activityType === "failure") && (entry.activityType !== "acquisition" || amount > 0n) && (entry.activityType !== "spend" || amount < 0n),
|
|
1018
|
+
"INVALID_AMOUNT",
|
|
1019
|
+
"Admin Token activity amount has an invalid sign or zero value"
|
|
1020
|
+
);
|
|
1021
|
+
economyAssert(
|
|
1022
|
+
entry.activityType === "failure" === (entry.status === "failed"),
|
|
1023
|
+
"INVALID_CONTRACT",
|
|
1024
|
+
"Failed rows must use the failure activity type"
|
|
1025
|
+
);
|
|
1026
|
+
economyAssert(
|
|
1027
|
+
SAFE_LABELS.has(entry.safeLabel) && SAFE_LABELS_BY_ACTIVITY_TYPE[entry.activityType]?.has(entry.safeLabel) === true,
|
|
1028
|
+
"INVALID_CONTRACT",
|
|
1029
|
+
"Admin Token activity label must use the approved non-identifying allowlist"
|
|
1030
|
+
);
|
|
1031
|
+
assertAlias(entry.rowAlias, "Row alias");
|
|
1032
|
+
assertAlias(entry.subjectAlias, "Subject alias");
|
|
1033
|
+
economyAssert(
|
|
1034
|
+
entry.rowAlias !== entry.subjectAlias,
|
|
1035
|
+
"INVALID_CONTRACT",
|
|
1036
|
+
"Row and subject aliases must use separate pseudonym domains"
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
function assertAdminTokenActivityFilter(filter) {
|
|
1040
|
+
assertExactKeys(
|
|
1041
|
+
filter,
|
|
1042
|
+
[
|
|
1043
|
+
"activityTypes",
|
|
1044
|
+
"statuses",
|
|
1045
|
+
"sources",
|
|
1046
|
+
"subjectAlias"
|
|
1047
|
+
],
|
|
1048
|
+
"Admin Token activity filter"
|
|
1049
|
+
);
|
|
1050
|
+
if (filter.activityTypes !== void 0) {
|
|
1051
|
+
assertUniqueValues(
|
|
1052
|
+
filter.activityTypes,
|
|
1053
|
+
ACTIVITY_TYPES,
|
|
1054
|
+
"Admin Token activity types"
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
if (filter.statuses !== void 0) {
|
|
1058
|
+
assertUniqueValues(
|
|
1059
|
+
filter.statuses,
|
|
1060
|
+
ACTIVITY_STATUSES,
|
|
1061
|
+
"Admin Token activity statuses"
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
if (filter.sources !== void 0) {
|
|
1065
|
+
assertUniqueValues(
|
|
1066
|
+
filter.sources,
|
|
1067
|
+
ACTIVITY_SOURCES,
|
|
1068
|
+
"Admin Token activity sources"
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
if (filter.subjectAlias !== void 0) {
|
|
1072
|
+
assertAlias(filter.subjectAlias, "Subject alias filter");
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
function sameOptionalValues(left, right) {
|
|
1076
|
+
if (left === void 0 || right === void 0) {
|
|
1077
|
+
return left === right;
|
|
1078
|
+
}
|
|
1079
|
+
return left.length === right.length && left.every((value) => right.includes(value));
|
|
1080
|
+
}
|
|
1081
|
+
function sameActivityFilter(left, right) {
|
|
1082
|
+
if (left === void 0 || right === void 0) {
|
|
1083
|
+
return left === right;
|
|
1084
|
+
}
|
|
1085
|
+
return sameOptionalValues(left.activityTypes, right.activityTypes) && sameOptionalValues(left.statuses, right.statuses) && sameOptionalValues(left.sources, right.sources) && left.subjectAlias === right.subjectAlias;
|
|
1086
|
+
}
|
|
1087
|
+
function assertAdminTokenActivityCursorBinding(binding) {
|
|
1088
|
+
assertExactKeys(
|
|
1089
|
+
binding,
|
|
1090
|
+
[
|
|
1091
|
+
"schemaVersion",
|
|
1092
|
+
"sort",
|
|
1093
|
+
"window",
|
|
1094
|
+
"filter",
|
|
1095
|
+
"audience",
|
|
1096
|
+
"pseudonymVersion"
|
|
1097
|
+
],
|
|
1098
|
+
"Admin Token activity cursor binding"
|
|
1099
|
+
);
|
|
1100
|
+
economyAssert(
|
|
1101
|
+
binding.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_SORTS.has(binding.sort) && PSEUDONYM_AUDIENCES.has(binding.audience) && PSEUDONYM_VERSION.test(binding.pseudonymVersion),
|
|
1102
|
+
"INVALID_CONTRACT",
|
|
1103
|
+
"Unsupported Admin Token activity cursor binding"
|
|
1104
|
+
);
|
|
1105
|
+
assertReportingWindow(binding.window);
|
|
1106
|
+
if (binding.filter !== void 0) {
|
|
1107
|
+
assertAdminTokenActivityFilter(binding.filter);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function assertAdminTokenActivityPageRequest(request) {
|
|
1111
|
+
assertExactKeys(
|
|
1112
|
+
request,
|
|
1113
|
+
[
|
|
1114
|
+
"schemaVersion",
|
|
1115
|
+
"limit",
|
|
1116
|
+
"cursor",
|
|
1117
|
+
"cursorBinding",
|
|
1118
|
+
"sort",
|
|
1119
|
+
"window",
|
|
1120
|
+
"filter",
|
|
1121
|
+
"audience",
|
|
1122
|
+
"pseudonymVersion"
|
|
1123
|
+
],
|
|
1124
|
+
"Admin Token activity request"
|
|
1125
|
+
);
|
|
1126
|
+
economyAssert(
|
|
1127
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && Number.isSafeInteger(request.limit) && request.limit >= 1 && request.limit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE && ACTIVITY_SORTS.has(request.sort) && PSEUDONYM_AUDIENCES.has(request.audience) && PSEUDONYM_VERSION.test(request.pseudonymVersion),
|
|
1128
|
+
"INVALID_CONTRACT",
|
|
1129
|
+
"Unsupported or unbounded Admin Token activity request"
|
|
1130
|
+
);
|
|
1131
|
+
assertReportingWindow(request.window);
|
|
1132
|
+
if (request.filter !== void 0) {
|
|
1133
|
+
assertAdminTokenActivityFilter(request.filter);
|
|
1134
|
+
}
|
|
1135
|
+
economyAssert(
|
|
1136
|
+
request.cursor === void 0 === (request.cursorBinding === void 0),
|
|
1137
|
+
"INVALID_CONTRACT",
|
|
1138
|
+
"Admin Token activity cursor and trusted binding must be provided together"
|
|
1139
|
+
);
|
|
1140
|
+
if (request.cursor === void 0 || request.cursorBinding === void 0) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
assertOpaqueCursor(request.cursor);
|
|
1144
|
+
assertAdminTokenActivityCursorBinding(request.cursorBinding);
|
|
1145
|
+
economyAssert(
|
|
1146
|
+
request.cursorBinding.sort === request.sort && request.cursorBinding.window.fromInclusive === request.window.fromInclusive && request.cursorBinding.window.toExclusive === request.window.toExclusive && request.cursorBinding.audience === request.audience && request.cursorBinding.pseudonymVersion === request.pseudonymVersion && sameActivityFilter(request.cursorBinding.filter, request.filter),
|
|
1147
|
+
"INVALID_CONTRACT",
|
|
1148
|
+
"Admin Token cursor is not bound to the normalized query"
|
|
1149
|
+
);
|
|
1150
|
+
}
|
|
1151
|
+
function compareActivityEntries(left, right, sort) {
|
|
1152
|
+
if (sort === "amount-absolute-desc") {
|
|
1153
|
+
const leftAmount = absolute(parseTokenSubunits(left.amount));
|
|
1154
|
+
const rightAmount = absolute(parseTokenSubunits(right.amount));
|
|
1155
|
+
if (leftAmount !== rightAmount) {
|
|
1156
|
+
return leftAmount > rightAmount ? -1 : 1;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
const leftTime = parseIsoTimestamp(left.occurredAt);
|
|
1160
|
+
const rightTime = parseIsoTimestamp(right.occurredAt);
|
|
1161
|
+
if (leftTime !== rightTime) {
|
|
1162
|
+
return leftTime > rightTime ? -1 : 1;
|
|
1163
|
+
}
|
|
1164
|
+
return compareTextDescending(left.rowAlias, right.rowAlias);
|
|
1165
|
+
}
|
|
1166
|
+
function assertAdminTokenActivityPage(page) {
|
|
1167
|
+
assertExactKeys(
|
|
1168
|
+
page,
|
|
1169
|
+
["schemaVersion", "entries", "hasMore", "nextCursor", "metadata"],
|
|
1170
|
+
"Admin Token activity page"
|
|
1171
|
+
);
|
|
1172
|
+
assertExactKeys(
|
|
1173
|
+
page.metadata,
|
|
1174
|
+
[
|
|
1175
|
+
"schemaVersion",
|
|
1176
|
+
"generatedAt",
|
|
1177
|
+
"fromInclusive",
|
|
1178
|
+
"toExclusive",
|
|
1179
|
+
"sort",
|
|
1180
|
+
"filter",
|
|
1181
|
+
"pageLimit",
|
|
1182
|
+
"audience",
|
|
1183
|
+
"pseudonymVersion",
|
|
1184
|
+
"rawIdentifiersIncluded"
|
|
1185
|
+
],
|
|
1186
|
+
"Admin Token activity metadata"
|
|
1187
|
+
);
|
|
1188
|
+
economyAssert(
|
|
1189
|
+
page.schemaVersion === ECONOMY_CONTRACT_VERSION && page.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && typeof page.hasMore === "boolean" && page.metadata.rawIdentifiersIncluded === false && ACTIVITY_SORTS.has(page.metadata.sort) && PSEUDONYM_AUDIENCES.has(page.metadata.audience) && PSEUDONYM_VERSION.test(page.metadata.pseudonymVersion) && Number.isSafeInteger(page.metadata.pageLimit) && page.metadata.pageLimit >= 1 && page.metadata.pageLimit <= ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
1190
|
+
"INVALID_CONTRACT",
|
|
1191
|
+
"Unsupported Admin Token activity result metadata"
|
|
1192
|
+
);
|
|
1193
|
+
const window = assertReportingWindow({
|
|
1194
|
+
fromInclusive: page.metadata.fromInclusive,
|
|
1195
|
+
toExclusive: page.metadata.toExclusive
|
|
1196
|
+
});
|
|
1197
|
+
if (page.metadata.filter !== void 0) {
|
|
1198
|
+
assertAdminTokenActivityFilter(page.metadata.filter);
|
|
1199
|
+
}
|
|
1200
|
+
parseIsoTimestamp(page.metadata.generatedAt);
|
|
1201
|
+
economyAssert(
|
|
1202
|
+
Array.isArray(page.entries) && page.entries.length <= page.metadata.pageLimit && page.hasMore === (page.nextCursor !== void 0) && (!page.hasMore || page.entries.length > 0),
|
|
1203
|
+
"INVALID_CONTRACT",
|
|
1204
|
+
"Admin Token activity page is unbounded or has inconsistent pagination"
|
|
1205
|
+
);
|
|
1206
|
+
if (page.nextCursor !== void 0) {
|
|
1207
|
+
assertOpaqueCursor(page.nextCursor);
|
|
1208
|
+
}
|
|
1209
|
+
const rowAliases = /* @__PURE__ */ new Set();
|
|
1210
|
+
let previous;
|
|
1211
|
+
for (const entry of page.entries) {
|
|
1212
|
+
assertAdminTokenActivityEntry(entry);
|
|
1213
|
+
const occurredAt = parseIsoTimestamp(entry.occurredAt);
|
|
1214
|
+
economyAssert(
|
|
1215
|
+
occurredAt >= window.from && occurredAt < window.to,
|
|
1216
|
+
"INVALID_TIME_WINDOW",
|
|
1217
|
+
"Admin Token activity falls outside the declared result window"
|
|
1218
|
+
);
|
|
1219
|
+
const filter = page.metadata.filter;
|
|
1220
|
+
economyAssert(
|
|
1221
|
+
filter === void 0 || (filter.activityTypes === void 0 || filter.activityTypes.includes(entry.activityType)) && (filter.statuses === void 0 || filter.statuses.includes(entry.status)) && (filter.sources === void 0 || filter.sources.includes(entry.source)) && (filter.subjectAlias === void 0 || filter.subjectAlias === entry.subjectAlias),
|
|
1222
|
+
"INVALID_CONTRACT",
|
|
1223
|
+
"Admin Token activity result contains a row outside its metadata filters"
|
|
1224
|
+
);
|
|
1225
|
+
economyAssert(
|
|
1226
|
+
!rowAliases.has(entry.rowAlias),
|
|
1227
|
+
"DUPLICATE_IDENTIFIER",
|
|
1228
|
+
"Admin Token activity page cannot repeat a row alias"
|
|
1229
|
+
);
|
|
1230
|
+
rowAliases.add(entry.rowAlias);
|
|
1231
|
+
if (previous !== void 0) {
|
|
1232
|
+
economyAssert(
|
|
1233
|
+
compareActivityEntries(previous, entry, page.metadata.sort) < 0,
|
|
1234
|
+
"INVALID_CONTRACT",
|
|
1235
|
+
"Admin Token activity page does not use its declared stable sort"
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
previous = entry;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
function assertAdminTokenActivityPageForRequest(page, request) {
|
|
1242
|
+
assertAdminTokenActivityPageRequest(request);
|
|
1243
|
+
assertAdminTokenActivityPage(page);
|
|
1244
|
+
economyAssert(
|
|
1245
|
+
page.metadata.fromInclusive === request.window.fromInclusive && page.metadata.toExclusive === request.window.toExclusive && page.metadata.sort === request.sort && sameActivityFilter(page.metadata.filter, request.filter) && page.metadata.pageLimit === request.limit && page.metadata.audience === request.audience && page.metadata.pseudonymVersion === request.pseudonymVersion,
|
|
1246
|
+
"INVALID_CONTRACT",
|
|
1247
|
+
"Admin Token activity result metadata does not match its normalized request"
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
function assertAdminTokenTrendRequest(request) {
|
|
1251
|
+
assertExactKeys(
|
|
1252
|
+
request,
|
|
1253
|
+
["schemaVersion", "window", "granularity", "activityTypes"],
|
|
1254
|
+
"Admin Token trend request"
|
|
1255
|
+
);
|
|
1256
|
+
economyAssert(
|
|
1257
|
+
request.schemaVersion === ECONOMY_CONTRACT_VERSION && TREND_GRANULARITIES.has(request.granularity),
|
|
1258
|
+
"INVALID_CONTRACT",
|
|
1259
|
+
"Unsupported Admin Token trend request"
|
|
1260
|
+
);
|
|
1261
|
+
assertReportingWindow(
|
|
1262
|
+
request.window,
|
|
1263
|
+
request.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1264
|
+
);
|
|
1265
|
+
if (request.activityTypes !== void 0) {
|
|
1266
|
+
assertUniqueValues(
|
|
1267
|
+
request.activityTypes,
|
|
1268
|
+
ACTIVITY_TYPES,
|
|
1269
|
+
"Admin Token trend activity types"
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
function medianHalfSubunits(values) {
|
|
1274
|
+
const ordered = [...values].sort(
|
|
1275
|
+
(left, right) => left === right ? 0 : left < right ? -1 : 1
|
|
1276
|
+
);
|
|
1277
|
+
const lower = ordered[Math.floor((ordered.length - 1) / 2)];
|
|
1278
|
+
const upper = ordered[Math.floor(ordered.length / 2)];
|
|
1279
|
+
economyAssert(
|
|
1280
|
+
lower !== void 0 && upper !== void 0,
|
|
1281
|
+
"INVALID_CONTRACT",
|
|
1282
|
+
"Median requires at least one value"
|
|
1283
|
+
);
|
|
1284
|
+
const sum = lower + upper;
|
|
1285
|
+
economyAssert(
|
|
1286
|
+
sum % 2n === 0n,
|
|
1287
|
+
"INVALID_AMOUNT",
|
|
1288
|
+
"Median cannot be represented in exact half TokenSubunits"
|
|
1289
|
+
);
|
|
1290
|
+
return sum / 2n;
|
|
1291
|
+
}
|
|
1292
|
+
function serializeExactStatistic(halfSubunits) {
|
|
1293
|
+
economyAssert(
|
|
1294
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1295
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1296
|
+
"Admin Token statistic exceeds its exact bounded representation"
|
|
1297
|
+
);
|
|
1298
|
+
if (halfSubunits % 2n === 0n) {
|
|
1299
|
+
return {
|
|
1300
|
+
numerator: (halfSubunits / 2n).toString(10),
|
|
1301
|
+
denominator: 1
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
numerator: halfSubunits.toString(10),
|
|
1306
|
+
denominator: 2
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
function parseExactStatistic(value, label) {
|
|
1310
|
+
assertExactKeys(value, ["numerator", "denominator"], label);
|
|
1311
|
+
economyAssert(
|
|
1312
|
+
typeof value.numerator === "string" && value.numerator.length <= 22 && EXACT_STATISTIC_INTEGER.test(value.numerator) && (value.denominator === 1 || value.denominator === 2),
|
|
1313
|
+
"INVALID_AMOUNT",
|
|
1314
|
+
`${label} must be an exact bounded rational TokenSubunit value`
|
|
1315
|
+
);
|
|
1316
|
+
const numerator = BigInt(value.numerator);
|
|
1317
|
+
economyAssert(
|
|
1318
|
+
value.denominator === 1 || numerator % 2n !== 0n,
|
|
1319
|
+
"INVALID_AMOUNT",
|
|
1320
|
+
`${label} must use a reduced exact representation`
|
|
1321
|
+
);
|
|
1322
|
+
const halfSubunits = numerator * BigInt(2 / value.denominator);
|
|
1323
|
+
economyAssert(
|
|
1324
|
+
absolute(halfSubunits) <= MAXIMUM_STATISTIC_HALF_SUBUNITS,
|
|
1325
|
+
"AMOUNT_OUT_OF_RANGE",
|
|
1326
|
+
`${label} exceeds its exact bounded representation`
|
|
1327
|
+
);
|
|
1328
|
+
return halfSubunits;
|
|
1329
|
+
}
|
|
1330
|
+
function classifyAnomaly(options) {
|
|
1331
|
+
if (options.absoluteDeltaHalfSubunits < options.minimumAbsoluteDeltaHalfSubunits) {
|
|
1332
|
+
return {
|
|
1333
|
+
status: "normal",
|
|
1334
|
+
explanationCode: "below-absolute-minimum"
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
if (options.medianAbsoluteDeviationHalfSubunits === 0n) {
|
|
1338
|
+
return options.absoluteDeltaHalfSubunits > 0n ? {
|
|
1339
|
+
status: "irregular-spike",
|
|
1340
|
+
explanationCode: "zero-mad-absolute-threshold-exceeded"
|
|
1341
|
+
} : {
|
|
1342
|
+
status: "normal",
|
|
1343
|
+
explanationCode: "within-baseline-variation"
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
const exceedsBaseline = options.absoluteDeltaHalfSubunits * 1000n >= options.medianAbsoluteDeviationHalfSubunits * BigInt(options.madMultiplierMilli);
|
|
1347
|
+
return exceedsBaseline ? {
|
|
1348
|
+
status: "irregular-spike",
|
|
1349
|
+
explanationCode: "median-mad-and-absolute-threshold-exceeded"
|
|
1350
|
+
} : {
|
|
1351
|
+
status: "normal",
|
|
1352
|
+
explanationCode: "within-baseline-variation"
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
function createAdminTokenAnomalyIndicator(input) {
|
|
1356
|
+
assertExactKeys(
|
|
1357
|
+
input,
|
|
1358
|
+
[
|
|
1359
|
+
"observedAmount",
|
|
1360
|
+
"baselineSamples",
|
|
1361
|
+
"minimumAbsoluteDelta",
|
|
1362
|
+
"madMultiplierMilli"
|
|
1363
|
+
],
|
|
1364
|
+
"Admin Token anomaly input"
|
|
1365
|
+
);
|
|
1366
|
+
economyAssert(
|
|
1367
|
+
Array.isArray(input.baselineSamples) && input.baselineSamples.length === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && Number.isSafeInteger(input.madMultiplierMilli) && input.madMultiplierMilli >= 1 && input.madMultiplierMilli <= 1e6,
|
|
1368
|
+
"INVALID_CONTRACT",
|
|
1369
|
+
"Admin Token anomaly input requires 28 baselines and a bounded fixed-point multiplier"
|
|
1370
|
+
);
|
|
1371
|
+
const observed = parseTokenSubunits(input.observedAmount);
|
|
1372
|
+
const baseline = input.baselineSamples.map((sample) => {
|
|
1373
|
+
assertExactKeys(
|
|
1374
|
+
sample,
|
|
1375
|
+
["amount", "distinctSubjects"],
|
|
1376
|
+
"Admin Token anomaly baseline sample"
|
|
1377
|
+
);
|
|
1378
|
+
economyAssert(
|
|
1379
|
+
Number.isSafeInteger(sample.distinctSubjects) && sample.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1380
|
+
"INVALID_CONTRACT",
|
|
1381
|
+
"Admin Token anomaly baselines must exclude privacy-suppressed cohorts"
|
|
1382
|
+
);
|
|
1383
|
+
return parseTokenSubunits(sample.amount);
|
|
1384
|
+
});
|
|
1385
|
+
const minimum = parseTokenSubunits(input.minimumAbsoluteDelta);
|
|
1386
|
+
economyAssert(
|
|
1387
|
+
minimum > 0n,
|
|
1388
|
+
"INVALID_AMOUNT",
|
|
1389
|
+
"Admin Token anomaly absolute minimum must be positive"
|
|
1390
|
+
);
|
|
1391
|
+
const baselineHalfSubunits = baseline.map((amount) => amount * 2n);
|
|
1392
|
+
const medianHalf = medianHalfSubunits(baselineHalfSubunits);
|
|
1393
|
+
const medianAbsoluteDeviationHalf = medianHalfSubunits(
|
|
1394
|
+
baselineHalfSubunits.map((amount) => absolute(amount - medianHalf))
|
|
1395
|
+
);
|
|
1396
|
+
const deviationHalf = observed * 2n - medianHalf;
|
|
1397
|
+
const classification = classifyAnomaly({
|
|
1398
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1399
|
+
medianAbsoluteDeviationHalfSubunits: medianAbsoluteDeviationHalf,
|
|
1400
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1401
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1402
|
+
});
|
|
1403
|
+
return {
|
|
1404
|
+
method: "same-window-median-mad-v1",
|
|
1405
|
+
...classification,
|
|
1406
|
+
baselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1407
|
+
medianAmount: serializeExactStatistic(medianHalf),
|
|
1408
|
+
medianAbsoluteDeviation: serializeExactStatistic(medianAbsoluteDeviationHalf),
|
|
1409
|
+
minimumAbsoluteDelta: input.minimumAbsoluteDelta,
|
|
1410
|
+
deviationFromMedian: serializeExactStatistic(deviationHalf),
|
|
1411
|
+
madMultiplierMilli: input.madMultiplierMilli
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function createAdminTokenAnomalyUnavailable(input) {
|
|
1415
|
+
assertExactKeys(
|
|
1416
|
+
input,
|
|
1417
|
+
["reason", "eligibleBaselineWindowCount"],
|
|
1418
|
+
"Unavailable Admin Token anomaly input"
|
|
1419
|
+
);
|
|
1420
|
+
economyAssert(
|
|
1421
|
+
ANOMALY_UNAVAILABLE_REASONS.has(input.reason) && Number.isSafeInteger(input.eligibleBaselineWindowCount) && input.eligibleBaselineWindowCount >= 0 && input.eligibleBaselineWindowCount < ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1422
|
+
"INVALID_CONTRACT",
|
|
1423
|
+
"Unavailable Admin Token anomaly requires a bounded reason and eligible baseline count"
|
|
1424
|
+
);
|
|
1425
|
+
return {
|
|
1426
|
+
method: "same-window-median-mad-v1",
|
|
1427
|
+
status: "unavailable",
|
|
1428
|
+
reason: input.reason,
|
|
1429
|
+
eligibleBaselineWindowCount: input.eligibleBaselineWindowCount,
|
|
1430
|
+
requiredBaselineWindowCount: ADMIN_TOKEN_ANOMALY_BASELINE_DAYS
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
function assertAdminTokenAnomalyIndicator(anomaly, observedAmount) {
|
|
1434
|
+
assertExactKeys(
|
|
1435
|
+
anomaly,
|
|
1436
|
+
[
|
|
1437
|
+
"method",
|
|
1438
|
+
"status",
|
|
1439
|
+
"baselineWindowCount",
|
|
1440
|
+
"medianAmount",
|
|
1441
|
+
"medianAbsoluteDeviation",
|
|
1442
|
+
"minimumAbsoluteDelta",
|
|
1443
|
+
"deviationFromMedian",
|
|
1444
|
+
"madMultiplierMilli",
|
|
1445
|
+
"explanationCode"
|
|
1446
|
+
],
|
|
1447
|
+
"Admin Token anomaly indicator"
|
|
1448
|
+
);
|
|
1449
|
+
const observed = parseTokenSubunits(observedAmount);
|
|
1450
|
+
const medianHalf = parseExactStatistic(
|
|
1451
|
+
anomaly.medianAmount,
|
|
1452
|
+
"Admin Token anomaly median"
|
|
1453
|
+
);
|
|
1454
|
+
const madHalf = parseExactStatistic(
|
|
1455
|
+
anomaly.medianAbsoluteDeviation,
|
|
1456
|
+
"Admin Token anomaly median absolute deviation"
|
|
1457
|
+
);
|
|
1458
|
+
const minimum = parseTokenSubunits(anomaly.minimumAbsoluteDelta);
|
|
1459
|
+
const deviationHalf = parseExactStatistic(
|
|
1460
|
+
anomaly.deviationFromMedian,
|
|
1461
|
+
"Admin Token anomaly deviation"
|
|
1462
|
+
);
|
|
1463
|
+
economyAssert(
|
|
1464
|
+
anomaly.method === "same-window-median-mad-v1" && anomaly.baselineWindowCount === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && medianHalf >= TOKEN_SUBUNITS_MIN * 2n && medianHalf <= TOKEN_SUBUNITS_MAX * 2n && madHalf >= 0n && minimum > 0n && Number.isSafeInteger(anomaly.madMultiplierMilli) && anomaly.madMultiplierMilli >= 1 && anomaly.madMultiplierMilli <= 1e6 && deviationHalf === observed * 2n - medianHalf,
|
|
1465
|
+
"INVALID_CONTRACT",
|
|
1466
|
+
"Admin Token anomaly arithmetic or method is invalid"
|
|
1467
|
+
);
|
|
1468
|
+
const expected = classifyAnomaly({
|
|
1469
|
+
absoluteDeltaHalfSubunits: absolute(deviationHalf),
|
|
1470
|
+
medianAbsoluteDeviationHalfSubunits: madHalf,
|
|
1471
|
+
minimumAbsoluteDeltaHalfSubunits: minimum * 2n,
|
|
1472
|
+
madMultiplierMilli: anomaly.madMultiplierMilli
|
|
1473
|
+
});
|
|
1474
|
+
economyAssert(
|
|
1475
|
+
anomaly.status === expected.status && anomaly.explanationCode === expected.explanationCode,
|
|
1476
|
+
"INVALID_CONTRACT",
|
|
1477
|
+
"Admin Token anomaly classification is inconsistent with its explanation"
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
function assertAdminTokenAnomalyUnavailable(anomaly) {
|
|
1481
|
+
assertExactKeys(
|
|
1482
|
+
anomaly,
|
|
1483
|
+
[
|
|
1484
|
+
"method",
|
|
1485
|
+
"status",
|
|
1486
|
+
"reason",
|
|
1487
|
+
"eligibleBaselineWindowCount",
|
|
1488
|
+
"requiredBaselineWindowCount"
|
|
1489
|
+
],
|
|
1490
|
+
"Unavailable Admin Token anomaly"
|
|
1491
|
+
);
|
|
1492
|
+
economyAssert(
|
|
1493
|
+
anomaly.method === "same-window-median-mad-v1" && anomaly.status === "unavailable" && ANOMALY_UNAVAILABLE_REASONS.has(anomaly.reason) && Number.isSafeInteger(anomaly.eligibleBaselineWindowCount) && anomaly.eligibleBaselineWindowCount >= 0 && anomaly.eligibleBaselineWindowCount < ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && anomaly.requiredBaselineWindowCount === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
1494
|
+
"INVALID_CONTRACT",
|
|
1495
|
+
"Unavailable Admin Token anomaly metadata is invalid"
|
|
1496
|
+
);
|
|
1497
|
+
}
|
|
1498
|
+
function assertTrendBucketAlignment(start, end, granularity) {
|
|
1499
|
+
const expectedDuration = granularity === "hour" ? HOUR_MILLISECONDS : DAY_MILLISECONDS;
|
|
1500
|
+
const date = new Date(start);
|
|
1501
|
+
const aligned = date.getUTCMinutes() === 0 && date.getUTCSeconds() === 0 && date.getUTCMilliseconds() === 0 && (granularity === "hour" || date.getUTCHours() === 0);
|
|
1502
|
+
economyAssert(
|
|
1503
|
+
aligned && end - start === expectedDuration,
|
|
1504
|
+
"INVALID_TIME_WINDOW",
|
|
1505
|
+
"Admin Token trend bucket is not aligned to its declared granularity"
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
function assertTrendAggregate(aggregate) {
|
|
1509
|
+
assertPlainObject(aggregate, "Admin Token trend aggregate");
|
|
1510
|
+
if (aggregate.visibility === "suppressed") {
|
|
1511
|
+
assertExactKeys(
|
|
1512
|
+
aggregate,
|
|
1513
|
+
["visibility", "reason", "threshold"],
|
|
1514
|
+
"Suppressed Admin Token trend aggregate"
|
|
1515
|
+
);
|
|
1516
|
+
economyAssert(
|
|
1517
|
+
aggregate.reason === "cohort-below-minimum" && aggregate.threshold === ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
1518
|
+
"INVALID_CONTRACT",
|
|
1519
|
+
"Suppressed Admin Token trend aggregate has invalid privacy metadata"
|
|
1520
|
+
);
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
assertExactKeys(
|
|
1524
|
+
aggregate,
|
|
1525
|
+
[
|
|
1526
|
+
"visibility",
|
|
1527
|
+
"distinctSubjects",
|
|
1528
|
+
"activityCount",
|
|
1529
|
+
"signedAmount"
|
|
1530
|
+
],
|
|
1531
|
+
"Reported Admin Token trend aggregate"
|
|
1532
|
+
);
|
|
1533
|
+
parseTokenSubunits(aggregate.signedAmount);
|
|
1534
|
+
economyAssert(
|
|
1535
|
+
aggregate.visibility === "reported" && Number.isSafeInteger(aggregate.distinctSubjects) && aggregate.distinctSubjects >= ADMIN_TOKEN_MINIMUM_COHORT_SIZE && Number.isSafeInteger(aggregate.activityCount) && aggregate.activityCount >= aggregate.distinctSubjects,
|
|
1536
|
+
"INVALID_CONTRACT",
|
|
1537
|
+
"Reported Admin Token trend aggregate is invalid or below the privacy threshold"
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
function assertAdminTokenTrendResult(result) {
|
|
1541
|
+
assertExactKeys(
|
|
1542
|
+
result,
|
|
1543
|
+
["schemaVersion", "series", "metadata"],
|
|
1544
|
+
"Admin Token trend result"
|
|
1545
|
+
);
|
|
1546
|
+
assertExactKeys(
|
|
1547
|
+
result.metadata,
|
|
1548
|
+
[
|
|
1549
|
+
"schemaVersion",
|
|
1550
|
+
"generatedAt",
|
|
1551
|
+
"fromInclusive",
|
|
1552
|
+
"toExclusive",
|
|
1553
|
+
"granularity",
|
|
1554
|
+
"activityTypes",
|
|
1555
|
+
"minimumCohortSize",
|
|
1556
|
+
"anomalyBaselineDays",
|
|
1557
|
+
"rawIdentifiersIncluded"
|
|
1558
|
+
],
|
|
1559
|
+
"Admin Token trend metadata"
|
|
1560
|
+
);
|
|
1561
|
+
economyAssert(
|
|
1562
|
+
result.schemaVersion === ECONOMY_CONTRACT_VERSION && result.metadata.schemaVersion === ECONOMY_CONTRACT_VERSION && TREND_GRANULARITIES.has(result.metadata.granularity) && result.metadata.minimumCohortSize === ADMIN_TOKEN_MINIMUM_COHORT_SIZE && result.metadata.anomalyBaselineDays === ADMIN_TOKEN_ANOMALY_BASELINE_DAYS && result.metadata.rawIdentifiersIncluded === false && Array.isArray(result.series) && result.series.length <= ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
1563
|
+
"INVALID_CONTRACT",
|
|
1564
|
+
"Unsupported or unbounded Admin Token trend result"
|
|
1565
|
+
);
|
|
1566
|
+
assertUniqueValues(
|
|
1567
|
+
result.metadata.activityTypes,
|
|
1568
|
+
ACTIVITY_TYPES,
|
|
1569
|
+
"Admin Token trend result activity types"
|
|
1570
|
+
);
|
|
1571
|
+
const window = assertReportingWindow(
|
|
1572
|
+
{
|
|
1573
|
+
fromInclusive: result.metadata.fromInclusive,
|
|
1574
|
+
toExclusive: result.metadata.toExclusive
|
|
1575
|
+
},
|
|
1576
|
+
result.metadata.granularity === "hour" ? ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS : ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS
|
|
1577
|
+
);
|
|
1578
|
+
parseIsoTimestamp(result.metadata.generatedAt);
|
|
1579
|
+
const pointKeys = /* @__PURE__ */ new Set();
|
|
1580
|
+
let previousKey;
|
|
1581
|
+
for (const point of result.series) {
|
|
1582
|
+
assertExactKeys(
|
|
1583
|
+
point,
|
|
1584
|
+
[
|
|
1585
|
+
"schemaVersion",
|
|
1586
|
+
"bucketStart",
|
|
1587
|
+
"bucketEnd",
|
|
1588
|
+
"activityType",
|
|
1589
|
+
"aggregate",
|
|
1590
|
+
"anomaly"
|
|
1591
|
+
],
|
|
1592
|
+
"Admin Token trend point"
|
|
1593
|
+
);
|
|
1594
|
+
economyAssert(
|
|
1595
|
+
point.schemaVersion === ECONOMY_CONTRACT_VERSION && ACTIVITY_TYPES.has(point.activityType) && result.metadata.activityTypes.includes(point.activityType),
|
|
1596
|
+
"INVALID_CONTRACT",
|
|
1597
|
+
"Unsupported Admin Token trend point"
|
|
1598
|
+
);
|
|
1599
|
+
const start = parseIsoTimestamp(point.bucketStart);
|
|
1600
|
+
const end = parseIsoTimestamp(point.bucketEnd);
|
|
1601
|
+
economyAssert(
|
|
1602
|
+
start >= window.from && end <= window.to,
|
|
1603
|
+
"INVALID_TIME_WINDOW",
|
|
1604
|
+
"Admin Token trend bucket falls outside the declared result window"
|
|
1605
|
+
);
|
|
1606
|
+
assertTrendBucketAlignment(start, end, result.metadata.granularity);
|
|
1607
|
+
assertTrendAggregate(point.aggregate);
|
|
1608
|
+
if (point.aggregate.visibility === "suppressed") {
|
|
1609
|
+
economyAssert(
|
|
1610
|
+
point.anomaly === void 0,
|
|
1611
|
+
"INVALID_CONTRACT",
|
|
1612
|
+
"Suppressed Admin Token cohorts cannot include anomaly details"
|
|
1613
|
+
);
|
|
1614
|
+
} else {
|
|
1615
|
+
economyAssert(
|
|
1616
|
+
point.anomaly !== void 0,
|
|
1617
|
+
"INVALID_CONTRACT",
|
|
1618
|
+
"Reported Admin Token cohorts require an anomaly result"
|
|
1619
|
+
);
|
|
1620
|
+
if (point.anomaly.status === "unavailable") {
|
|
1621
|
+
assertAdminTokenAnomalyUnavailable(point.anomaly);
|
|
1622
|
+
} else {
|
|
1623
|
+
assertAdminTokenAnomalyIndicator(
|
|
1624
|
+
point.anomaly,
|
|
1625
|
+
point.aggregate.signedAmount
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
const key = `${point.bucketStart}\0${point.activityType}`;
|
|
1630
|
+
economyAssert(
|
|
1631
|
+
!pointKeys.has(key) && (previousKey === void 0 || previousKey < key),
|
|
1632
|
+
"DUPLICATE_IDENTIFIER",
|
|
1633
|
+
"Admin Token trend points must be unique and stably ordered"
|
|
1634
|
+
);
|
|
1635
|
+
pointKeys.add(key);
|
|
1636
|
+
previousKey = key;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function assertAdminTokenTrendResultForRequest(result, request) {
|
|
1640
|
+
assertAdminTokenTrendRequest(request);
|
|
1641
|
+
assertAdminTokenTrendResult(result);
|
|
1642
|
+
const requestedActivityTypes = request.activityTypes ?? [...ACTIVITY_TYPES];
|
|
1643
|
+
economyAssert(
|
|
1644
|
+
result.metadata.fromInclusive === request.window.fromInclusive && result.metadata.toExclusive === request.window.toExclusive && result.metadata.granularity === request.granularity && sameOptionalValues(
|
|
1645
|
+
result.metadata.activityTypes,
|
|
1646
|
+
requestedActivityTypes
|
|
1647
|
+
),
|
|
1648
|
+
"INVALID_CONTRACT",
|
|
1649
|
+
"Admin Token trend result metadata does not match its normalized request"
|
|
1650
|
+
);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
504
1653
|
// src/allocations.ts
|
|
505
1654
|
function assertWholePositive(amount, label) {
|
|
506
1655
|
const parsed = parseTokenSubunits(amount);
|
|
@@ -837,7 +1986,7 @@ var COMMAND_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
|
837
1986
|
"acceptedRegion",
|
|
838
1987
|
"writerFencingToken"
|
|
839
1988
|
]);
|
|
840
|
-
function
|
|
1989
|
+
function assertExactKeys2(value, allowedKeys, label) {
|
|
841
1990
|
economyAssert(
|
|
842
1991
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
843
1992
|
"INVALID_CONTRACT",
|
|
@@ -881,7 +2030,7 @@ function assertRelationshipContext(relationshipId, authorizationVersion) {
|
|
|
881
2030
|
);
|
|
882
2031
|
}
|
|
883
2032
|
function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
884
|
-
|
|
2033
|
+
assertExactKeys2(
|
|
885
2034
|
fingerprint,
|
|
886
2035
|
/* @__PURE__ */ new Set([
|
|
887
2036
|
"schemaVersion",
|
|
@@ -906,7 +2055,7 @@ function assertEconomyHmacFingerprint(fingerprint, expectedDomain) {
|
|
|
906
2055
|
);
|
|
907
2056
|
}
|
|
908
2057
|
function assertEconomyAuthorizationEvidence(evidence) {
|
|
909
|
-
|
|
2058
|
+
assertExactKeys2(
|
|
910
2059
|
evidence,
|
|
911
2060
|
/* @__PURE__ */ new Set([
|
|
912
2061
|
"schemaVersion",
|
|
@@ -943,7 +2092,7 @@ function assertEconomyAuthorizationEvidence(evidence) {
|
|
|
943
2092
|
);
|
|
944
2093
|
}
|
|
945
2094
|
function assertCausationReference(causation) {
|
|
946
|
-
|
|
2095
|
+
assertExactKeys2(
|
|
947
2096
|
causation,
|
|
948
2097
|
/* @__PURE__ */ new Set(["schemaVersion", "kind", "causationId"]),
|
|
949
2098
|
"Economy causation reference"
|
|
@@ -998,7 +2147,7 @@ function assertCommandSourcePrincipal(envelope) {
|
|
|
998
2147
|
}
|
|
999
2148
|
}
|
|
1000
2149
|
function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
1001
|
-
|
|
2150
|
+
assertExactKeys2(
|
|
1002
2151
|
envelope,
|
|
1003
2152
|
COMMAND_ENVELOPE_KEYS,
|
|
1004
2153
|
"Audited economy command envelope"
|
|
@@ -1064,7 +2213,7 @@ function assertAuditedEconomyCommandEnvelope(envelope) {
|
|
|
1064
2213
|
);
|
|
1065
2214
|
}
|
|
1066
2215
|
function assertEconomyProviderEvidenceHash(evidence) {
|
|
1067
|
-
|
|
2216
|
+
assertExactKeys2(
|
|
1068
2217
|
evidence,
|
|
1069
2218
|
/* @__PURE__ */ new Set([
|
|
1070
2219
|
"schemaVersion",
|
|
@@ -1135,7 +2284,7 @@ function assertEconomyProviderEvidenceHash(evidence) {
|
|
|
1135
2284
|
}
|
|
1136
2285
|
}
|
|
1137
2286
|
function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
1138
|
-
|
|
2287
|
+
assertExactKeys2(
|
|
1139
2288
|
binding,
|
|
1140
2289
|
/* @__PURE__ */ new Set([
|
|
1141
2290
|
"schemaVersion",
|
|
@@ -1170,7 +2319,7 @@ function assertEconomyEncryptedOperationalHandleBinding(binding) {
|
|
|
1170
2319
|
parseIsoTimestamp(binding.createdAt);
|
|
1171
2320
|
}
|
|
1172
2321
|
function assertEvidenceRecordReference(reference) {
|
|
1173
|
-
|
|
2322
|
+
assertExactKeys2(
|
|
1174
2323
|
reference,
|
|
1175
2324
|
/* @__PURE__ */ new Set(["schemaVersion", "recordId", "contentHash"]),
|
|
1176
2325
|
"Evidence record reference"
|
|
@@ -1201,7 +2350,7 @@ function assertUniqueSortedReferences(references, label) {
|
|
|
1201
2350
|
}
|
|
1202
2351
|
}
|
|
1203
2352
|
function assertEconomyProviderEvidenceManifest(manifest) {
|
|
1204
|
-
|
|
2353
|
+
assertExactKeys2(
|
|
1205
2354
|
manifest,
|
|
1206
2355
|
/* @__PURE__ */ new Set([
|
|
1207
2356
|
"schemaVersion",
|
|
@@ -1243,7 +2392,7 @@ function assertEconomyProviderEvidenceManifest(manifest) {
|
|
|
1243
2392
|
parseIsoTimestamp(manifest.createdAt);
|
|
1244
2393
|
}
|
|
1245
2394
|
function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
1246
|
-
|
|
2395
|
+
assertExactKeys2(
|
|
1247
2396
|
receipt,
|
|
1248
2397
|
/* @__PURE__ */ new Set([
|
|
1249
2398
|
"schemaVersion",
|
|
@@ -1267,7 +2416,7 @@ function assertEconomyAcceptedCommandReceipt(receipt) {
|
|
|
1267
2416
|
parseIsoTimestamp(receipt.acceptedAt);
|
|
1268
2417
|
}
|
|
1269
2418
|
function assertEconomyCommandResultReceipt(receipt) {
|
|
1270
|
-
|
|
2419
|
+
assertExactKeys2(
|
|
1271
2420
|
receipt,
|
|
1272
2421
|
/* @__PURE__ */ new Set([
|
|
1273
2422
|
"schemaVersion",
|
|
@@ -1324,7 +2473,7 @@ function assertEconomyCommandResultReceipt(receipt) {
|
|
|
1324
2473
|
}
|
|
1325
2474
|
}
|
|
1326
2475
|
function assertEconomyAuditedIdempotencyScope(scope) {
|
|
1327
|
-
|
|
2476
|
+
assertExactKeys2(
|
|
1328
2477
|
scope,
|
|
1329
2478
|
/* @__PURE__ */ new Set([
|
|
1330
2479
|
"schemaVersion",
|
|
@@ -1355,7 +2504,7 @@ function assertEconomyAuditedIdempotencyScope(scope) {
|
|
|
1355
2504
|
);
|
|
1356
2505
|
}
|
|
1357
2506
|
function assertEconomyAuditedIdempotencyResult(result) {
|
|
1358
|
-
|
|
2507
|
+
assertExactKeys2(
|
|
1359
2508
|
result,
|
|
1360
2509
|
/* @__PURE__ */ new Set([
|
|
1361
2510
|
"schemaVersion",
|
|
@@ -1646,7 +2795,7 @@ var MANIFEST_KEYS = /* @__PURE__ */ new Set([
|
|
|
1646
2795
|
"recordReferences",
|
|
1647
2796
|
"committedAt"
|
|
1648
2797
|
]);
|
|
1649
|
-
function
|
|
2798
|
+
function assertExactKeys3(value, allowedKeys, label) {
|
|
1650
2799
|
economyAssert(
|
|
1651
2800
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
1652
2801
|
"INVALID_CONTRACT",
|
|
@@ -1684,7 +2833,7 @@ function referenceOrder(left, right) {
|
|
|
1684
2833
|
return byKind === 0 ? compareUnicodeCodeUnits(left.recordId, right.recordId) : byKind;
|
|
1685
2834
|
}
|
|
1686
2835
|
function assertEconomyAuthorityRecordReference(reference) {
|
|
1687
|
-
|
|
2836
|
+
assertExactKeys3(
|
|
1688
2837
|
reference,
|
|
1689
2838
|
/* @__PURE__ */ new Set([
|
|
1690
2839
|
"schemaVersion",
|
|
@@ -1848,7 +2997,7 @@ function assertCommitAllowedInState(manifest) {
|
|
|
1848
2997
|
}
|
|
1849
2998
|
}
|
|
1850
2999
|
function assertEconomyAuthorityCommitManifest(manifest) {
|
|
1851
|
-
|
|
3000
|
+
assertExactKeys3(manifest, MANIFEST_KEYS, "Authority commit manifest");
|
|
1852
3001
|
economyAssert(
|
|
1853
3002
|
manifest.schemaVersion === ECONOMY_CONTRACT_VERSION && COMMIT_KINDS.has(manifest.commitKind) && AUTHORITY_STATES.has(manifest.authorityStateBefore) && AUTHORITY_STATES.has(manifest.authorityStateAfter),
|
|
1854
3003
|
"INVALID_CONTRACT",
|
|
@@ -1895,7 +3044,7 @@ function assertEconomyAuthorityCommitManifest(manifest) {
|
|
|
1895
3044
|
parseIsoTimestamp(manifest.committedAt);
|
|
1896
3045
|
}
|
|
1897
3046
|
function assertEconomyAuthorityHead(head) {
|
|
1898
|
-
|
|
3047
|
+
assertExactKeys3(head, HEAD_KEYS, "Economy authority head");
|
|
1899
3048
|
economyAssert(
|
|
1900
3049
|
head.schemaVersion === ECONOMY_CONTRACT_VERSION && AUTHORITY_STATES.has(head.state),
|
|
1901
3050
|
"INVALID_CONTRACT",
|
|
@@ -1954,7 +3103,7 @@ function advanceEconomyAuthorityHead(head, manifest, manifestCanonicalHash) {
|
|
|
1954
3103
|
};
|
|
1955
3104
|
}
|
|
1956
3105
|
function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
1957
|
-
|
|
3106
|
+
assertExactKeys3(
|
|
1958
3107
|
receipt,
|
|
1959
3108
|
/* @__PURE__ */ new Set([
|
|
1960
3109
|
"schemaVersion",
|
|
@@ -2100,7 +3249,7 @@ function assertEconomyIntegrityVerificationReceipt(receipt) {
|
|
|
2100
3249
|
parseIsoTimestamp(receipt.verifiedAt);
|
|
2101
3250
|
}
|
|
2102
3251
|
function assertEconomyIntegrityAnchorManifest(manifest) {
|
|
2103
|
-
|
|
3252
|
+
assertExactKeys3(
|
|
2104
3253
|
manifest,
|
|
2105
3254
|
/* @__PURE__ */ new Set([
|
|
2106
3255
|
"schemaVersion",
|
|
@@ -2262,7 +3411,7 @@ function sortEconomyAuthorityRecordReferences(references) {
|
|
|
2262
3411
|
}
|
|
2263
3412
|
|
|
2264
3413
|
// src/ledger.ts
|
|
2265
|
-
var
|
|
3414
|
+
var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
2266
3415
|
"purchase",
|
|
2267
3416
|
"subscription",
|
|
2268
3417
|
"rewarded-ad",
|
|
@@ -2279,14 +3428,14 @@ var ACTIVITY_TYPES = /* @__PURE__ */ new Set([
|
|
|
2279
3428
|
"event",
|
|
2280
3429
|
"competition"
|
|
2281
3430
|
]);
|
|
2282
|
-
var
|
|
3431
|
+
var ACTIVITY_STATUSES2 = /* @__PURE__ */ new Set([
|
|
2283
3432
|
"pending",
|
|
2284
3433
|
"held",
|
|
2285
3434
|
"settled",
|
|
2286
3435
|
"reversed",
|
|
2287
3436
|
"failed"
|
|
2288
3437
|
]);
|
|
2289
|
-
var
|
|
3438
|
+
var ACTIVITY_SOURCES2 = /* @__PURE__ */ new Set([
|
|
2290
3439
|
"shopify",
|
|
2291
3440
|
"ayet",
|
|
2292
3441
|
"bitlabs",
|
|
@@ -2316,7 +3465,7 @@ function assertActivityEntry(entry) {
|
|
|
2316
3465
|
);
|
|
2317
3466
|
assertEconomyIdentifier(entry.transactionId, "transactionId");
|
|
2318
3467
|
economyAssert(
|
|
2319
|
-
|
|
3468
|
+
ACTIVITY_TYPES2.has(entry.activityType) && ACTIVITY_STATUSES2.has(entry.status) && ACTIVITY_SOURCES2.has(entry.source),
|
|
2320
3469
|
"INVALID_CONTRACT",
|
|
2321
3470
|
"Activity type, status, or source is unsupported"
|
|
2322
3471
|
);
|
|
@@ -2354,7 +3503,7 @@ function assertBalancedTransaction(transaction) {
|
|
|
2354
3503
|
assertEconomyIdentifier(transaction.transactionId, "transactionId");
|
|
2355
3504
|
assertEconomyIdentifier(transaction.idempotencyKey, "idempotencyKey");
|
|
2356
3505
|
economyAssert(
|
|
2357
|
-
|
|
3506
|
+
ACTIVITY_TYPES2.has(transaction.activityType) && ACTIVITY_STATUSES2.has(transaction.status),
|
|
2358
3507
|
"INVALID_CONTRACT",
|
|
2359
3508
|
"Transaction activity type or status is unsupported"
|
|
2360
3509
|
);
|
|
@@ -4319,6 +5468,341 @@ function assertDistinctAdjustmentApproval(request) {
|
|
|
4319
5468
|
}
|
|
4320
5469
|
}
|
|
4321
5470
|
|
|
5471
|
+
// src/operator-adjustments.ts
|
|
5472
|
+
var PREVIEW_KEYS = /* @__PURE__ */ new Set([
|
|
5473
|
+
"schemaVersion",
|
|
5474
|
+
"previewId",
|
|
5475
|
+
"adjustmentId",
|
|
5476
|
+
"operation",
|
|
5477
|
+
"targetAccountId",
|
|
5478
|
+
"targetComponent",
|
|
5479
|
+
"targetWalletId",
|
|
5480
|
+
"targetLedgerAccountId",
|
|
5481
|
+
"offsetLedgerAccountId",
|
|
5482
|
+
"sourceLotId",
|
|
5483
|
+
"amount",
|
|
5484
|
+
"reasonCode",
|
|
5485
|
+
"ticketReferenceHash",
|
|
5486
|
+
"transferPolicy",
|
|
5487
|
+
"refundPolicy",
|
|
5488
|
+
"originalSourceLotId",
|
|
5489
|
+
"originalTransactionId",
|
|
5490
|
+
"preparedAt",
|
|
5491
|
+
"expiresAt"
|
|
5492
|
+
]);
|
|
5493
|
+
var DECISION_KEYS = /* @__PURE__ */ new Set([
|
|
5494
|
+
"schemaVersion",
|
|
5495
|
+
"decisionId",
|
|
5496
|
+
"adjustmentId",
|
|
5497
|
+
"proposalId",
|
|
5498
|
+
"proposalHash",
|
|
5499
|
+
"previewHash",
|
|
5500
|
+
"decision",
|
|
5501
|
+
"proposedByAccountId",
|
|
5502
|
+
"decidedByAccountId",
|
|
5503
|
+
"proposedAt",
|
|
5504
|
+
"decidedAt"
|
|
5505
|
+
]);
|
|
5506
|
+
var PROPOSAL_KEYS = /* @__PURE__ */ new Set([
|
|
5507
|
+
"schemaVersion",
|
|
5508
|
+
"proposalId",
|
|
5509
|
+
"adjustmentId",
|
|
5510
|
+
"previewHash",
|
|
5511
|
+
"status",
|
|
5512
|
+
"proposedByAccountId",
|
|
5513
|
+
"proposedAt",
|
|
5514
|
+
"expiresAt"
|
|
5515
|
+
]);
|
|
5516
|
+
var EXECUTION_KEYS = /* @__PURE__ */ new Set([
|
|
5517
|
+
"schemaVersion",
|
|
5518
|
+
"executionId",
|
|
5519
|
+
"adjustmentId",
|
|
5520
|
+
"previewHash",
|
|
5521
|
+
"proposalHash",
|
|
5522
|
+
"decisionHash",
|
|
5523
|
+
"sourceLotId",
|
|
5524
|
+
"transactionId",
|
|
5525
|
+
"resultReceiptId",
|
|
5526
|
+
"executedAt"
|
|
5527
|
+
]);
|
|
5528
|
+
var OPERATIONS = /* @__PURE__ */ new Set([
|
|
5529
|
+
"credit",
|
|
5530
|
+
"reverse-credit"
|
|
5531
|
+
]);
|
|
5532
|
+
var TARGET_COMPONENTS = /* @__PURE__ */ new Set([
|
|
5533
|
+
"personal",
|
|
5534
|
+
"household-treasury"
|
|
5535
|
+
]);
|
|
5536
|
+
var TRANSFER_POLICIES = /* @__PURE__ */ new Set([
|
|
5537
|
+
"household-allocatable",
|
|
5538
|
+
"same-user-only",
|
|
5539
|
+
"non-transferable"
|
|
5540
|
+
]);
|
|
5541
|
+
var DECISIONS = /* @__PURE__ */ new Set([
|
|
5542
|
+
"approve",
|
|
5543
|
+
"reject"
|
|
5544
|
+
]);
|
|
5545
|
+
function assertExactKeys4(value, allowed, label) {
|
|
5546
|
+
economyAssert(
|
|
5547
|
+
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
5548
|
+
"INVALID_CONTRACT",
|
|
5549
|
+
`${label} must be an object`
|
|
5550
|
+
);
|
|
5551
|
+
economyAssert(
|
|
5552
|
+
Object.keys(value).every((key) => allowed.has(key)),
|
|
5553
|
+
"INVALID_CONTRACT",
|
|
5554
|
+
`${label} contains an unsupported field`
|
|
5555
|
+
);
|
|
5556
|
+
}
|
|
5557
|
+
function assertCanonicalHash6(value, label) {
|
|
5558
|
+
economyAssert(
|
|
5559
|
+
/^sha256:[a-f0-9]{64}$/u.test(value),
|
|
5560
|
+
"INVALID_CONTRACT",
|
|
5561
|
+
`${label} must be a canonical SHA-256 reference`
|
|
5562
|
+
);
|
|
5563
|
+
}
|
|
5564
|
+
function assertReasonCode(reasonCode) {
|
|
5565
|
+
economyAssert(
|
|
5566
|
+
/^[A-Z][A-Z0-9_]{2,95}$/u.test(reasonCode),
|
|
5567
|
+
"INVALID_CONTRACT",
|
|
5568
|
+
"Adjustment reasonCode must be a bounded uppercase identifier"
|
|
5569
|
+
);
|
|
5570
|
+
}
|
|
5571
|
+
function assertOperatorAdjustmentPreview(preview) {
|
|
5572
|
+
assertExactKeys4(preview, PREVIEW_KEYS, "Operator adjustment preview");
|
|
5573
|
+
economyAssert(
|
|
5574
|
+
preview.schemaVersion === ECONOMY_CONTRACT_VERSION && OPERATIONS.has(preview.operation) && TARGET_COMPONENTS.has(preview.targetComponent) && TRANSFER_POLICIES.has(preview.transferPolicy) && preview.refundPolicy === "not-refundable",
|
|
5575
|
+
"INVALID_CONTRACT",
|
|
5576
|
+
"Unsupported operator adjustment preview"
|
|
5577
|
+
);
|
|
5578
|
+
assertEconomyIdentifier(preview.previewId, "previewId");
|
|
5579
|
+
assertEconomyIdentifier(preview.adjustmentId, "adjustmentId");
|
|
5580
|
+
assertEconomyIdentifier(preview.targetAccountId, "targetAccountId");
|
|
5581
|
+
assertEconomyIdentifier(preview.targetWalletId, "targetWalletId");
|
|
5582
|
+
assertEconomyIdentifier(
|
|
5583
|
+
preview.targetLedgerAccountId,
|
|
5584
|
+
"targetLedgerAccountId"
|
|
5585
|
+
);
|
|
5586
|
+
assertEconomyIdentifier(
|
|
5587
|
+
preview.offsetLedgerAccountId,
|
|
5588
|
+
"offsetLedgerAccountId"
|
|
5589
|
+
);
|
|
5590
|
+
assertEconomyIdentifier(preview.sourceLotId, "sourceLotId");
|
|
5591
|
+
economyAssert(
|
|
5592
|
+
parseTokenSubunits(preview.amount) > 0n,
|
|
5593
|
+
"INVALID_AMOUNT",
|
|
5594
|
+
"Operator adjustment amount must be positive"
|
|
5595
|
+
);
|
|
5596
|
+
assertReasonCode(preview.reasonCode);
|
|
5597
|
+
assertCanonicalHash6(preview.ticketReferenceHash, "ticketReferenceHash");
|
|
5598
|
+
const preparedAt = parseIsoTimestamp(preview.preparedAt);
|
|
5599
|
+
const expiresAt = parseIsoTimestamp(preview.expiresAt);
|
|
5600
|
+
economyAssert(
|
|
5601
|
+
expiresAt > preparedAt,
|
|
5602
|
+
"INVALID_TIME_WINDOW",
|
|
5603
|
+
"Operator adjustment preview must expire after preparation"
|
|
5604
|
+
);
|
|
5605
|
+
if (preview.operation === "credit") {
|
|
5606
|
+
economyAssert(
|
|
5607
|
+
preview.originalSourceLotId === void 0 && preview.originalTransactionId === void 0,
|
|
5608
|
+
"INVALID_CONTRACT",
|
|
5609
|
+
"A credit preview cannot bind an original transaction"
|
|
5610
|
+
);
|
|
5611
|
+
return;
|
|
5612
|
+
}
|
|
5613
|
+
economyAssert(
|
|
5614
|
+
preview.originalSourceLotId !== void 0 && preview.originalTransactionId !== void 0,
|
|
5615
|
+
"INVALID_CONTRACT",
|
|
5616
|
+
"A reversal preview must bind the original lot and transaction"
|
|
5617
|
+
);
|
|
5618
|
+
assertEconomyIdentifier(preview.originalSourceLotId, "originalSourceLotId");
|
|
5619
|
+
assertEconomyIdentifier(
|
|
5620
|
+
preview.originalTransactionId,
|
|
5621
|
+
"originalTransactionId"
|
|
5622
|
+
);
|
|
5623
|
+
}
|
|
5624
|
+
function canonicalOperatorAdjustmentPreviewPayload(preview) {
|
|
5625
|
+
assertOperatorAdjustmentPreview(preview);
|
|
5626
|
+
return JSON.stringify({
|
|
5627
|
+
schemaVersion: preview.schemaVersion,
|
|
5628
|
+
previewId: preview.previewId,
|
|
5629
|
+
adjustmentId: preview.adjustmentId,
|
|
5630
|
+
operation: preview.operation,
|
|
5631
|
+
targetAccountId: preview.targetAccountId,
|
|
5632
|
+
targetComponent: preview.targetComponent,
|
|
5633
|
+
targetWalletId: preview.targetWalletId,
|
|
5634
|
+
targetLedgerAccountId: preview.targetLedgerAccountId,
|
|
5635
|
+
offsetLedgerAccountId: preview.offsetLedgerAccountId,
|
|
5636
|
+
sourceLotId: preview.sourceLotId,
|
|
5637
|
+
amount: preview.amount,
|
|
5638
|
+
reasonCode: preview.reasonCode,
|
|
5639
|
+
ticketReferenceHash: preview.ticketReferenceHash,
|
|
5640
|
+
transferPolicy: preview.transferPolicy,
|
|
5641
|
+
refundPolicy: preview.refundPolicy,
|
|
5642
|
+
...preview.originalSourceLotId === void 0 ? {} : { originalSourceLotId: preview.originalSourceLotId },
|
|
5643
|
+
...preview.originalTransactionId === void 0 ? {} : { originalTransactionId: preview.originalTransactionId },
|
|
5644
|
+
preparedAt: preview.preparedAt,
|
|
5645
|
+
expiresAt: preview.expiresAt
|
|
5646
|
+
});
|
|
5647
|
+
}
|
|
5648
|
+
function assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash) {
|
|
5649
|
+
assertOperatorAdjustmentPreview(preview);
|
|
5650
|
+
assertCanonicalHash6(expectedPreviewHash, "expectedPreviewHash");
|
|
5651
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
5652
|
+
economyAssert(
|
|
5653
|
+
proposal.schemaVersion === ECONOMY_CONTRACT_VERSION && proposal.status === "pending-approval",
|
|
5654
|
+
"INVALID_CONTRACT",
|
|
5655
|
+
"Unsupported operator adjustment proposal"
|
|
5656
|
+
);
|
|
5657
|
+
assertEconomyIdentifier(proposal.proposalId, "proposalId");
|
|
5658
|
+
assertEconomyIdentifier(proposal.adjustmentId, "adjustmentId");
|
|
5659
|
+
assertCanonicalHash6(proposal.previewHash, "previewHash");
|
|
5660
|
+
assertEconomyIdentifier(
|
|
5661
|
+
proposal.proposedByAccountId,
|
|
5662
|
+
"proposedByAccountId"
|
|
5663
|
+
);
|
|
5664
|
+
economyAssert(
|
|
5665
|
+
proposal.adjustmentId === preview.adjustmentId && proposal.previewHash === expectedPreviewHash,
|
|
5666
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
5667
|
+
"Operator adjustment proposal does not match its preview"
|
|
5668
|
+
);
|
|
5669
|
+
const proposedAt = parseIsoTimestamp(proposal.proposedAt);
|
|
5670
|
+
const expiresAt = parseIsoTimestamp(proposal.expiresAt);
|
|
5671
|
+
economyAssert(
|
|
5672
|
+
proposedAt >= parseIsoTimestamp(preview.preparedAt) && expiresAt === parseIsoTimestamp(preview.expiresAt) && expiresAt > proposedAt,
|
|
5673
|
+
"INVALID_TIME_WINDOW",
|
|
5674
|
+
"Operator adjustment proposal times are inconsistent"
|
|
5675
|
+
);
|
|
5676
|
+
}
|
|
5677
|
+
function canonicalOperatorAdjustmentProposalPayload(proposal) {
|
|
5678
|
+
assertExactKeys4(proposal, PROPOSAL_KEYS, "Operator adjustment proposal");
|
|
5679
|
+
return JSON.stringify({
|
|
5680
|
+
schemaVersion: proposal.schemaVersion,
|
|
5681
|
+
proposalId: proposal.proposalId,
|
|
5682
|
+
adjustmentId: proposal.adjustmentId,
|
|
5683
|
+
previewHash: proposal.previewHash,
|
|
5684
|
+
status: proposal.status,
|
|
5685
|
+
proposedByAccountId: proposal.proposedByAccountId,
|
|
5686
|
+
proposedAt: proposal.proposedAt,
|
|
5687
|
+
expiresAt: proposal.expiresAt
|
|
5688
|
+
});
|
|
5689
|
+
}
|
|
5690
|
+
function assertOperatorAdjustmentDecision(decision, proposal, preview, expectedPreviewHash, expectedProposalHash) {
|
|
5691
|
+
assertOperatorAdjustmentProposal(proposal, preview, expectedPreviewHash);
|
|
5692
|
+
assertCanonicalHash6(expectedProposalHash, "expectedProposalHash");
|
|
5693
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
5694
|
+
economyAssert(
|
|
5695
|
+
decision.schemaVersion === ECONOMY_CONTRACT_VERSION && DECISIONS.has(decision.decision),
|
|
5696
|
+
"INVALID_CONTRACT",
|
|
5697
|
+
"Unsupported operator adjustment decision"
|
|
5698
|
+
);
|
|
5699
|
+
assertEconomyIdentifier(decision.decisionId, "decisionId");
|
|
5700
|
+
assertEconomyIdentifier(decision.adjustmentId, "adjustmentId");
|
|
5701
|
+
assertEconomyIdentifier(decision.proposalId, "proposalId");
|
|
5702
|
+
assertCanonicalHash6(decision.proposalHash, "proposalHash");
|
|
5703
|
+
assertCanonicalHash6(decision.previewHash, "previewHash");
|
|
5704
|
+
assertEconomyIdentifier(
|
|
5705
|
+
decision.proposedByAccountId,
|
|
5706
|
+
"proposedByAccountId"
|
|
5707
|
+
);
|
|
5708
|
+
assertEconomyIdentifier(
|
|
5709
|
+
decision.decidedByAccountId,
|
|
5710
|
+
"decidedByAccountId"
|
|
5711
|
+
);
|
|
5712
|
+
economyAssert(
|
|
5713
|
+
decision.proposedByAccountId !== decision.decidedByAccountId,
|
|
5714
|
+
"ADJUSTMENT_SELF_APPROVAL",
|
|
5715
|
+
"Operator adjustment approval requires a distinct operator"
|
|
5716
|
+
);
|
|
5717
|
+
economyAssert(
|
|
5718
|
+
decision.adjustmentId === preview.adjustmentId && decision.proposalId === proposal.proposalId && decision.proposalHash === expectedProposalHash && decision.previewHash === expectedPreviewHash,
|
|
5719
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
5720
|
+
"Operator adjustment decision does not match its preview"
|
|
5721
|
+
);
|
|
5722
|
+
const proposedAt = parseIsoTimestamp(decision.proposedAt);
|
|
5723
|
+
const decidedAt = parseIsoTimestamp(decision.decidedAt);
|
|
5724
|
+
economyAssert(
|
|
5725
|
+
decision.proposedByAccountId === proposal.proposedByAccountId && proposedAt === parseIsoTimestamp(proposal.proposedAt) && decidedAt >= proposedAt,
|
|
5726
|
+
"INVALID_TIME_WINDOW",
|
|
5727
|
+
"Operator adjustment decision times are inconsistent"
|
|
5728
|
+
);
|
|
5729
|
+
economyAssert(
|
|
5730
|
+
decidedAt <= parseIsoTimestamp(preview.expiresAt),
|
|
5731
|
+
"ADJUSTMENT_EXPIRED",
|
|
5732
|
+
"Operator adjustment preview has expired"
|
|
5733
|
+
);
|
|
5734
|
+
}
|
|
5735
|
+
function canonicalOperatorAdjustmentDecisionPayload(decision) {
|
|
5736
|
+
assertExactKeys4(decision, DECISION_KEYS, "Operator adjustment decision");
|
|
5737
|
+
return JSON.stringify({
|
|
5738
|
+
schemaVersion: decision.schemaVersion,
|
|
5739
|
+
decisionId: decision.decisionId,
|
|
5740
|
+
adjustmentId: decision.adjustmentId,
|
|
5741
|
+
proposalId: decision.proposalId,
|
|
5742
|
+
proposalHash: decision.proposalHash,
|
|
5743
|
+
previewHash: decision.previewHash,
|
|
5744
|
+
decision: decision.decision,
|
|
5745
|
+
proposedByAccountId: decision.proposedByAccountId,
|
|
5746
|
+
decidedByAccountId: decision.decidedByAccountId,
|
|
5747
|
+
proposedAt: decision.proposedAt,
|
|
5748
|
+
decidedAt: decision.decidedAt
|
|
5749
|
+
});
|
|
5750
|
+
}
|
|
5751
|
+
function assertOperatorAdjustmentExecution(execution, preview, proposal, decision, expectedPreviewHash, expectedProposalHash, expectedDecisionHash) {
|
|
5752
|
+
assertOperatorAdjustmentDecision(
|
|
5753
|
+
decision,
|
|
5754
|
+
proposal,
|
|
5755
|
+
preview,
|
|
5756
|
+
expectedPreviewHash,
|
|
5757
|
+
expectedProposalHash
|
|
5758
|
+
);
|
|
5759
|
+
assertCanonicalHash6(expectedDecisionHash, "expectedDecisionHash");
|
|
5760
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
5761
|
+
economyAssert(
|
|
5762
|
+
execution.schemaVersion === ECONOMY_CONTRACT_VERSION,
|
|
5763
|
+
"INVALID_CONTRACT",
|
|
5764
|
+
"Unsupported operator adjustment execution"
|
|
5765
|
+
);
|
|
5766
|
+
assertEconomyIdentifier(execution.executionId, "executionId");
|
|
5767
|
+
assertEconomyIdentifier(execution.adjustmentId, "adjustmentId");
|
|
5768
|
+
assertCanonicalHash6(execution.previewHash, "previewHash");
|
|
5769
|
+
assertCanonicalHash6(execution.proposalHash, "proposalHash");
|
|
5770
|
+
assertCanonicalHash6(execution.decisionHash, "decisionHash");
|
|
5771
|
+
assertEconomyIdentifier(execution.sourceLotId, "sourceLotId");
|
|
5772
|
+
assertEconomyIdentifier(execution.transactionId, "transactionId");
|
|
5773
|
+
assertEconomyIdentifier(execution.resultReceiptId, "resultReceiptId");
|
|
5774
|
+
economyAssert(
|
|
5775
|
+
decision.decision === "approve",
|
|
5776
|
+
"ADJUSTMENT_NOT_APPROVED",
|
|
5777
|
+
"Only an approved adjustment may execute"
|
|
5778
|
+
);
|
|
5779
|
+
economyAssert(
|
|
5780
|
+
execution.adjustmentId === preview.adjustmentId && execution.previewHash === expectedPreviewHash && execution.proposalHash === expectedProposalHash && execution.decisionHash === expectedDecisionHash && execution.sourceLotId === preview.sourceLotId,
|
|
5781
|
+
"ADJUSTMENT_PREVIEW_MISMATCH",
|
|
5782
|
+
"Operator adjustment execution does not match its approval plan"
|
|
5783
|
+
);
|
|
5784
|
+
economyAssert(
|
|
5785
|
+
parseIsoTimestamp(execution.executedAt) >= parseIsoTimestamp(decision.decidedAt),
|
|
5786
|
+
"INVALID_TIME_WINDOW",
|
|
5787
|
+
"Operator adjustment execution predates its decision"
|
|
5788
|
+
);
|
|
5789
|
+
}
|
|
5790
|
+
function canonicalOperatorAdjustmentExecutionPayload(execution) {
|
|
5791
|
+
assertExactKeys4(execution, EXECUTION_KEYS, "Operator adjustment execution");
|
|
5792
|
+
return JSON.stringify({
|
|
5793
|
+
schemaVersion: execution.schemaVersion,
|
|
5794
|
+
executionId: execution.executionId,
|
|
5795
|
+
adjustmentId: execution.adjustmentId,
|
|
5796
|
+
previewHash: execution.previewHash,
|
|
5797
|
+
proposalHash: execution.proposalHash,
|
|
5798
|
+
decisionHash: execution.decisionHash,
|
|
5799
|
+
sourceLotId: execution.sourceLotId,
|
|
5800
|
+
transactionId: execution.transactionId,
|
|
5801
|
+
resultReceiptId: execution.resultReceiptId,
|
|
5802
|
+
executedAt: execution.executedAt
|
|
5803
|
+
});
|
|
5804
|
+
}
|
|
5805
|
+
|
|
4322
5806
|
// src/paid-lots.ts
|
|
4323
5807
|
var ZERO_ARITHMETIC = Object.freeze({
|
|
4324
5808
|
retainedDelta: serializeTokenSubunits(0n),
|
|
@@ -5349,7 +6833,7 @@ function createProjectionSnapshot(transactions, rebuiltAt) {
|
|
|
5349
6833
|
}
|
|
5350
6834
|
|
|
5351
6835
|
// src/ports/query.ts
|
|
5352
|
-
var
|
|
6836
|
+
var ACTIVITY_TYPES3 = /* @__PURE__ */ new Set([
|
|
5353
6837
|
"purchase",
|
|
5354
6838
|
"subscription",
|
|
5355
6839
|
"rewarded-ad",
|
|
@@ -5366,14 +6850,14 @@ var ACTIVITY_TYPES2 = /* @__PURE__ */ new Set([
|
|
|
5366
6850
|
"event",
|
|
5367
6851
|
"competition"
|
|
5368
6852
|
]);
|
|
5369
|
-
var
|
|
6853
|
+
var ACTIVITY_STATUSES3 = /* @__PURE__ */ new Set([
|
|
5370
6854
|
"pending",
|
|
5371
6855
|
"held",
|
|
5372
6856
|
"settled",
|
|
5373
6857
|
"reversed",
|
|
5374
6858
|
"failed"
|
|
5375
6859
|
]);
|
|
5376
|
-
var
|
|
6860
|
+
var ACTIVITY_SOURCES3 = /* @__PURE__ */ new Set([
|
|
5377
6861
|
"shopify",
|
|
5378
6862
|
"ayet",
|
|
5379
6863
|
"bitlabs",
|
|
@@ -5401,14 +6885,14 @@ function assertSafeDisplayString(value, label) {
|
|
|
5401
6885
|
`${label} must be bounded and safe for display`
|
|
5402
6886
|
);
|
|
5403
6887
|
}
|
|
5404
|
-
function
|
|
6888
|
+
function assertOpaqueCursor2(value) {
|
|
5405
6889
|
economyAssert(
|
|
5406
6890
|
typeof value === "string" && value.length > 0 && value.length <= 512 && !hasControlCharacters2(value),
|
|
5407
6891
|
"INVALID_CONTRACT",
|
|
5408
6892
|
"Activity cursor must be a bounded opaque value"
|
|
5409
6893
|
);
|
|
5410
6894
|
}
|
|
5411
|
-
function
|
|
6895
|
+
function assertUniqueValues2(values, allowed, label) {
|
|
5412
6896
|
const unique = new Set(values);
|
|
5413
6897
|
economyAssert(
|
|
5414
6898
|
values.length > 0 && values.length === unique.size && values.every((value) => allowed.has(value)),
|
|
@@ -5671,7 +7155,7 @@ function assertWalletActivityEntry(entry) {
|
|
|
5671
7155
|
assertEconomyIdentifier(entry.activityId, "activityId");
|
|
5672
7156
|
assertEconomyIdentifier(entry.walletId, "walletId");
|
|
5673
7157
|
economyAssert(
|
|
5674
|
-
|
|
7158
|
+
ACTIVITY_TYPES3.has(entry.activityType) && ACTIVITY_STATUSES3.has(entry.status) && ACTIVITY_SOURCES3.has(entry.source),
|
|
5675
7159
|
"INVALID_CONTRACT",
|
|
5676
7160
|
"Wallet activity type, status, or source is unsupported"
|
|
5677
7161
|
);
|
|
@@ -5719,20 +7203,20 @@ function assertWalletActivityPageRequest(request) {
|
|
|
5719
7203
|
"Activity page limit must be between one and 100"
|
|
5720
7204
|
);
|
|
5721
7205
|
if (request.cursor !== void 0) {
|
|
5722
|
-
|
|
7206
|
+
assertOpaqueCursor2(request.cursor);
|
|
5723
7207
|
}
|
|
5724
7208
|
const filter = request.filter;
|
|
5725
7209
|
if (filter === void 0) {
|
|
5726
7210
|
return;
|
|
5727
7211
|
}
|
|
5728
7212
|
if (filter.activityTypes !== void 0) {
|
|
5729
|
-
|
|
7213
|
+
assertUniqueValues2(filter.activityTypes, ACTIVITY_TYPES3, "Activity types");
|
|
5730
7214
|
}
|
|
5731
7215
|
if (filter.statuses !== void 0) {
|
|
5732
|
-
|
|
7216
|
+
assertUniqueValues2(filter.statuses, ACTIVITY_STATUSES3, "Activity statuses");
|
|
5733
7217
|
}
|
|
5734
7218
|
if (filter.sources !== void 0) {
|
|
5735
|
-
|
|
7219
|
+
assertUniqueValues2(filter.sources, ACTIVITY_SOURCES3, "Activity sources");
|
|
5736
7220
|
}
|
|
5737
7221
|
if (filter.beneficiaryAccountId !== void 0) {
|
|
5738
7222
|
assertEconomyIdentifier(
|
|
@@ -5765,7 +7249,7 @@ function assertWalletActivityPage(page) {
|
|
|
5765
7249
|
"Activity pages are bounded and cannot advertise more rows from an empty page"
|
|
5766
7250
|
);
|
|
5767
7251
|
if (page.nextCursor !== void 0) {
|
|
5768
|
-
|
|
7252
|
+
assertOpaqueCursor2(page.nextCursor);
|
|
5769
7253
|
}
|
|
5770
7254
|
const activityIds = /* @__PURE__ */ new Set();
|
|
5771
7255
|
let previous;
|
|
@@ -6747,7 +8231,7 @@ var RESULT_OUTCOMES = /* @__PURE__ */ new Set([
|
|
|
6747
8231
|
"failed",
|
|
6748
8232
|
"no-op"
|
|
6749
8233
|
]);
|
|
6750
|
-
var
|
|
8234
|
+
var ACTIVITY_TYPES4 = /* @__PURE__ */ new Set([
|
|
6751
8235
|
"purchase",
|
|
6752
8236
|
"subscription",
|
|
6753
8237
|
"rewarded-ad",
|
|
@@ -6859,7 +8343,7 @@ var PORTABLE_KEYS = /* @__PURE__ */ new Set([
|
|
|
6859
8343
|
"signature",
|
|
6860
8344
|
...PORTABLE_BODY_KEYS
|
|
6861
8345
|
]);
|
|
6862
|
-
function
|
|
8346
|
+
function assertExactKeys5(value, allowedKeys, label) {
|
|
6863
8347
|
economyAssert(
|
|
6864
8348
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
6865
8349
|
"INVALID_CONTRACT",
|
|
@@ -6871,7 +8355,7 @@ function assertExactKeys3(value, allowedKeys, label) {
|
|
|
6871
8355
|
`${label} contains an unsupported field`
|
|
6872
8356
|
);
|
|
6873
8357
|
}
|
|
6874
|
-
function
|
|
8358
|
+
function assertCanonicalHash7(value, label) {
|
|
6875
8359
|
economyAssert(
|
|
6876
8360
|
typeof value === "string" && CANONICAL_HASH.test(value),
|
|
6877
8361
|
"INVALID_CONTRACT",
|
|
@@ -6880,7 +8364,7 @@ function assertCanonicalHash6(value, label) {
|
|
|
6880
8364
|
}
|
|
6881
8365
|
function canonicalHash(payload, hashCanonicalPayload2, label) {
|
|
6882
8366
|
const value = hashCanonicalPayload2(payload);
|
|
6883
|
-
|
|
8367
|
+
assertCanonicalHash7(value, label);
|
|
6884
8368
|
return value;
|
|
6885
8369
|
}
|
|
6886
8370
|
function assertUnsignedInteger(value, label) {
|
|
@@ -6948,7 +8432,7 @@ function canonicalSignatureMetadata(signature) {
|
|
|
6948
8432
|
};
|
|
6949
8433
|
}
|
|
6950
8434
|
function assertEconomySealedRecoveryPayload(payload) {
|
|
6951
|
-
|
|
8435
|
+
assertExactKeys5(
|
|
6952
8436
|
payload,
|
|
6953
8437
|
/* @__PURE__ */ new Set([
|
|
6954
8438
|
"schemaVersion",
|
|
@@ -6978,17 +8462,17 @@ function assertEconomySealedRecoveryPayload(payload) {
|
|
|
6978
8462
|
22,
|
|
6979
8463
|
22
|
|
6980
8464
|
);
|
|
6981
|
-
|
|
8465
|
+
assertCanonicalHash7(
|
|
6982
8466
|
payload.plaintextContentHash,
|
|
6983
8467
|
"Recovery plaintext-content hash"
|
|
6984
8468
|
);
|
|
6985
|
-
|
|
8469
|
+
assertCanonicalHash7(
|
|
6986
8470
|
payload.encryptionContextHash,
|
|
6987
8471
|
"Recovery encryption-context hash"
|
|
6988
8472
|
);
|
|
6989
8473
|
}
|
|
6990
8474
|
function assertAcceptanceBody(body) {
|
|
6991
|
-
|
|
8475
|
+
assertExactKeys5(
|
|
6992
8476
|
body,
|
|
6993
8477
|
"acceptanceEnvelopeId" in body ? ACCEPTANCE_KEYS : ACCEPTANCE_BODY_KEYS,
|
|
6994
8478
|
"Recovery acceptance body"
|
|
@@ -7007,9 +8491,9 @@ function assertAcceptanceBody(body) {
|
|
|
7007
8491
|
body.idempotencyFingerprint,
|
|
7008
8492
|
"economy.idempotency-key.v1"
|
|
7009
8493
|
);
|
|
7010
|
-
|
|
8494
|
+
assertCanonicalHash7(body.commandEnvelopeHash, "Command-envelope hash");
|
|
7011
8495
|
assertEconomyIdentifier(body.acceptedReceiptId, "acceptedReceiptId");
|
|
7012
|
-
|
|
8496
|
+
assertCanonicalHash7(body.acceptedReceiptHash, "Accepted-receipt hash");
|
|
7013
8497
|
assertEconomySealedRecoveryPayload(body.sealedPayload);
|
|
7014
8498
|
const preparedAt = parseIsoTimestamp(body.preparedAt);
|
|
7015
8499
|
const acceptedAt = parseIsoTimestamp(body.acceptedAt);
|
|
@@ -7057,7 +8541,7 @@ function createEconomyRecoveryAcceptanceEnvelope(body, hashCanonicalPayload2) {
|
|
|
7057
8541
|
};
|
|
7058
8542
|
}
|
|
7059
8543
|
function assertEconomyRecoveryAcceptanceEnvelope(envelope, hashCanonicalPayload2) {
|
|
7060
|
-
|
|
8544
|
+
assertExactKeys5(envelope, ACCEPTANCE_KEYS, "Recovery acceptance envelope");
|
|
7061
8545
|
assertAcceptanceBody(envelope);
|
|
7062
8546
|
assertEconomyIdentifier(
|
|
7063
8547
|
envelope.acceptanceEnvelopeId,
|
|
@@ -7098,7 +8582,7 @@ function canonicalEconomyRecoveryAcceptanceEnvelopePayload(envelope, hashCanonic
|
|
|
7098
8582
|
});
|
|
7099
8583
|
}
|
|
7100
8584
|
function assertCommittedResultBody(body) {
|
|
7101
|
-
|
|
8585
|
+
assertExactKeys5(
|
|
7102
8586
|
body,
|
|
7103
8587
|
"committedResultId" in body ? COMMITTED_RESULT_KEYS : COMMITTED_RESULT_BODY_KEYS,
|
|
7104
8588
|
"Recovery committed-result body"
|
|
@@ -7126,7 +8610,7 @@ function assertCommittedResultBody(body) {
|
|
|
7126
8610
|
[body.authorityCommitHash, "Authority-commit hash"],
|
|
7127
8611
|
[body.authorityHeadHashAfter, "Authority-head hash"]
|
|
7128
8612
|
]) {
|
|
7129
|
-
|
|
8613
|
+
assertCanonicalHash7(value, label);
|
|
7130
8614
|
}
|
|
7131
8615
|
economyAssert(
|
|
7132
8616
|
RESULT_OUTCOMES.has(body.outcome),
|
|
@@ -7149,7 +8633,7 @@ function assertCommittedResultBody(body) {
|
|
|
7149
8633
|
assertEconomyIdentifier(body.transactionId, "transactionId");
|
|
7150
8634
|
}
|
|
7151
8635
|
if (body.transactionCanonicalHash !== void 0) {
|
|
7152
|
-
|
|
8636
|
+
assertCanonicalHash7(
|
|
7153
8637
|
body.transactionCanonicalHash,
|
|
7154
8638
|
"Transaction canonical hash"
|
|
7155
8639
|
);
|
|
@@ -7192,7 +8676,7 @@ function createEconomyRecoveryCommittedResult(body, hashCanonicalPayload2) {
|
|
|
7192
8676
|
};
|
|
7193
8677
|
}
|
|
7194
8678
|
function assertEconomyRecoveryCommittedResult(result, hashCanonicalPayload2) {
|
|
7195
|
-
|
|
8679
|
+
assertExactKeys5(
|
|
7196
8680
|
result,
|
|
7197
8681
|
COMMITTED_RESULT_KEYS,
|
|
7198
8682
|
"Recovery committed result"
|
|
@@ -7251,7 +8735,7 @@ function assertEconomyRecoveryResultLink(acceptance, result, hashCanonicalPayloa
|
|
|
7251
8735
|
);
|
|
7252
8736
|
}
|
|
7253
8737
|
function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
7254
|
-
|
|
8738
|
+
assertExactKeys5(
|
|
7255
8739
|
signature,
|
|
7256
8740
|
/* @__PURE__ */ new Set([
|
|
7257
8741
|
"schemaVersion",
|
|
@@ -7271,7 +8755,7 @@ function assertEconomyEvidenceSignatureMetadata(signature) {
|
|
|
7271
8755
|
parseIsoTimestamp(signature.signedAt);
|
|
7272
8756
|
}
|
|
7273
8757
|
function assertEconomyEvidenceSignature(signature) {
|
|
7274
|
-
|
|
8758
|
+
assertExactKeys5(
|
|
7275
8759
|
signature,
|
|
7276
8760
|
/* @__PURE__ */ new Set([
|
|
7277
8761
|
"schemaVersion",
|
|
@@ -7293,7 +8777,7 @@ function assertEconomyEvidenceSignature(signature) {
|
|
|
7293
8777
|
assertBase64url(signature.value, "Evidence signature value", 32, 2048);
|
|
7294
8778
|
}
|
|
7295
8779
|
function assertRegionalEvidenceBody(body) {
|
|
7296
|
-
|
|
8780
|
+
assertExactKeys5(
|
|
7297
8781
|
body,
|
|
7298
8782
|
"evidenceReceiptId" in body ? REGIONAL_KEYS : REGIONAL_BODY_KEYS,
|
|
7299
8783
|
"Regional evidence-receipt body"
|
|
@@ -7325,7 +8809,7 @@ function assertRegionalEvidenceBody(body) {
|
|
|
7325
8809
|
"INVALID_CONTRACT",
|
|
7326
8810
|
"Unsupported recovery record kind"
|
|
7327
8811
|
);
|
|
7328
|
-
|
|
8812
|
+
assertCanonicalHash7(
|
|
7329
8813
|
body.recoveryRecordContentHash,
|
|
7330
8814
|
"Recovery-record content hash"
|
|
7331
8815
|
);
|
|
@@ -7341,7 +8825,7 @@ function assertRegionalEvidenceBody(body) {
|
|
|
7341
8825
|
"INVALID_CONTRACT",
|
|
7342
8826
|
"Non-genesis regional evidence receipt requires a previous hash"
|
|
7343
8827
|
);
|
|
7344
|
-
|
|
8828
|
+
assertCanonicalHash7(
|
|
7345
8829
|
body.previousReceiptHash,
|
|
7346
8830
|
"Previous evidence-receipt hash"
|
|
7347
8831
|
);
|
|
@@ -7385,7 +8869,7 @@ function createEconomyRegionalEvidenceReceipt(body, signature, hashCanonicalPayl
|
|
|
7385
8869
|
};
|
|
7386
8870
|
}
|
|
7387
8871
|
function assertEconomyRegionalEvidenceReceipt(receipt, hashCanonicalPayload2) {
|
|
7388
|
-
|
|
8872
|
+
assertExactKeys5(receipt, REGIONAL_KEYS, "Regional evidence receipt");
|
|
7389
8873
|
assertRegionalEvidenceBody(receipt);
|
|
7390
8874
|
assertEconomyIdentifier(receipt.evidenceReceiptId, "evidenceReceiptId");
|
|
7391
8875
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -7516,7 +9000,7 @@ function assertEconomyRegionalEvidenceChain(receipts, expectedPreviousReceiptHas
|
|
|
7516
9000
|
"INVALID_CONTRACT",
|
|
7517
9001
|
"Partial evidence chain requires its trusted preceding hash"
|
|
7518
9002
|
);
|
|
7519
|
-
|
|
9003
|
+
assertCanonicalHash7(
|
|
7520
9004
|
expectedPreviousReceiptHash,
|
|
7521
9005
|
"Expected preceding evidence-receipt hash"
|
|
7522
9006
|
);
|
|
@@ -7587,7 +9071,7 @@ function assertEconomyRegionalEvidenceEquality(receipts, expectedRegions, hashCa
|
|
|
7587
9071
|
);
|
|
7588
9072
|
}
|
|
7589
9073
|
function assertEconomyMerkleInclusionProof(proof) {
|
|
7590
|
-
|
|
9074
|
+
assertExactKeys5(
|
|
7591
9075
|
proof,
|
|
7592
9076
|
/* @__PURE__ */ new Set([
|
|
7593
9077
|
"schemaVersion",
|
|
@@ -7608,8 +9092,8 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7608
9092
|
"Unsupported Merkle inclusion proof"
|
|
7609
9093
|
);
|
|
7610
9094
|
assertEconomyIdentifier(proof.anchorId, "anchorId");
|
|
7611
|
-
|
|
7612
|
-
|
|
9095
|
+
assertCanonicalHash7(proof.anchorManifestHash, "Anchor-manifest hash");
|
|
9096
|
+
assertCanonicalHash7(proof.leafHash, "Merkle leaf hash");
|
|
7613
9097
|
assertUnsignedInteger(proof.leafIndex, "Merkle leaf index");
|
|
7614
9098
|
assertUnsignedInteger(proof.leafCount, "Merkle leaf count");
|
|
7615
9099
|
economyAssert(
|
|
@@ -7618,7 +9102,7 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7618
9102
|
"Merkle leaf position is outside its bounded tree"
|
|
7619
9103
|
);
|
|
7620
9104
|
for (const step of proof.siblings) {
|
|
7621
|
-
|
|
9105
|
+
assertExactKeys5(
|
|
7622
9106
|
step,
|
|
7623
9107
|
/* @__PURE__ */ new Set(["schemaVersion", "side", "hash"]),
|
|
7624
9108
|
"Merkle proof step"
|
|
@@ -7628,7 +9112,7 @@ function assertEconomyMerkleInclusionProof(proof) {
|
|
|
7628
9112
|
"INVALID_CONTRACT",
|
|
7629
9113
|
"Unsupported Merkle proof step"
|
|
7630
9114
|
);
|
|
7631
|
-
|
|
9115
|
+
assertCanonicalHash7(step.hash, "Merkle sibling hash");
|
|
7632
9116
|
}
|
|
7633
9117
|
}
|
|
7634
9118
|
function canonicalMerkleProof(proof) {
|
|
@@ -7707,7 +9191,7 @@ function assertEconomyMerkleInclusion(proof, anchor, hashCanonicalPayload2) {
|
|
|
7707
9191
|
);
|
|
7708
9192
|
}
|
|
7709
9193
|
function assertPortableEvidenceReference(reference) {
|
|
7710
|
-
|
|
9194
|
+
assertExactKeys5(
|
|
7711
9195
|
reference,
|
|
7712
9196
|
/* @__PURE__ */ new Set([
|
|
7713
9197
|
"schemaVersion",
|
|
@@ -7727,7 +9211,7 @@ function assertPortableEvidenceReference(reference) {
|
|
|
7727
9211
|
reference.evidenceReceiptId,
|
|
7728
9212
|
"evidenceReceiptId"
|
|
7729
9213
|
);
|
|
7730
|
-
|
|
9214
|
+
assertCanonicalHash7(
|
|
7731
9215
|
reference.evidenceReceiptHash,
|
|
7732
9216
|
"Evidence-receipt hash"
|
|
7733
9217
|
);
|
|
@@ -7744,7 +9228,7 @@ function canonicalPortableEvidenceReference(reference) {
|
|
|
7744
9228
|
};
|
|
7745
9229
|
}
|
|
7746
9230
|
function assertPortableBody(body) {
|
|
7747
|
-
|
|
9231
|
+
assertExactKeys5(
|
|
7748
9232
|
body,
|
|
7749
9233
|
"portableReceiptId" in body ? PORTABLE_KEYS : PORTABLE_BODY_KEYS,
|
|
7750
9234
|
"Portable customer-receipt body"
|
|
@@ -7768,7 +9252,7 @@ function assertPortableBody(body) {
|
|
|
7768
9252
|
assertEconomyIdentifier(value, label);
|
|
7769
9253
|
}
|
|
7770
9254
|
economyAssert(
|
|
7771
|
-
|
|
9255
|
+
ACTIVITY_TYPES4.has(body.activityType) && (body.direction === "credit" || body.direction === "debit"),
|
|
7772
9256
|
"INVALID_CONTRACT",
|
|
7773
9257
|
"Portable customer receipt has an unsupported activity or direction"
|
|
7774
9258
|
);
|
|
@@ -7783,7 +9267,7 @@ function assertPortableBody(body) {
|
|
|
7783
9267
|
[body.committedResultContentHash, "Committed-result content hash"],
|
|
7784
9268
|
[body.authorityCommitHash, "Authority-commit hash"]
|
|
7785
9269
|
]) {
|
|
7786
|
-
|
|
9270
|
+
assertCanonicalHash7(value, label);
|
|
7787
9271
|
}
|
|
7788
9272
|
assertUnsignedInteger(body.authoritySequence, "Authority sequence");
|
|
7789
9273
|
economyAssert(
|
|
@@ -7868,7 +9352,7 @@ function createEconomyPortableCustomerReceipt(body, signature, hashCanonicalPayl
|
|
|
7868
9352
|
};
|
|
7869
9353
|
}
|
|
7870
9354
|
function assertEconomyPortableCustomerReceipt(receipt, hashCanonicalPayload2) {
|
|
7871
|
-
|
|
9355
|
+
assertExactKeys5(receipt, PORTABLE_KEYS, "Portable customer receipt");
|
|
7872
9356
|
assertPortableBody(receipt);
|
|
7873
9357
|
assertEconomyIdentifier(receipt.portableReceiptId, "portableReceiptId");
|
|
7874
9358
|
assertEconomyEvidenceSignature(receipt.signature);
|
|
@@ -8168,7 +9652,7 @@ var DOCUMENT_ID_KEYS = /* @__PURE__ */ new Set([
|
|
|
8168
9652
|
"lifetimeProjectionId",
|
|
8169
9653
|
"outboxEventId"
|
|
8170
9654
|
]);
|
|
8171
|
-
function
|
|
9655
|
+
function assertExactKeys6(value, allowed, label) {
|
|
8172
9656
|
economyAssert(
|
|
8173
9657
|
value !== null && typeof value === "object" && !Array.isArray(value),
|
|
8174
9658
|
"INVALID_CONTRACT",
|
|
@@ -8208,7 +9692,7 @@ function createPersonalWalletInitializationDocumentIds(subjectAccountId, hash) {
|
|
|
8208
9692
|
};
|
|
8209
9693
|
}
|
|
8210
9694
|
function assertPersonalWalletInitializationCommand(command) {
|
|
8211
|
-
|
|
9695
|
+
assertExactKeys6(command, COMMAND_KEYS, "Wallet initialization command");
|
|
8212
9696
|
economyAssert(
|
|
8213
9697
|
command.schemaVersion === ECONOMY_CONTRACT_VERSION && command.commandType === "initialize-wallet" && command.walletKind === "personal",
|
|
8214
9698
|
"INVALID_CONTRACT",
|
|
@@ -8232,7 +9716,7 @@ function canonicalPersonalWalletInitializationCommandPayload(command) {
|
|
|
8232
9716
|
});
|
|
8233
9717
|
}
|
|
8234
9718
|
function assertPersonalWalletInitializationOutboxIntent(intent) {
|
|
8235
|
-
|
|
9719
|
+
assertExactKeys6(intent, OUTBOX_KEYS, "Wallet initialization outbox intent");
|
|
8236
9720
|
economyAssert(
|
|
8237
9721
|
intent.schemaVersion === ECONOMY_CONTRACT_VERSION && intent.eventType === "wallet.initialized.v1",
|
|
8238
9722
|
"INVALID_CONTRACT",
|
|
@@ -8332,8 +9816,8 @@ function createPersonalWalletInitializationState(input, hash) {
|
|
|
8332
9816
|
return state;
|
|
8333
9817
|
}
|
|
8334
9818
|
function assertPersonalWalletInitializationState(state) {
|
|
8335
|
-
|
|
8336
|
-
|
|
9819
|
+
assertExactKeys6(state, STATE_KEYS, "Wallet initialization state");
|
|
9820
|
+
assertExactKeys6(
|
|
8337
9821
|
state.documentIds,
|
|
8338
9822
|
DOCUMENT_ID_KEYS,
|
|
8339
9823
|
"Wallet initialization document IDs"
|
|
@@ -8364,6 +9848,13 @@ function assertPersonalWalletInitializationState(state) {
|
|
|
8364
9848
|
);
|
|
8365
9849
|
}
|
|
8366
9850
|
export {
|
|
9851
|
+
ADMIN_TOKEN_ANOMALY_BASELINE_DAYS,
|
|
9852
|
+
ADMIN_TOKEN_DEFAULT_WINDOW_DAYS,
|
|
9853
|
+
ADMIN_TOKEN_MAXIMUM_HOURLY_WINDOW_DAYS,
|
|
9854
|
+
ADMIN_TOKEN_MAXIMUM_PAGE_SIZE,
|
|
9855
|
+
ADMIN_TOKEN_MAXIMUM_TREND_POINTS,
|
|
9856
|
+
ADMIN_TOKEN_MAXIMUM_WINDOW_DAYS,
|
|
9857
|
+
ADMIN_TOKEN_MINIMUM_COHORT_SIZE,
|
|
8367
9858
|
BASELINE_GBP_CATALOG_VERSION,
|
|
8368
9859
|
BASELINE_GBP_REFERENCE_RATE,
|
|
8369
9860
|
BASELINE_GBP_TOKEN_PACKS,
|
|
@@ -8391,6 +9882,19 @@ export {
|
|
|
8391
9882
|
applyWalletBalanceDelta,
|
|
8392
9883
|
applyWalletLifetimeDeltas,
|
|
8393
9884
|
assertActivityEntry,
|
|
9885
|
+
assertAdminTokenActivityCursorBinding,
|
|
9886
|
+
assertAdminTokenActivityEntry,
|
|
9887
|
+
assertAdminTokenActivityPage,
|
|
9888
|
+
assertAdminTokenActivityPageForRequest,
|
|
9889
|
+
assertAdminTokenActivityPageRequest,
|
|
9890
|
+
assertAdminTokenEconomySummary,
|
|
9891
|
+
assertAdminTokenTrendRequest,
|
|
9892
|
+
assertAdminTokenTrendResult,
|
|
9893
|
+
assertAdminTokenTrendResultForRequest,
|
|
9894
|
+
assertAdminTokenWalletBalanceCursorBinding,
|
|
9895
|
+
assertAdminTokenWalletBalancePage,
|
|
9896
|
+
assertAdminTokenWalletBalancePageForRequest,
|
|
9897
|
+
assertAdminTokenWalletBalancePageRequest,
|
|
8394
9898
|
assertAuditedEconomyCommandEnvelope,
|
|
8395
9899
|
assertBalancedTransaction,
|
|
8396
9900
|
assertDeterministicWalletBalanceSummary,
|
|
@@ -8444,6 +9948,10 @@ export {
|
|
|
8444
9948
|
assertModuleSpendQuote,
|
|
8445
9949
|
assertNonNegativeAccounts,
|
|
8446
9950
|
assertOpenPurchaseIntent,
|
|
9951
|
+
assertOperatorAdjustmentDecision,
|
|
9952
|
+
assertOperatorAdjustmentExecution,
|
|
9953
|
+
assertOperatorAdjustmentPreview,
|
|
9954
|
+
assertOperatorAdjustmentProposal,
|
|
8447
9955
|
assertPaidLotLifecycle,
|
|
8448
9956
|
assertPaidLotLifecycleEvent,
|
|
8449
9957
|
assertPaidLotPurchaseProvenance,
|
|
@@ -8507,11 +10015,18 @@ export {
|
|
|
8507
10015
|
canonicalEconomyRegionalEvidenceReceiptBodyPayload,
|
|
8508
10016
|
canonicalEconomyRegionalEvidenceReceiptPayload,
|
|
8509
10017
|
canonicalEconomyRegionalEvidenceReceiptSigningPayload,
|
|
10018
|
+
canonicalOperatorAdjustmentDecisionPayload,
|
|
10019
|
+
canonicalOperatorAdjustmentExecutionPayload,
|
|
10020
|
+
canonicalOperatorAdjustmentPreviewPayload,
|
|
10021
|
+
canonicalOperatorAdjustmentProposalPayload,
|
|
8510
10022
|
canonicalPersonalWalletInitializationCommandPayload,
|
|
8511
10023
|
canonicalPersonalWalletInitializationOutboxPayload,
|
|
8512
10024
|
canonicalTransactionPayload,
|
|
8513
10025
|
closeModuleAllowance,
|
|
8514
10026
|
convertRewardPayout,
|
|
10027
|
+
createAdminTokenAnomalyIndicator,
|
|
10028
|
+
createAdminTokenAnomalyUnavailable,
|
|
10029
|
+
createDefaultAdminTokenReportingWindow,
|
|
8515
10030
|
createEarlyBackerRetentionFromPaidLot,
|
|
8516
10031
|
createEconomyPortableCustomerReceipt,
|
|
8517
10032
|
createEconomyRecoveryAcceptanceEnvelope,
|