@plasius/economy 0.1.0 → 0.2.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 +7 -1
- package/dist/index.cjs +20 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -46
- package/dist/index.d.ts +48 -46
- package/dist/index.js +20 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/amount.ts","../src/contracts.ts","../src/acquisition.ts","../src/allocations.ts","../src/early-backers.ts","../src/ledger.ts","../src/lots.ts","../src/operations.ts","../src/projection.ts","../src/recurrence.ts","../src/spend-requests.ts","../src/wallets.ts"],"sourcesContent":["export * from \"./acquisition.js\";\nexport * from \"./allocations.js\";\nexport * from \"./amount.js\";\nexport * from \"./contracts.js\";\nexport * from \"./early-backers.js\";\nexport * from \"./errors.js\";\nexport * from \"./ledger.js\";\nexport * from \"./lots.js\";\nexport * from \"./operations.js\";\nexport * from \"./ports/persistence.js\";\nexport * from \"./projection.js\";\nexport * from \"./recurrence.js\";\nexport * from \"./spend-requests.js\";\nexport * from \"./wallets.js\";\n","/** Stable machine-readable failures exposed by the economy domain. */\nexport type EconomyErrorCode =\n | \"INVALID_AMOUNT\"\n | \"AMOUNT_OUT_OF_RANGE\"\n | \"AMOUNT_NOT_WHOLE_TOKEN\"\n | \"INVALID_CONTRACT\"\n | \"UNBALANCED_TRANSACTION\"\n | \"DUPLICATE_IDENTIFIER\"\n | \"DUPLICATE_TRANSACTION\"\n | \"INSUFFICIENT_BALANCE\"\n | \"INSUFFICIENT_ELIGIBLE_LOTS\"\n | \"SOURCE_LOT_RESTRICTED\"\n | \"REVERSAL_ALREADY_EXISTS\"\n | \"NEGATIVE_PROJECTION\"\n | \"INVALID_TIME_WINDOW\";\n\nexport interface EconomyErrorEnvelopeV1 {\n readonly schemaVersion: \"1\";\n readonly error: {\n readonly code: EconomyErrorCode;\n readonly message: string;\n readonly requestId?: string;\n };\n}\n\n/**\n * Domain error with a stable code and deliberately non-sensitive message.\n * Provider evidence, identities, and payment details must not be included.\n */\nexport class EconomyError extends Error {\n readonly code: EconomyErrorCode;\n\n constructor(code: EconomyErrorCode, message: string) {\n super(message);\n this.name = \"EconomyError\";\n this.code = code;\n }\n}\n\n/** Throws a stable economy error when a domain assertion fails. */\nexport function economyAssert(\n condition: unknown,\n code: EconomyErrorCode,\n message: string,\n): asserts condition {\n if (!condition) {\n throw new EconomyError(code, message);\n }\n}\n\n/** Creates a bounded, non-sensitive error contract for an HTTP adapter. */\nexport function toEconomyErrorEnvelope(\n error: EconomyError,\n requestId?: string,\n): EconomyErrorEnvelopeV1 {\n return {\n schemaVersion: \"1\",\n error: {\n code: error.code,\n message: error.message.slice(0, 256),\n ...(requestId === undefined ? {} : { requestId }),\n },\n };\n}\n","import { EconomyError, economyAssert } from \"./errors.js\";\n\n/** Number of indivisible subunits in one public Token. */\nexport const TOKEN_SUBUNITS_PER_TOKEN = 1_000n;\n\n/** PostgreSQL-compatible signed bigint bounds. */\nexport const TOKEN_SUBUNITS_MIN = -(2n ** 63n);\nexport const TOKEN_SUBUNITS_MAX = 2n ** 63n - 1n;\n\ndeclare const tokenSubunitStringBrand: unique symbol;\n\n/** Canonical base-10 representation used at JSON and persistence boundaries. */\nexport type TokenSubunitString = string & {\n readonly [tokenSubunitStringBrand]: \"TokenSubunitString\";\n};\n\nconst CANONICAL_INTEGER = /^(?:0|-?[1-9][0-9]*)$/u;\n\nfunction assertInRange(amount: bigint): void {\n economyAssert(\n amount >= TOKEN_SUBUNITS_MIN && amount <= TOKEN_SUBUNITS_MAX,\n \"AMOUNT_OUT_OF_RANGE\",\n \"TokenSubunit amount is outside the signed 64-bit range\",\n );\n}\n\n/** Parses a canonical base-10 TokenSubunit string without floating point. */\nexport function parseTokenSubunits(value: string): bigint {\n economyAssert(\n CANONICAL_INTEGER.test(value),\n \"INVALID_AMOUNT\",\n \"TokenSubunit amount must be a canonical base-10 integer string\",\n );\n\n try {\n const amount = BigInt(value);\n assertInRange(amount);\n return amount;\n } catch (error) {\n if (error instanceof EconomyError) {\n throw error;\n }\n throw new EconomyError(\"INVALID_AMOUNT\", \"TokenSubunit amount is invalid\");\n }\n}\n\n/** Serializes a signed 64-bit TokenSubunit amount to canonical base-10. */\nexport function serializeTokenSubunits(amount: bigint): TokenSubunitString {\n assertInRange(amount);\n return amount.toString(10) as TokenSubunitString;\n}\n\n/** Converts an exact whole-Token integer into TokenSubunits. */\nexport function wholeTokensToSubunits(tokens: bigint): bigint {\n const amount = tokens * TOKEN_SUBUNITS_PER_TOKEN;\n assertInRange(amount);\n return amount;\n}\n\n/** Returns true when a subunit amount represents an exact whole Token. */\nexport function isWholeTokenAmount(amount: bigint): boolean {\n return amount % TOKEN_SUBUNITS_PER_TOKEN === 0n;\n}\n\n/** Converts TokenSubunits to whole Tokens, rejecting fractional progress. */\nexport function subunitsToWholeTokens(amount: bigint): bigint {\n economyAssert(\n isWholeTokenAmount(amount),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Amount must contain whole Tokens\",\n );\n return amount / TOKEN_SUBUNITS_PER_TOKEN;\n}\n\n/** Sums amount strings with signed 64-bit overflow protection. */\nexport function sumTokenSubunits(values: readonly string[]): bigint {\n let total = 0n;\n for (const value of values) {\n total += parseTokenSubunits(value);\n assertInRange(total);\n }\n return total;\n}\n\n","import { economyAssert } from \"./errors.js\";\n\nexport const ECONOMY_CONTRACT_VERSION = \"1\" as const;\nexport type EconomyContractVersion = typeof ECONOMY_CONTRACT_VERSION;\n\nexport type AccountId = string;\nexport type AllocationId = string;\nexport type HouseholdId = string;\nexport type LotId = string;\nexport type PostingId = string;\nexport type ProviderEventId = string;\nexport type TransactionId = string;\nexport type WalletId = string;\nexport type IsoTimestamp = string;\n\nconst IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;\n\n/** Validates opaque pseudonymous domain identifiers. */\nexport function assertEconomyIdentifier(\n value: string,\n label = \"identifier\",\n): void {\n economyAssert(\n IDENTIFIER.test(value),\n \"INVALID_CONTRACT\",\n `${label} must be a non-empty opaque identifier`,\n );\n}\n\n/** Parses a bounded ISO timestamp and returns milliseconds since epoch. */\nexport function parseIsoTimestamp(value: IsoTimestamp): number {\n const match = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(?:\\.(\\d{3}))?Z$/u.exec(\n value,\n );\n economyAssert(\n match !== null,\n \"INVALID_CONTRACT\",\n \"Timestamp must be an ISO-8601 UTC value\",\n );\n const milliseconds = Date.parse(value);\n const base = match[1];\n const fraction = match[2] ?? \"000\";\n economyAssert(\n Number.isFinite(milliseconds) &&\n base !== undefined &&\n new Date(milliseconds).toISOString() === `${base}.${fraction}Z`,\n \"INVALID_CONTRACT\",\n \"Timestamp must be valid\",\n );\n return milliseconds;\n}\n\n/** Returns a new record with keys sorted for canonical serialization. */\nexport function sortStringRecord(\n value: Readonly<Record<string, string>>,\n): Readonly<Record<string, string>> {\n return Object.fromEntries(\n Object.entries(value).sort(([left], [right]) => left.localeCompare(right)),\n );\n}\n","import {\n TOKEN_SUBUNITS_PER_TOKEN,\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type ProviderEventId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport type { ActivityStatus, ActivityType } from \"./ledger.js\";\n\nexport interface TokenPackV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly packId: string;\n readonly catalogVersion: string;\n readonly currency: \"GBP\";\n readonly priceMinorUnits: string;\n readonly grantAmount: TokenSubunitString;\n readonly active: boolean;\n}\n\n/** Product-copy reference only; it is not a redemption or exchange promise. */\nexport interface TokenReferenceRateV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly rateVersion: string;\n readonly currency: \"GBP\";\n readonly referenceMinorUnitsPerToken: string;\n readonly tokenSubunitsPerToken: string;\n readonly cashRedemptionAllowed: false;\n}\n\nexport const BASELINE_GBP_REFERENCE_RATE: TokenReferenceRateV1 = Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n rateVersion: \"gbp-reference-v1\",\n currency: \"GBP\",\n referenceMinorUnitsPerToken: \"10\",\n tokenSubunitsPerToken: TOKEN_SUBUNITS_PER_TOKEN.toString(10),\n cashRedemptionAllowed: false,\n});\n\nexport const BASELINE_GBP_CATALOG_VERSION = \"gbp-v1\" as const;\n\n/** Initial flat-price public catalog. Changes require a new catalog version. */\nexport const BASELINE_GBP_TOKEN_PACKS: readonly TokenPackV1[] = Object.freeze([\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_5_50_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"500\",\n grantAmount: serializeTokenSubunits(50_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_10_100_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"1000\",\n grantAmount: serializeTokenSubunits(100_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_25_250_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"2500\",\n grantAmount: serializeTokenSubunits(250_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_50_500_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"5000\",\n grantAmount: serializeTokenSubunits(500_000n),\n active: true,\n }),\n]);\n\nexport interface PurchaseLimitPolicyV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly maxOrderPriceMinorUnits: string;\n readonly rollingPayerPriceMinorUnits: string;\n readonly rollingHouseholdPriceMinorUnits: string;\n readonly rollingDays: number;\n}\n\n/** Default server limits; household controls may only lower these values. */\nexport const BASELINE_PURCHASE_LIMIT_POLICY: PurchaseLimitPolicyV1 =\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n maxOrderPriceMinorUnits: \"5000\",\n rollingPayerPriceMinorUnits: \"10000\",\n rollingHouseholdPriceMinorUnits: \"10000\",\n rollingDays: 30,\n });\n\nexport type PurchaseIntentStatus =\n | \"created\"\n | \"checkout-created\"\n | \"paid-unreconciled\"\n | \"credited\"\n | \"expired\"\n | \"cancelled\"\n | \"disputed\";\n\n/** Short-lived server authority binding checkout facts to a payer/household. */\nexport interface PurchaseIntentV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly intentId: string;\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly receivingWalletId: WalletId;\n readonly packId: string;\n readonly catalogVersion: string;\n readonly expectedCurrency: \"GBP\";\n readonly expectedPriceMinorUnits: string;\n readonly grantAmount: TokenSubunitString;\n readonly status: PurchaseIntentStatus;\n readonly createdAt: IsoTimestamp;\n readonly expiresAt: IsoTimestamp;\n readonly providerCheckoutReferenceHash?: string;\n}\n\nexport interface RewardRateV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly rateVersion: string;\n readonly provider: \"ayet\" | \"bitlabs\";\n /** TokenSubunits granted per denominator of authoritative GBP minor units. */\n readonly tokenSubunitsNumerator: string;\n readonly gbpMinorUnitsDenominator: string;\n readonly effectiveFrom: IsoTimestamp;\n readonly effectiveUntil?: IsoTimestamp;\n}\n\nexport interface FxSnapshotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly snapshotId: string;\n readonly sourceCurrency: string;\n readonly quoteCurrency: \"GBP\";\n /** Exact rational conversion to GBP minor units. */\n readonly gbpMinorUnitsNumerator: string;\n readonly sourceMinorUnitsDenominator: string;\n readonly capturedAt: IsoTimestamp;\n}\n\nexport type RewardConversionStatus =\n | \"pending\"\n | \"completed\"\n | \"reconciled\";\n\nexport type BitLabsConversionState =\n | \"PENDING\"\n | \"COMPLETED\"\n | \"RECONCILED\";\n\nexport interface RewardActivityTransitionV1 {\n readonly conversionStatus: RewardConversionStatus;\n readonly activityType: ActivityType;\n readonly activityStatus: ActivityStatus;\n}\n\nexport interface RewardConversionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly provider: \"ayet\" | \"bitlabs\";\n readonly providerEventId: ProviderEventId;\n readonly beneficiaryAccountId: AccountId;\n readonly walletId: WalletId;\n readonly status: RewardConversionStatus;\n readonly providerPayoutMinorUnits: string;\n readonly providerCurrency: string;\n readonly gbpMinorUnits: string;\n readonly tokenSubunits: TokenSubunitString;\n readonly rateVersion: string;\n readonly fxSnapshotId: string;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Validates a minimized, signed-provider conversion record before journaling. */\nexport function assertRewardConversion(\n conversion: RewardConversionV1,\n): void {\n economyAssert(\n conversion.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion contract version\",\n );\n economyAssert(\n conversion.provider === \"ayet\" || conversion.provider === \"bitlabs\",\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion provider\",\n );\n assertEconomyIdentifier(conversion.providerEventId, \"providerEventId\");\n assertEconomyIdentifier(\n conversion.beneficiaryAccountId,\n \"beneficiaryAccountId\",\n );\n assertEconomyIdentifier(conversion.walletId, \"walletId\");\n economyAssert(\n [\"pending\", \"completed\", \"reconciled\"].includes(conversion.status),\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion status\",\n );\n economyAssert(\n /^[A-Z]{3}$/u.test(conversion.providerCurrency),\n \"INVALID_CONTRACT\",\n \"Reward payout currency must use an uppercase ISO code\",\n );\n economyAssert(\n parseNonNegativeInteger(\n conversion.providerPayoutMinorUnits,\n \"Provider payout\",\n ) > 0n &&\n parseNonNegativeInteger(conversion.gbpMinorUnits, \"GBP payout\") >= 0n &&\n parseTokenSubunits(conversion.tokenSubunits) > 0n,\n \"INVALID_AMOUNT\",\n \"Reward conversion must carry positive payout and Token values\",\n );\n assertEconomyIdentifier(conversion.rateVersion, \"rateVersion\");\n assertEconomyIdentifier(conversion.fxSnapshotId, \"fxSnapshotId\");\n parseIsoTimestamp(conversion.occurredAt);\n}\n\nfunction parseNonNegativeInteger(value: string, label: string): bigint {\n economyAssert(\n /^(?:0|[1-9][0-9]*)$/u.test(value),\n \"INVALID_AMOUNT\",\n `${label} must be a non-negative integer string`,\n );\n return BigInt(value);\n}\n\n/** Validates a paid pack; pack grants are whole Tokens in the baseline. */\nexport function assertTokenPack(pack: TokenPackV1): void {\n economyAssert(\n pack.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported Token pack contract version\",\n );\n assertEconomyIdentifier(pack.packId, \"packId\");\n assertEconomyIdentifier(pack.catalogVersion, \"catalogVersion\");\n economyAssert(\n pack.currency === \"GBP\" && typeof pack.active === \"boolean\",\n \"INVALID_CONTRACT\",\n \"Token packs must use GBP and declare whether they are active\",\n );\n economyAssert(\n parseNonNegativeInteger(pack.priceMinorUnits, \"Pack price\") > 0n,\n \"INVALID_AMOUNT\",\n \"Pack price must be positive\",\n );\n const grant = parseTokenSubunits(pack.grantAmount);\n economyAssert(\n grant > 0n && isWholeTokenAmount(grant),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Paid pack grants must contain whole Tokens\",\n );\n}\n\n/** Validates nominal reference metadata without creating redemption rights. */\nexport function assertTokenReferenceRate(\n rate: TokenReferenceRateV1,\n): void {\n economyAssert(\n rate.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported Token reference-rate contract version\",\n );\n assertEconomyIdentifier(rate.rateVersion, \"rateVersion\");\n const referenceMinorUnits = parseNonNegativeInteger(\n rate.referenceMinorUnitsPerToken,\n \"Reference minor units per Token\",\n );\n const subunitsPerToken = parseNonNegativeInteger(\n rate.tokenSubunitsPerToken,\n \"TokenSubunits per Token\",\n );\n economyAssert(\n rate.currency === \"GBP\" &&\n referenceMinorUnits > 0n &&\n subunitsPerToken === TOKEN_SUBUNITS_PER_TOKEN &&\n rate.cashRedemptionAllowed === false,\n \"INVALID_CONTRACT\",\n \"Token reference rate must preserve the GBP nominal, subunit, and no-redemption boundary\",\n );\n}\n\n/** Proves that every pack in one catalog uses the same flat nominal ratio. */\nexport function assertFlatTokenCatalog(\n packs: readonly TokenPackV1[],\n referenceRate: TokenReferenceRateV1,\n): void {\n assertTokenReferenceRate(referenceRate);\n economyAssert(\n packs.length > 0,\n \"INVALID_CONTRACT\",\n \"Token catalog must contain at least one pack\",\n );\n const packIds = new Set<string>();\n const catalogVersion = packs[0]?.catalogVersion;\n const referenceMinorUnits = BigInt(\n referenceRate.referenceMinorUnitsPerToken,\n );\n const subunitsPerToken = BigInt(referenceRate.tokenSubunitsPerToken);\n for (const pack of packs) {\n assertTokenPack(pack);\n economyAssert(\n !packIds.has(pack.packId),\n \"DUPLICATE_IDENTIFIER\",\n \"Token catalog pack IDs must be unique\",\n );\n economyAssert(\n pack.catalogVersion === catalogVersion,\n \"INVALID_CONTRACT\",\n \"Token catalog packs must share one catalog version\",\n );\n packIds.add(pack.packId);\n const scaledReference =\n parseTokenSubunits(pack.grantAmount) * referenceMinorUnits;\n economyAssert(\n scaledReference % subunitsPerToken === 0n &&\n scaledReference / subunitsPerToken === BigInt(pack.priceMinorUnits),\n \"INVALID_CONTRACT\",\n \"Token catalog must use the declared flat nominal reference ratio\",\n );\n }\n}\n\n/** Validates server-side order and rolling acquisition ceilings. */\nexport function assertPurchaseLimitPolicy(\n policy: PurchaseLimitPolicyV1,\n): void {\n economyAssert(\n policy.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported purchase-limit contract version\",\n );\n const maxOrder = parseNonNegativeInteger(\n policy.maxOrderPriceMinorUnits,\n \"Maximum order\",\n );\n const payer = parseNonNegativeInteger(\n policy.rollingPayerPriceMinorUnits,\n \"Rolling payer limit\",\n );\n const household = parseNonNegativeInteger(\n policy.rollingHouseholdPriceMinorUnits,\n \"Rolling household limit\",\n );\n economyAssert(\n maxOrder > 0n && payer >= maxOrder && household >= maxOrder,\n \"INVALID_AMOUNT\",\n \"Rolling purchase limits must cover at least one maximum order\",\n );\n economyAssert(\n Number.isSafeInteger(policy.rollingDays) &&\n policy.rollingDays >= 1 &&\n policy.rollingDays <= 365,\n \"INVALID_CONTRACT\",\n \"Purchase-limit rolling window must be a bounded whole-day count\",\n );\n}\n\n/** Validates the immutable server-side facts bound into a purchase intent. */\nexport function assertPurchaseIntentBinding(\n intent: PurchaseIntentV1,\n pack: TokenPackV1,\n): void {\n assertTokenPack(pack);\n economyAssert(\n intent.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported purchase-intent contract version\",\n );\n assertEconomyIdentifier(intent.intentId, \"intentId\");\n assertEconomyIdentifier(intent.payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(intent.receivingHouseholdId, \"receivingHouseholdId\");\n assertEconomyIdentifier(intent.receivingWalletId, \"receivingWalletId\");\n assertEconomyIdentifier(intent.packId, \"packId\");\n assertEconomyIdentifier(intent.catalogVersion, \"catalogVersion\");\n\n const createdAt = parseIsoTimestamp(intent.createdAt);\n const expiresAt = parseIsoTimestamp(intent.expiresAt);\n economyAssert(\n expiresAt > createdAt,\n \"INVALID_TIME_WINDOW\",\n \"Purchase intent expiry must follow its creation time\",\n );\n economyAssert(\n intent.expectedCurrency === \"GBP\" &&\n intent.packId === pack.packId &&\n intent.catalogVersion === pack.catalogVersion &&\n intent.expectedCurrency === pack.currency &&\n intent.expectedPriceMinorUnits === pack.priceMinorUnits &&\n intent.grantAmount === pack.grantAmount,\n \"INVALID_CONTRACT\",\n \"Purchase intent does not match its authoritative catalog pack\",\n );\n parseNonNegativeInteger(intent.expectedPriceMinorUnits, \"Expected price\");\n parseTokenSubunits(intent.grantAmount);\n economyAssert(\n [\n \"created\",\n \"checkout-created\",\n \"paid-unreconciled\",\n \"credited\",\n \"expired\",\n \"cancelled\",\n \"disputed\",\n ].includes(intent.status),\n \"INVALID_CONTRACT\",\n \"Purchase intent has an unsupported status\",\n );\n if (intent.providerCheckoutReferenceHash !== undefined) {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(intent.providerCheckoutReferenceHash),\n \"INVALID_CONTRACT\",\n \"Checkout references must be stored as sanitized SHA-256 hashes\",\n );\n }\n}\n\n/** Rejects stale, inactive, or already-consumed intents before checkout creation. */\nexport function assertOpenPurchaseIntent(\n intent: PurchaseIntentV1,\n pack: TokenPackV1,\n checkedAt: IsoTimestamp,\n): void {\n assertPurchaseIntentBinding(intent, pack);\n const checkedAtValue = parseIsoTimestamp(checkedAt);\n economyAssert(\n pack.active &&\n (intent.status === \"created\" || intent.status === \"checkout-created\") &&\n checkedAtValue >= parseIsoTimestamp(intent.createdAt) &&\n checkedAtValue < parseIsoTimestamp(intent.expiresAt),\n \"INVALID_TIME_WINDOW\",\n \"Purchase intent is inactive, expired, or not open for checkout\",\n );\n}\n\nexport function assertRewardRate(rate: RewardRateV1): void {\n economyAssert(\n rate.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported reward-rate contract version\",\n );\n assertEconomyIdentifier(rate.rateVersion, \"rateVersion\");\n economyAssert(\n rate.provider === \"ayet\" || rate.provider === \"bitlabs\",\n \"INVALID_CONTRACT\",\n \"Unsupported reward provider\",\n );\n const effectiveFrom = parseIsoTimestamp(rate.effectiveFrom);\n if (rate.effectiveUntil !== undefined) {\n economyAssert(\n parseIsoTimestamp(rate.effectiveUntil) > effectiveFrom,\n \"INVALID_TIME_WINDOW\",\n \"Reward-rate expiry must follow its effective time\",\n );\n }\n}\n\nexport function assertFxSnapshot(fx: FxSnapshotV1): void {\n economyAssert(\n fx.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported FX snapshot contract version\",\n );\n assertEconomyIdentifier(fx.snapshotId, \"snapshotId\");\n economyAssert(\n /^[A-Z]{3}$/u.test(fx.sourceCurrency) && fx.quoteCurrency === \"GBP\",\n \"INVALID_CONTRACT\",\n \"FX snapshots must convert an ISO currency into GBP\",\n );\n parseIsoTimestamp(fx.capturedAt);\n}\n\n/** Converts provider payout using exact rational FX and rate snapshots. */\nexport function convertRewardPayout(\n providerPayoutMinorUnits: string,\n rate: RewardRateV1,\n fx: FxSnapshotV1,\n): { readonly gbpMinorUnits: string; readonly tokenSubunits: TokenSubunitString } {\n assertRewardRate(rate);\n assertFxSnapshot(fx);\n const payout = parseNonNegativeInteger(\n providerPayoutMinorUnits,\n \"Provider payout\",\n );\n const fxNumerator = parseNonNegativeInteger(\n fx.gbpMinorUnitsNumerator,\n \"FX numerator\",\n );\n const fxDenominator = parseNonNegativeInteger(\n fx.sourceMinorUnitsDenominator,\n \"FX denominator\",\n );\n const tokenNumerator = parseNonNegativeInteger(\n rate.tokenSubunitsNumerator,\n \"Rate numerator\",\n );\n const tokenDenominator = parseNonNegativeInteger(\n rate.gbpMinorUnitsDenominator,\n \"Rate denominator\",\n );\n economyAssert(\n fxDenominator > 0n && tokenDenominator > 0n,\n \"INVALID_AMOUNT\",\n \"FX and reward-rate denominators must be positive\",\n );\n economyAssert(\n fxNumerator > 0n && tokenNumerator > 0n,\n \"INVALID_AMOUNT\",\n \"FX and reward-rate numerators must be positive\",\n );\n\n const gbpMinorUnits = (payout * fxNumerator) / fxDenominator;\n const tokenSubunits = (gbpMinorUnits * tokenNumerator) / tokenDenominator;\n return {\n gbpMinorUnits: gbpMinorUnits.toString(10),\n tokenSubunits: serializeTokenSubunits(tokenSubunits),\n };\n}\n\n/** Maps BitLabs' signed callback state into an immutable journal transition. */\nexport function mapBitLabsConversionState(\n state: string,\n): RewardActivityTransitionV1 {\n const transitions: Readonly<\n Record<BitLabsConversionState, RewardActivityTransitionV1>\n > = {\n PENDING: {\n conversionStatus: \"pending\",\n activityType: \"hold\",\n activityStatus: \"held\",\n },\n COMPLETED: {\n conversionStatus: \"completed\",\n activityType: \"offerwall\",\n activityStatus: \"settled\",\n },\n RECONCILED: {\n conversionStatus: \"reconciled\",\n activityType: \"reversal\",\n activityStatus: \"reversed\",\n },\n };\n const transition = transitions[state as BitLabsConversionState];\n economyAssert(\n transition !== undefined,\n \"INVALID_CONTRACT\",\n \"Unsupported BitLabs conversion state\",\n );\n return transition;\n}\n","import {\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n sumTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type AllocationId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport type { SourceLotSliceV1 } from \"./lots.js\";\n\nexport type AllocationStatus = \"active\" | \"closed\";\nexport type PeriodicLimitWindow = \"daily\" | \"weekly\" | \"monthly\";\n\nexport interface GameplayLimitsV1 {\n readonly perTransaction: TokenSubunitString;\n readonly periodic: TokenSubunitString;\n readonly periodicWindow: PeriodicLimitWindow;\n}\n\n/** Guardian-funded, child-visible reservation. This is not a gameplay ledger. */\nexport interface GameplayAllocationV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly allocationId: AllocationId;\n readonly householdId: HouseholdId;\n readonly hostWalletId: WalletId;\n readonly childWalletId: WalletId;\n readonly childAccountId: AccountId;\n readonly status: AllocationStatus;\n readonly reservedAmount: TokenSubunitString;\n readonly remainingAmount: TokenSubunitString;\n readonly reclaimedAmount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly reclaimedSlices: readonly SourceLotSliceV1[];\n readonly limits: GameplayLimitsV1;\n readonly version: number;\n readonly createdAt: IsoTimestamp;\n readonly updatedAt: IsoTimestamp;\n}\n\nfunction assertWholePositive(amount: TokenSubunitString, label: string): bigint {\n const parsed = parseTokenSubunits(amount);\n economyAssert(parsed > 0n, \"INVALID_AMOUNT\", `${label} must be positive`);\n economyAssert(\n isWholeTokenAmount(parsed),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n `${label} must contain whole Tokens`,\n );\n return parsed;\n}\n\nfunction assertSlices(\n slices: readonly SourceLotSliceV1[],\n expectedAmount: bigint,\n label: string,\n): void {\n economyAssert(slices.length > 0, \"INVALID_CONTRACT\", `${label} are required`);\n const lotIds = new Set<string>();\n for (const slice of slices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n economyAssert(\n !lotIds.has(slice.lotId),\n \"DUPLICATE_IDENTIFIER\",\n `${label} must not repeat a lot`,\n );\n lotIds.add(slice.lotId);\n economyAssert(\n parseTokenSubunits(slice.amount) > 0n,\n \"INVALID_AMOUNT\",\n `${label} amounts must be positive`,\n );\n }\n economyAssert(\n sumTokenSubunits(slices.map((slice) => slice.amount)) === expectedAmount,\n \"INVALID_CONTRACT\",\n `${label} must sum to the command amount`,\n );\n}\n\n/** Validates allocation arithmetic and whole-Token reservation policy. */\nexport function assertGameplayAllocation(\n allocation: GameplayAllocationV1,\n): void {\n economyAssert(\n allocation.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported allocation contract version\",\n );\n assertEconomyIdentifier(allocation.allocationId, \"allocationId\");\n assertEconomyIdentifier(allocation.householdId, \"householdId\");\n assertEconomyIdentifier(allocation.hostWalletId, \"hostWalletId\");\n assertEconomyIdentifier(allocation.childWalletId, \"childWalletId\");\n assertEconomyIdentifier(allocation.childAccountId, \"childAccountId\");\n const createdAt = parseIsoTimestamp(allocation.createdAt);\n const updatedAt = parseIsoTimestamp(allocation.updatedAt);\n economyAssert(\n updatedAt >= createdAt,\n \"INVALID_TIME_WINDOW\",\n \"Allocation update time cannot precede its creation time\",\n );\n economyAssert(\n allocation.status === \"active\" || allocation.status === \"closed\",\n \"INVALID_CONTRACT\",\n \"Allocation has an unsupported status\",\n );\n\n const reserved = parseTokenSubunits(allocation.reservedAmount);\n const remaining = parseTokenSubunits(allocation.remainingAmount);\n const reclaimed = parseTokenSubunits(allocation.reclaimedAmount);\n economyAssert(\n reserved > 0n &&\n remaining >= 0n &&\n reclaimed >= 0n &&\n isWholeTokenAmount(reserved) &&\n isWholeTokenAmount(remaining) &&\n isWholeTokenAmount(reclaimed),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Allocation reservations and reclaims must contain whole Tokens\",\n );\n economyAssert(\n remaining + reclaimed <= reserved,\n \"INVALID_CONTRACT\",\n \"Allocation remaining and reclaimed amounts exceed its reservation\",\n );\n\n const fundingByLot = new Map<string, bigint>();\n let funded = 0n;\n for (const slice of allocation.fundingSlices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n const amount = parseTokenSubunits(slice.amount);\n economyAssert(\n amount > 0n,\n \"INVALID_AMOUNT\",\n \"Allocation funding slices must be positive\",\n );\n funded += amount;\n fundingByLot.set(\n slice.lotId,\n (fundingByLot.get(slice.lotId) ?? 0n) + amount,\n );\n }\n economyAssert(\n funded === reserved,\n \"INVALID_CONTRACT\",\n \"Allocation funding provenance must equal its total reservation\",\n );\n\n const reclaimedByLot = new Map<string, bigint>();\n let reclaimedFromSlices = 0n;\n for (const slice of allocation.reclaimedSlices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n const amount = parseTokenSubunits(slice.amount);\n economyAssert(\n amount > 0n,\n \"INVALID_AMOUNT\",\n \"Allocation reclaim slices must be positive\",\n );\n reclaimedFromSlices += amount;\n reclaimedByLot.set(\n slice.lotId,\n (reclaimedByLot.get(slice.lotId) ?? 0n) + amount,\n );\n }\n economyAssert(\n reclaimedFromSlices === reclaimed,\n \"INVALID_CONTRACT\",\n \"Allocation reclaim provenance must equal its reclaimed amount\",\n );\n for (const [lotId, amount] of reclaimedByLot) {\n economyAssert(\n amount <= (fundingByLot.get(lotId) ?? 0n),\n \"SOURCE_LOT_RESTRICTED\",\n \"Reclaimed provenance cannot exceed allocation funding\",\n );\n }\n economyAssert(\n allocation.version >= 1 && Number.isSafeInteger(allocation.version),\n \"INVALID_CONTRACT\",\n \"Allocation version must be a positive safe integer\",\n );\n\n const perTransaction = parseTokenSubunits(allocation.limits.perTransaction);\n const periodic = parseTokenSubunits(allocation.limits.periodic);\n economyAssert(\n [\"daily\", \"weekly\", \"monthly\"].includes(allocation.limits.periodicWindow),\n \"INVALID_CONTRACT\",\n \"Gameplay limit has an unsupported period\",\n );\n economyAssert(\n perTransaction >= 0n &&\n periodic >= 0n &&\n isWholeTokenAmount(perTransaction) &&\n isWholeTokenAmount(periodic),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Gameplay limits must contain whole Tokens\",\n );\n economyAssert(\n perTransaction <= periodic || periodic === 0n,\n \"INVALID_CONTRACT\",\n \"Per-transaction limit cannot exceed an enabled periodic limit\",\n );\n}\n\nexport interface CreateGameplayAllocationInputV1 {\n readonly allocationId: AllocationId;\n readonly householdId: HouseholdId;\n readonly hostWalletId: WalletId;\n readonly childWalletId: WalletId;\n readonly childAccountId: AccountId;\n readonly amount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly limits: GameplayLimitsV1;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Creates a new whole-Token reservation from already-selected source lots. */\nexport function createGameplayAllocation(\n input: CreateGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n const amount = assertWholePositive(input.amount, \"Allocation amount\");\n assertSlices(input.fundingSlices, amount, \"Allocation funding slices\");\n const allocation: GameplayAllocationV1 = {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n allocationId: input.allocationId,\n householdId: input.householdId,\n hostWalletId: input.hostWalletId,\n childWalletId: input.childWalletId,\n childAccountId: input.childAccountId,\n status: \"active\",\n reservedAmount: input.amount,\n remainingAmount: input.amount,\n reclaimedAmount: serializeTokenSubunits(0n),\n fundingSlices: input.fundingSlices,\n reclaimedSlices: [],\n limits: input.limits,\n version: 1,\n createdAt: input.occurredAt,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(allocation);\n return allocation;\n}\n\nexport interface BoostGameplayAllocationInputV1 {\n readonly amount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly expectedVersion: number;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Returns the next immutable allocation state after a whole-Token boost. */\nexport function boostGameplayAllocation(\n allocation: GameplayAllocationV1,\n input: BoostGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n assertGameplayAllocation(allocation);\n economyAssert(\n allocation.status === \"active\" && allocation.version === input.expectedVersion,\n \"INVALID_CONTRACT\",\n \"Allocation is closed or its optimistic version is stale\",\n );\n const amount = assertWholePositive(input.amount, \"Boost amount\");\n assertSlices(input.fundingSlices, amount, \"Boost funding slices\");\n\n const next: GameplayAllocationV1 = {\n ...allocation,\n reservedAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.reservedAmount) + amount,\n ),\n remainingAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.remainingAmount) + amount,\n ),\n fundingSlices: [...allocation.fundingSlices, ...input.fundingSlices],\n version: allocation.version + 1,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(next);\n return next;\n}\n\nexport interface ReclaimGameplayAllocationInputV1 {\n readonly amount: TokenSubunitString;\n readonly sourceSlices: readonly SourceLotSliceV1[];\n readonly expectedVersion: number;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Reclaims unused whole Tokens without changing spent history. */\nexport function reclaimGameplayAllocation(\n allocation: GameplayAllocationV1,\n input: ReclaimGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n assertGameplayAllocation(allocation);\n economyAssert(\n allocation.status === \"active\" && allocation.version === input.expectedVersion,\n \"INVALID_CONTRACT\",\n \"Allocation is closed or its optimistic version is stale\",\n );\n const amount = assertWholePositive(input.amount, \"Reclaim amount\");\n economyAssert(\n amount <= parseTokenSubunits(allocation.remainingAmount),\n \"INSUFFICIENT_BALANCE\",\n \"Cannot reclaim more than the unused allocation\",\n );\n assertSlices(input.sourceSlices, amount, \"Reclaim source slices\");\n const fundedLotIds = new Set(\n allocation.fundingSlices.map((slice) => slice.lotId),\n );\n economyAssert(\n input.sourceSlices.every((slice) => fundedLotIds.has(slice.lotId)),\n \"SOURCE_LOT_RESTRICTED\",\n \"Reclaim slices must originate from the allocation\",\n );\n\n const remaining = parseTokenSubunits(allocation.remainingAmount) - amount;\n const next: GameplayAllocationV1 = {\n ...allocation,\n remainingAmount: serializeTokenSubunits(remaining),\n reclaimedAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.reclaimedAmount) + amount,\n ),\n reclaimedSlices: [...allocation.reclaimedSlices, ...input.sourceSlices],\n status: remaining === 0n ? \"closed\" : allocation.status,\n version: allocation.version + 1,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(next);\n return next;\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type LotId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport const PRE_UTILITY_BACKER_COHORT = \"pre_utility_backer_v1\" as const;\n\nexport interface EarlyBackerWindowV1 {\n readonly publicTokensLaunchAt: IsoTimestamp;\n readonly firstPublicSpendLiveAt?: IsoTimestamp;\n}\n\n/** Paid-lot facts required to recalculate retained early-backer basis. */\nexport interface PaidLotRetentionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly lotId: LotId;\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly purchaseId: string;\n readonly catalogVersion: string;\n readonly purchasedAt: IsoTimestamp;\n readonly settledAt: IsoTimestamp;\n readonly creditedAt: IsoTimestamp;\n readonly retainedAmount: TokenSubunitString;\n}\n\nexport interface EarlyBackerEvaluationV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly cohortKey: typeof PRE_UTILITY_BACKER_COHORT;\n readonly status: \"not-qualified\" | \"provisional\";\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly netRetainedAmount: TokenSubunitString;\n readonly contributingLotIds: readonly LotId[];\n readonly evaluatedAt: IsoTimestamp;\n}\n\nfunction isWithinWindow(\n timestamp: IsoTimestamp,\n launch: number,\n cutoff: number | undefined,\n): boolean {\n const value = parseIsoTimestamp(timestamp);\n return value >= launch && (cutoff === undefined || value < cutoff);\n}\n\n/**\n * Recalculates provisional cohort basis from retained paid lots. It promises no\n * future reward and deliberately has no permanent entitled state.\n */\nexport function evaluateEarlyBacker(\n payerAccountId: AccountId,\n receivingHouseholdId: HouseholdId,\n paidLots: readonly PaidLotRetentionV1[],\n window: EarlyBackerWindowV1,\n evaluatedAt: IsoTimestamp,\n): EarlyBackerEvaluationV1 {\n assertEconomyIdentifier(payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(receivingHouseholdId, \"receivingHouseholdId\");\n const launch = parseIsoTimestamp(window.publicTokensLaunchAt);\n const cutoff =\n window.firstPublicSpendLiveAt === undefined\n ? undefined\n : parseIsoTimestamp(window.firstPublicSpendLiveAt);\n economyAssert(\n cutoff === undefined || cutoff > launch,\n \"INVALID_TIME_WINDOW\",\n \"First public spend must occur after public Token launch\",\n );\n parseIsoTimestamp(evaluatedAt);\n\n let retained = 0n;\n const contributingLotIds: LotId[] = [];\n const seenLotIds = new Set<string>();\n for (const lot of paidLots) {\n economyAssert(\n lot.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported paid-lot retention contract version\",\n );\n assertEconomyIdentifier(lot.lotId, \"lotId\");\n economyAssert(\n !seenLotIds.has(lot.lotId),\n \"DUPLICATE_IDENTIFIER\",\n \"Paid-lot retention input must not repeat a source lot\",\n );\n seenLotIds.add(lot.lotId);\n assertEconomyIdentifier(lot.payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(lot.receivingHouseholdId, \"receivingHouseholdId\");\n assertEconomyIdentifier(lot.purchaseId, \"purchaseId\");\n assertEconomyIdentifier(lot.catalogVersion, \"catalogVersion\");\n const purchasedAt = parseIsoTimestamp(lot.purchasedAt);\n const settledAt = parseIsoTimestamp(lot.settledAt);\n const creditedAt = parseIsoTimestamp(lot.creditedAt);\n economyAssert(\n purchasedAt <= settledAt && settledAt <= creditedAt,\n \"INVALID_TIME_WINDOW\",\n \"Paid-lot timestamps must follow purchase, settlement, then credit order\",\n );\n if (\n lot.payerAccountId !== payerAccountId ||\n lot.receivingHouseholdId !== receivingHouseholdId\n ) {\n continue;\n }\n const inWindow =\n isWithinWindow(lot.purchasedAt, launch, cutoff) &&\n isWithinWindow(lot.settledAt, launch, cutoff) &&\n isWithinWindow(lot.creditedAt, launch, cutoff);\n const amount = parseTokenSubunits(lot.retainedAmount);\n economyAssert(\n amount >= 0n,\n \"INVALID_AMOUNT\",\n \"Retained paid-lot basis cannot be negative\",\n );\n if (inWindow && amount > 0n) {\n retained += amount;\n contributingLotIds.push(lot.lotId);\n }\n }\n\n return {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n cohortKey: PRE_UTILITY_BACKER_COHORT,\n status: retained > 0n ? \"provisional\" : \"not-qualified\",\n payerAccountId,\n receivingHouseholdId,\n netRetainedAmount: serializeTokenSubunits(retained),\n contributingLotIds: contributingLotIds.sort((left, right) =>\n left.localeCompare(right),\n ),\n evaluatedAt,\n };\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n sumTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n sortStringRecord,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type LotId,\n type PostingId,\n type ProviderEventId,\n type TransactionId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type ActivityType =\n | \"purchase\"\n | \"subscription\"\n | \"rewarded-ad\"\n | \"offerwall\"\n | \"allocation\"\n | \"boost\"\n | \"reclaim\"\n | \"spend\"\n | \"hold\"\n | \"refund\"\n | \"chargeback\"\n | \"adjustment\"\n | \"reversal\"\n | \"event\"\n | \"competition\";\n\nexport type ActivityStatus =\n | \"pending\"\n | \"held\"\n | \"settled\"\n | \"reversed\"\n | \"failed\";\n\nconst ACTIVITY_TYPES = new Set<ActivityType>([\n \"purchase\",\n \"subscription\",\n \"rewarded-ad\",\n \"offerwall\",\n \"allocation\",\n \"boost\",\n \"reclaim\",\n \"spend\",\n \"hold\",\n \"refund\",\n \"chargeback\",\n \"adjustment\",\n \"reversal\",\n \"event\",\n \"competition\",\n]);\n\nconst ACTIVITY_STATUSES = new Set<ActivityStatus>([\n \"pending\",\n \"held\",\n \"settled\",\n \"reversed\",\n \"failed\",\n]);\n\nfunction assertCanonicalHash(value: string, label: string): void {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(value),\n \"INVALID_CONTRACT\",\n `${label} must be a canonical SHA-256 reference`,\n );\n}\n\nfunction hasControlCharacters(value: string): boolean {\n return [...value].some((character) => {\n const code = character.charCodeAt(0);\n return code <= 31 || code === 127;\n });\n}\n\n/** One signed side of an immutable double-entry transaction. */\nexport interface LedgerPostingV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly postingId: PostingId;\n readonly transactionId: TransactionId;\n readonly accountId: AccountId;\n readonly walletId?: WalletId;\n readonly lotId?: LotId;\n readonly amount: TokenSubunitString;\n}\n\n/** Immutable transaction envelope. Posting amounts must sum to exactly zero. */\nexport interface LedgerTransactionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly transactionId: TransactionId;\n readonly activityType: ActivityType;\n readonly status: ActivityStatus;\n readonly idempotencyKey: string;\n readonly providerEventId?: ProviderEventId;\n readonly reversesTransactionId?: TransactionId;\n readonly effectiveAt: IsoTimestamp;\n readonly recordedAt: IsoTimestamp;\n readonly previousCanonicalHash?: string;\n readonly canonicalHash?: string;\n readonly metadata: Readonly<Record<string, string>>;\n readonly postings: readonly LedgerPostingV1[];\n}\n\n/** Privacy-safe, display-oriented journal entry returned by an API adapter. */\nexport interface ActivityEntryV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly transactionId: TransactionId;\n readonly activityType: ActivityType;\n readonly status: ActivityStatus;\n readonly occurredAt: IsoTimestamp;\n readonly amount: TokenSubunitString;\n readonly beneficiaryAccountId?: AccountId;\n readonly maskedReference?: string;\n readonly sourceLabel: string;\n}\n\n/** Validates one privacy-safe activity row returned by an HTTP adapter. */\nexport function assertActivityEntry(entry: ActivityEntryV1): void {\n economyAssert(\n entry.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported activity-entry contract version\",\n );\n assertEconomyIdentifier(entry.transactionId, \"transactionId\");\n economyAssert(\n ACTIVITY_TYPES.has(entry.activityType) &&\n ACTIVITY_STATUSES.has(entry.status),\n \"INVALID_CONTRACT\",\n \"Activity type or status is unsupported\",\n );\n parseIsoTimestamp(entry.occurredAt);\n economyAssert(\n parseTokenSubunits(entry.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Activity entries cannot contain a zero amount\",\n );\n if (entry.beneficiaryAccountId !== undefined) {\n assertEconomyIdentifier(\n entry.beneficiaryAccountId,\n \"beneficiaryAccountId\",\n );\n }\n if (entry.maskedReference !== undefined) {\n economyAssert(\n entry.maskedReference.length > 0 &&\n entry.maskedReference.length <= 128 &&\n !hasControlCharacters(entry.maskedReference),\n \"INVALID_CONTRACT\",\n \"Masked activity references must be bounded and safe for display\",\n );\n }\n economyAssert(\n entry.sourceLabel.trim().length > 0 &&\n entry.sourceLabel.length <= 128 &&\n !hasControlCharacters(entry.sourceLabel),\n \"INVALID_CONTRACT\",\n \"Activity source labels must be bounded and safe for display\",\n );\n}\n\n/** Proves the structural and arithmetic invariants of one transaction. */\nexport function assertBalancedTransaction(\n transaction: LedgerTransactionV1,\n): void {\n economyAssert(\n transaction.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported ledger contract version\",\n );\n assertEconomyIdentifier(transaction.transactionId, \"transactionId\");\n assertEconomyIdentifier(transaction.idempotencyKey, \"idempotencyKey\");\n economyAssert(\n ACTIVITY_TYPES.has(transaction.activityType) &&\n ACTIVITY_STATUSES.has(transaction.status),\n \"INVALID_CONTRACT\",\n \"Transaction activity type or status is unsupported\",\n );\n if (transaction.providerEventId !== undefined) {\n assertEconomyIdentifier(transaction.providerEventId, \"providerEventId\");\n }\n if (transaction.reversesTransactionId !== undefined) {\n assertEconomyIdentifier(\n transaction.reversesTransactionId,\n \"reversesTransactionId\",\n );\n }\n economyAssert(\n (transaction.activityType === \"reversal\") ===\n (transaction.reversesTransactionId !== undefined),\n \"INVALID_CONTRACT\",\n \"Reversal transactions must identify exactly one original transaction\",\n );\n const effectiveAt = parseIsoTimestamp(transaction.effectiveAt);\n const recordedAt = parseIsoTimestamp(transaction.recordedAt);\n economyAssert(\n recordedAt >= effectiveAt,\n \"INVALID_TIME_WINDOW\",\n \"Transaction recording time cannot precede its effective time\",\n );\n if (transaction.previousCanonicalHash !== undefined) {\n assertCanonicalHash(\n transaction.previousCanonicalHash,\n \"Previous canonical hash\",\n );\n }\n if (transaction.canonicalHash !== undefined) {\n assertCanonicalHash(transaction.canonicalHash, \"Canonical hash\");\n }\n const metadataEntries = Object.entries(transaction.metadata);\n economyAssert(\n metadataEntries.length <= 32 &&\n metadataEntries.every(\n ([key, value]) =>\n /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(key) &&\n value.length <= 512 &&\n !hasControlCharacters(value),\n ),\n \"INVALID_CONTRACT\",\n \"Transaction metadata must be bounded and free of control characters\",\n );\n economyAssert(\n transaction.postings.length >= 2,\n \"UNBALANCED_TRANSACTION\",\n \"A ledger transaction needs at least two postings\",\n );\n\n const postingIds = new Set<string>();\n for (const posting of transaction.postings) {\n economyAssert(\n posting.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported posting contract version\",\n );\n assertEconomyIdentifier(posting.postingId, \"postingId\");\n assertEconomyIdentifier(posting.accountId, \"accountId\");\n if (posting.walletId !== undefined) {\n assertEconomyIdentifier(posting.walletId, \"walletId\");\n }\n if (posting.lotId !== undefined) {\n assertEconomyIdentifier(posting.lotId, \"lotId\");\n }\n economyAssert(\n posting.transactionId === transaction.transactionId,\n \"INVALID_CONTRACT\",\n \"Posting transactionId must match its transaction\",\n );\n economyAssert(\n !postingIds.has(posting.postingId),\n \"DUPLICATE_IDENTIFIER\",\n \"Posting identifiers must be unique within a transaction\",\n );\n postingIds.add(posting.postingId);\n economyAssert(\n parseTokenSubunits(posting.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Zero-value postings are not permitted\",\n );\n }\n\n economyAssert(\n sumTokenSubunits(transaction.postings.map((posting) => posting.amount)) ===\n 0n,\n \"UNBALANCED_TRANSACTION\",\n \"Ledger postings must sum to zero TokenSubunits\",\n );\n}\n\n/**\n * Produces deterministic UTF-8 JSON for an approved SHA-256/HSM adapter.\n * Hashing itself deliberately remains outside this provider-neutral package.\n */\nexport function canonicalTransactionPayload(\n transaction: LedgerTransactionV1,\n): string {\n assertBalancedTransaction(transaction);\n const postings = [...transaction.postings]\n .sort((left, right) => left.postingId.localeCompare(right.postingId))\n .map((posting) => ({\n schemaVersion: posting.schemaVersion,\n postingId: posting.postingId,\n transactionId: posting.transactionId,\n accountId: posting.accountId,\n ...(posting.walletId === undefined ? {} : { walletId: posting.walletId }),\n ...(posting.lotId === undefined ? {} : { lotId: posting.lotId }),\n amount: posting.amount,\n }));\n\n return JSON.stringify({\n schemaVersion: transaction.schemaVersion,\n transactionId: transaction.transactionId,\n activityType: transaction.activityType,\n status: transaction.status,\n idempotencyKey: transaction.idempotencyKey,\n ...(transaction.providerEventId === undefined\n ? {}\n : { providerEventId: transaction.providerEventId }),\n ...(transaction.reversesTransactionId === undefined\n ? {}\n : { reversesTransactionId: transaction.reversesTransactionId }),\n effectiveAt: transaction.effectiveAt,\n recordedAt: transaction.recordedAt,\n ...(transaction.previousCanonicalHash === undefined\n ? {}\n : { previousCanonicalHash: transaction.previousCanonicalHash }),\n metadata: sortStringRecord(transaction.metadata),\n postings,\n });\n}\n\nexport interface ReversalInputV1 {\n readonly transactionId: TransactionId;\n readonly postingIds: readonly PostingId[];\n readonly idempotencyKey: string;\n readonly effectiveAt: IsoTimestamp;\n readonly recordedAt: IsoTimestamp;\n readonly metadata?: Readonly<Record<string, string>>;\n readonly previousCanonicalHash?: string;\n}\n\n/** Creates an immutable compensating transaction; it never edits the original. */\nexport function createReversalTransaction(\n original: LedgerTransactionV1,\n input: ReversalInputV1,\n): LedgerTransactionV1 {\n assertBalancedTransaction(original);\n economyAssert(\n original.reversesTransactionId === undefined,\n \"INVALID_CONTRACT\",\n \"A reversal cannot itself be reversed by this helper\",\n );\n economyAssert(\n input.postingIds.length === original.postings.length,\n \"INVALID_CONTRACT\",\n \"A reversal needs one new posting identifier per original posting\",\n );\n\n const postings = original.postings.map((posting, index) => {\n const postingId = input.postingIds[index];\n economyAssert(\n postingId !== undefined,\n \"INVALID_CONTRACT\",\n \"Missing reversal posting identifier\",\n );\n return {\n ...posting,\n postingId,\n transactionId: input.transactionId,\n amount: serializeTokenSubunits(-parseTokenSubunits(posting.amount)),\n } satisfies LedgerPostingV1;\n });\n\n const transaction: LedgerTransactionV1 = {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n transactionId: input.transactionId,\n activityType: \"reversal\",\n status: \"settled\",\n idempotencyKey: input.idempotencyKey,\n reversesTransactionId: original.transactionId,\n effectiveAt: input.effectiveAt,\n recordedAt: input.recordedAt,\n ...(input.previousCanonicalHash === undefined\n ? {}\n : { previousCanonicalHash: input.previousCanonicalHash }),\n metadata: input.metadata ?? {},\n postings,\n };\n assertBalancedTransaction(transaction);\n return transaction;\n}\n\n/** Rejects a second effective reversal for the same original transaction. */\nexport function assertReversalAvailable(\n originalTransactionId: TransactionId,\n existingTransactions: readonly LedgerTransactionV1[],\n): void {\n assertEconomyIdentifier(originalTransactionId, \"originalTransactionId\");\n economyAssert(\n !existingTransactions.some(\n (transaction) =>\n transaction.reversesTransactionId === originalTransactionId &&\n transaction.status !== \"failed\",\n ),\n \"REVERSAL_ALREADY_EXISTS\",\n \"The transaction already has an effective reversal\",\n );\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type LotId,\n type ProviderEventId,\n type WalletId,\n} from \"./contracts.js\";\nimport { EconomyError, economyAssert } from \"./errors.js\";\n\nexport type TokenSource =\n | \"shopify\"\n | \"ayet\"\n | \"bitlabs\"\n | \"subscription\"\n | \"event\"\n | \"competition\"\n | \"adjustment\";\n\nexport type LotTransferPolicy =\n | \"household-allocatable\"\n | \"same-user-only\"\n | \"non-transferable\";\n\nexport type LotRefundState =\n | \"none\"\n | \"partial\"\n | \"refunded\"\n | \"disputed\"\n | \"chargeback-lost\";\n\nexport interface SourceLotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly lotId: LotId;\n readonly walletId: WalletId;\n readonly beneficiaryAccountId: AccountId;\n readonly householdId?: HouseholdId;\n readonly payerAccountId?: AccountId;\n readonly source: TokenSource;\n readonly providerEventId?: ProviderEventId;\n readonly rateVersion: string;\n readonly settlementEvidenceHash: string;\n readonly transferPolicy: LotTransferPolicy;\n readonly refundState: LotRefundState;\n readonly originalAmount: TokenSubunitString;\n readonly remainingAmount: TokenSubunitString;\n readonly heldAmount: TokenSubunitString;\n readonly reversedAmount: TokenSubunitString;\n readonly settledAt: IsoTimestamp;\n readonly creditedAt: IsoTimestamp;\n readonly cohortKey?: string;\n}\n\nexport type LotUseOperation = \"allocate\" | \"spend\" | \"reclaim\" | \"refund\";\n\nexport interface LotUseContextV1 {\n readonly operation: LotUseOperation;\n readonly beneficiaryAccountId: AccountId;\n readonly householdId?: HouseholdId;\n}\n\nexport interface SourceLotSliceV1 {\n readonly lotId: LotId;\n readonly amount: TokenSubunitString;\n}\n\n/** Validates source-lot arithmetic, evidence, and immutable provenance fields. */\nexport function assertSourceLot(lot: SourceLotV1): void {\n economyAssert(\n lot.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported source-lot contract version\",\n );\n assertEconomyIdentifier(lot.lotId, \"lotId\");\n assertEconomyIdentifier(lot.walletId, \"walletId\");\n assertEconomyIdentifier(lot.beneficiaryAccountId, \"beneficiaryAccountId\");\n if (lot.householdId !== undefined) {\n assertEconomyIdentifier(lot.householdId, \"householdId\");\n }\n if (lot.payerAccountId !== undefined) {\n assertEconomyIdentifier(lot.payerAccountId, \"payerAccountId\");\n }\n if (lot.providerEventId !== undefined) {\n assertEconomyIdentifier(lot.providerEventId, \"providerEventId\");\n }\n assertEconomyIdentifier(lot.rateVersion, \"rateVersion\");\n economyAssert(\n [\n \"shopify\",\n \"ayet\",\n \"bitlabs\",\n \"subscription\",\n \"event\",\n \"competition\",\n \"adjustment\",\n ].includes(lot.source),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported source\",\n );\n economyAssert(\n [\"household-allocatable\", \"same-user-only\", \"non-transferable\"].includes(\n lot.transferPolicy,\n ),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported transfer policy\",\n );\n economyAssert(\n [\"none\", \"partial\", \"refunded\", \"disputed\", \"chargeback-lost\"].includes(\n lot.refundState,\n ),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported refund state\",\n );\n if (lot.source === \"ayet\" || lot.source === \"bitlabs\") {\n economyAssert(\n lot.transferPolicy === \"same-user-only\" &&\n lot.providerEventId !== undefined,\n \"SOURCE_LOT_RESTRICTED\",\n \"Reward-provider lots must remain with the earning account\",\n );\n }\n if (lot.source === \"shopify\") {\n economyAssert(\n lot.transferPolicy === \"household-allocatable\" &&\n lot.householdId !== undefined &&\n lot.payerAccountId !== undefined,\n \"INVALID_CONTRACT\",\n \"Shopify lots must retain payer and receiving-household provenance\",\n );\n }\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(lot.settlementEvidenceHash),\n \"INVALID_CONTRACT\",\n \"Settlement evidence must be a sanitized SHA-256 reference\",\n );\n const settledAt = parseIsoTimestamp(lot.settledAt);\n const creditedAt = parseIsoTimestamp(lot.creditedAt);\n economyAssert(\n creditedAt >= settledAt,\n \"INVALID_TIME_WINDOW\",\n \"Source-lot credit time cannot precede settlement\",\n );\n if (lot.cohortKey !== undefined) {\n assertEconomyIdentifier(lot.cohortKey, \"cohortKey\");\n }\n\n const original = parseTokenSubunits(lot.originalAmount);\n const remaining = parseTokenSubunits(lot.remainingAmount);\n const held = parseTokenSubunits(lot.heldAmount);\n const reversed = parseTokenSubunits(lot.reversedAmount);\n economyAssert(\n original > 0n && remaining >= 0n && held >= 0n && reversed >= 0n,\n \"INVALID_AMOUNT\",\n \"Source-lot amounts must be non-negative and original must be positive\",\n );\n economyAssert(\n remaining <= original && held <= remaining && reversed <= original,\n \"INVALID_CONTRACT\",\n \"Source-lot amount components exceed the original or remaining amount\",\n );\n economyAssert(\n remaining + reversed <= original,\n \"INVALID_CONTRACT\",\n \"Remaining and reversed source-lot amounts exceed the original\",\n );\n}\n\n/** Returns unheld, unconsumed TokenSubunits in a source lot. */\nexport function availableSourceLotAmount(lot: SourceLotV1): bigint {\n assertSourceLot(lot);\n return (\n parseTokenSubunits(lot.remainingAmount) - parseTokenSubunits(lot.heldAmount)\n );\n}\n\n/** Evaluates provider/source restrictions without trusting a browser claim. */\nexport function canUseSourceLot(\n lot: SourceLotV1,\n context: LotUseContextV1,\n): boolean {\n if (context.operation === \"refund\") {\n return true;\n }\n\n if (context.operation === \"allocate\" || context.operation === \"reclaim\") {\n return (\n lot.transferPolicy === \"household-allocatable\" &&\n lot.householdId !== undefined &&\n lot.householdId === context.householdId\n );\n }\n\n if (lot.transferPolicy === \"household-allocatable\") {\n return (\n lot.householdId !== undefined && lot.householdId === context.householdId\n );\n }\n\n return lot.beneficiaryAccountId === context.beneficiaryAccountId;\n}\n\n/**\n * Selects eligible lots deterministically in credited-time/lot-id order.\n * The returned slices are a proposal; persistence must consume them atomically.\n */\nexport function selectSourceLots(\n lots: readonly SourceLotV1[],\n requestedAmount: TokenSubunitString,\n context: LotUseContextV1,\n): readonly SourceLotSliceV1[] {\n const requested = parseTokenSubunits(requestedAmount);\n economyAssert(\n requested > 0n,\n \"INVALID_AMOUNT\",\n \"Requested source-lot amount must be positive\",\n );\n assertEconomyIdentifier(context.beneficiaryAccountId, \"beneficiaryAccountId\");\n\n const ordered = [...lots].sort((left, right) => {\n const timeDifference =\n parseIsoTimestamp(left.creditedAt) - parseIsoTimestamp(right.creditedAt);\n return timeDifference === 0\n ? left.lotId.localeCompare(right.lotId)\n : timeDifference;\n });\n\n let allAvailable = 0n;\n let remaining = requested;\n const slices: SourceLotSliceV1[] = [];\n\n for (const lot of ordered) {\n const available = availableSourceLotAmount(lot);\n allAvailable += available;\n if (available === 0n || !canUseSourceLot(lot, context)) {\n continue;\n }\n const selected = available < remaining ? available : remaining;\n slices.push({ lotId: lot.lotId, amount: serializeTokenSubunits(selected) });\n remaining -= selected;\n if (remaining === 0n) {\n return slices;\n }\n }\n\n if (allAvailable >= requested) {\n throw new EconomyError(\n \"SOURCE_LOT_RESTRICTED\",\n \"Available source lots do not permit this operation\",\n );\n }\n throw new EconomyError(\n \"INSUFFICIENT_ELIGIBLE_LOTS\",\n \"Insufficient eligible source-lot balance\",\n );\n}\n","import { parseTokenSubunits, type TokenSubunitString } from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type AdjustmentStatus =\n | \"draft\"\n | \"pending-approval\"\n | \"approved\"\n | \"rejected\"\n | \"executed\"\n | \"expired\";\n\n/** Dual-control request; the resulting change is always a ledger transaction. */\nexport interface AdjustmentRequestV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly adjustmentId: string;\n readonly walletId: WalletId;\n readonly amount: TokenSubunitString;\n readonly reason: string;\n readonly ticketReference: string;\n readonly status: AdjustmentStatus;\n readonly initiatedByAccountId: AccountId;\n readonly initiatedAt: IsoTimestamp;\n readonly approvedByAccountId?: AccountId;\n readonly approvedAt?: IsoTimestamp;\n readonly resultingTransactionId?: TransactionId;\n}\n\n/** Proves that production adjustment approval was performed by another actor. */\nexport function assertDistinctAdjustmentApproval(\n request: AdjustmentRequestV1,\n): void {\n economyAssert(\n request.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported adjustment contract version\",\n );\n assertEconomyIdentifier(request.adjustmentId, \"adjustmentId\");\n assertEconomyIdentifier(request.walletId, \"walletId\");\n assertEconomyIdentifier(request.initiatedByAccountId, \"initiatedByAccountId\");\n economyAssert(\n parseTokenSubunits(request.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Adjustment amount cannot be zero\",\n );\n economyAssert(\n request.reason.trim().length > 0 && request.reason.length <= 512,\n \"INVALID_CONTRACT\",\n \"Adjustment reason is required and must be bounded\",\n );\n assertEconomyIdentifier(request.ticketReference, \"ticketReference\");\n const initiatedAt = parseIsoTimestamp(request.initiatedAt);\n economyAssert(\n request.approvedByAccountId !== undefined &&\n request.approvedByAccountId !== request.initiatedByAccountId,\n \"INVALID_CONTRACT\",\n \"Adjustment approval requires a distinct authorized operator\",\n );\n assertEconomyIdentifier(request.approvedByAccountId, \"approvedByAccountId\");\n economyAssert(\n request.approvedAt !== undefined &&\n parseIsoTimestamp(request.approvedAt) >= initiatedAt,\n \"INVALID_TIME_WINDOW\",\n \"Adjustment approval time must follow initiation\",\n );\n economyAssert(\n request.status === \"approved\" || request.status === \"executed\",\n \"INVALID_CONTRACT\",\n \"Only approved adjustments satisfy dual-control approval\",\n );\n if (request.resultingTransactionId !== undefined) {\n assertEconomyIdentifier(\n request.resultingTransactionId,\n \"resultingTransactionId\",\n );\n }\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport {\n assertBalancedTransaction,\n type LedgerTransactionV1,\n} from \"./ledger.js\";\n\nexport type BalanceProjection = Readonly<Record<AccountId, TokenSubunitString>>;\n\nexport interface BalanceProjectionSnapshotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly balances: BalanceProjection;\n readonly lastTransactionId?: TransactionId;\n readonly rebuiltAt: IsoTimestamp;\n}\n\n/** Applies one balanced transaction without mutating the existing projection. */\nexport function applyTransactionToProjection(\n current: BalanceProjection,\n transaction: LedgerTransactionV1,\n): BalanceProjection {\n assertBalancedTransaction(transaction);\n const next: Record<AccountId, TokenSubunitString> = { ...current };\n for (const posting of transaction.postings) {\n const prior = parseTokenSubunits(next[posting.accountId] ?? \"0\");\n next[posting.accountId] = serializeTokenSubunits(\n prior + parseTokenSubunits(posting.amount),\n );\n }\n return next;\n}\n\n/**\n * Rebuilds balances deterministically and rejects duplicate economic envelopes.\n */\nexport function rebuildBalanceProjection(\n transactions: readonly LedgerTransactionV1[],\n): BalanceProjection {\n let projection: BalanceProjection = {};\n const transactionIds = new Set<string>();\n const idempotencyKeys = new Set<string>();\n const providerEvents = new Set<string>();\n\n for (const transaction of transactions) {\n economyAssert(\n !transactionIds.has(transaction.transactionId),\n \"DUPLICATE_TRANSACTION\",\n \"Transaction identifiers must be unique\",\n );\n economyAssert(\n !idempotencyKeys.has(transaction.idempotencyKey),\n \"DUPLICATE_TRANSACTION\",\n \"Idempotency keys must be unique\",\n );\n if (transaction.providerEventId !== undefined) {\n economyAssert(\n !providerEvents.has(transaction.providerEventId),\n \"DUPLICATE_TRANSACTION\",\n \"Provider event identifiers must be unique\",\n );\n providerEvents.add(transaction.providerEventId);\n }\n transactionIds.add(transaction.transactionId);\n idempotencyKeys.add(transaction.idempotencyKey);\n projection = applyTransactionToProjection(projection, transaction);\n }\n\n return projection;\n}\n\n/** Enforces non-negative balances only for spendable/reservable accounts. */\nexport function assertNonNegativeAccounts(\n projection: BalanceProjection,\n protectedAccountIds: readonly AccountId[],\n): void {\n for (const accountId of protectedAccountIds) {\n economyAssert(\n parseTokenSubunits(projection[accountId] ?? \"0\") >= 0n,\n \"NEGATIVE_PROJECTION\",\n \"A protected economy account would become negative\",\n );\n }\n}\n\n/** Creates a versioned snapshot after a deterministic rebuild. */\nexport function createProjectionSnapshot(\n transactions: readonly LedgerTransactionV1[],\n rebuiltAt: IsoTimestamp,\n): BalanceProjectionSnapshotV1 {\n parseIsoTimestamp(rebuiltAt);\n const last = transactions.at(-1);\n return {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n balances: rebuildBalanceProjection(transactions),\n ...(last === undefined ? {} : { lastTransactionId: last.transactionId }),\n rebuiltAt,\n };\n}\n","import {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type EconomyContractVersion,\n type IsoTimestamp,\n} from \"./contracts.js\";\nimport {\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type RecurrenceInterval = \"daily\" | \"weekly\" | \"monthly\";\n\n/** Provider-neutral subscription contract. Site policy controls enablement. */\nexport interface TokenSubscriptionPlanV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly planId: string;\n readonly catalogVersion: string;\n readonly interval: RecurrenceInterval;\n readonly priceMinorUnits: string;\n readonly currency: \"GBP\";\n readonly grantAmount: TokenSubunitString;\n readonly enabled: boolean;\n readonly effectiveFrom: IsoTimestamp;\n}\n\n/** Future convenience plan contract; disabled until public spend is live. */\nexport const BASELINE_MONTHLY_SUBSCRIPTION_PLAN: TokenSubscriptionPlanV1 =\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n planId: \"monthly-10-100-v1\",\n catalogVersion: \"gbp-subscriptions-v1\",\n interval: \"monthly\",\n priceMinorUnits: \"1000\",\n currency: \"GBP\",\n grantAmount: serializeTokenSubunits(100_000n),\n enabled: false,\n effectiveFrom: \"2026-07-15T00:00:00.000Z\",\n });\n\n/** Validates future provider-neutral recurrence without enabling it. */\nexport function assertTokenSubscriptionPlan(\n plan: TokenSubscriptionPlanV1,\n): void {\n economyAssert(\n plan.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported subscription-plan contract version\",\n );\n assertEconomyIdentifier(plan.planId, \"planId\");\n assertEconomyIdentifier(plan.catalogVersion, \"catalogVersion\");\n economyAssert(\n [\"daily\", \"weekly\", \"monthly\"].includes(plan.interval) &&\n plan.currency === \"GBP\" &&\n typeof plan.enabled === \"boolean\",\n \"INVALID_CONTRACT\",\n \"Subscription recurrence, currency, or enabled state is invalid\",\n );\n economyAssert(\n /^(?:0|[1-9][0-9]*)$/u.test(plan.priceMinorUnits) &&\n BigInt(plan.priceMinorUnits) > 0n,\n \"INVALID_AMOUNT\",\n \"Subscription price must be a positive integer minor-unit string\",\n );\n const grantAmount = parseTokenSubunits(plan.grantAmount);\n economyAssert(\n grantAmount > 0n && isWholeTokenAmount(grantAmount),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Subscription grants must contain whole Tokens\",\n );\n parseIsoTimestamp(plan.effectiveFrom);\n}\n","import { parseTokenSubunits, type TokenSubunitString } from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type AllocationId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type SpendRequestPurpose = \"gameplay-conversion\" | \"non-gameplay\";\nexport type SpendRequestStatus =\n | \"requested\"\n | \"approved\"\n | \"rejected\"\n | \"expired\"\n | \"executed\"\n | \"cancelled\";\n\n/** Future child request; baseline adapters must reject creation while disabled. */\nexport interface SpendRequestV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly requestId: string;\n readonly childAccountId: AccountId;\n readonly allocationId: AllocationId;\n readonly purpose: SpendRequestPurpose;\n readonly amount: TokenSubunitString;\n readonly status: SpendRequestStatus;\n readonly requestedAt: IsoTimestamp;\n readonly expiresAt: IsoTimestamp;\n readonly decidedByAccountId?: AccountId;\n readonly decidedAt?: IsoTimestamp;\n readonly approvalNonceHash?: string;\n readonly resultingTransactionId?: TransactionId;\n}\n\n/** Validates future child requests while creation remains policy-disabled. */\nexport function assertSpendRequest(request: SpendRequestV1): void {\n economyAssert(\n request.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported spend-request contract version\",\n );\n assertEconomyIdentifier(request.requestId, \"requestId\");\n assertEconomyIdentifier(request.childAccountId, \"childAccountId\");\n assertEconomyIdentifier(request.allocationId, \"allocationId\");\n economyAssert(\n request.purpose === \"gameplay-conversion\" ||\n request.purpose === \"non-gameplay\",\n \"INVALID_CONTRACT\",\n \"Spend request has an unsupported purpose\",\n );\n economyAssert(\n [\n \"requested\",\n \"approved\",\n \"rejected\",\n \"expired\",\n \"executed\",\n \"cancelled\",\n ].includes(request.status),\n \"INVALID_CONTRACT\",\n \"Spend request has an unsupported status\",\n );\n economyAssert(\n parseTokenSubunits(request.amount) > 0n,\n \"INVALID_AMOUNT\",\n \"Spend-request amount must be positive\",\n );\n const requestedAt = parseIsoTimestamp(request.requestedAt);\n const expiresAt = parseIsoTimestamp(request.expiresAt);\n economyAssert(\n expiresAt > requestedAt,\n \"INVALID_TIME_WINDOW\",\n \"Spend-request expiry must follow creation\",\n );\n\n const decisionRequired = [\"approved\", \"rejected\", \"executed\"].includes(\n request.status,\n );\n economyAssert(\n !decisionRequired ||\n (request.decidedByAccountId !== undefined &&\n request.decidedAt !== undefined),\n \"INVALID_CONTRACT\",\n \"Decided spend requests require a guardian actor and timestamp\",\n );\n if (request.decidedByAccountId !== undefined) {\n assertEconomyIdentifier(request.decidedByAccountId, \"decidedByAccountId\");\n }\n if (request.decidedAt !== undefined) {\n const decidedAt = parseIsoTimestamp(request.decidedAt);\n economyAssert(\n decidedAt >= requestedAt && decidedAt <= expiresAt,\n \"INVALID_TIME_WINDOW\",\n \"Spend-request decision must occur before expiry\",\n );\n }\n if (request.approvalNonceHash !== undefined) {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(request.approvalNonceHash),\n \"INVALID_CONTRACT\",\n \"Approval nonces must be stored as SHA-256 hashes\",\n );\n }\n if (request.status === \"approved\" || request.status === \"executed\") {\n economyAssert(\n request.approvalNonceHash !== undefined,\n \"INVALID_CONTRACT\",\n \"Approved spend requests require a one-time approval nonce hash\",\n );\n }\n if (request.resultingTransactionId !== undefined) {\n assertEconomyIdentifier(\n request.resultingTransactionId,\n \"resultingTransactionId\",\n );\n economyAssert(\n request.status === \"executed\",\n \"INVALID_CONTRACT\",\n \"Only executed spend requests may reference a ledger transaction\",\n );\n }\n}\n","import {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type WalletId,\n} from \"./contracts.js\";\nimport {\n parseTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type WalletKind =\n | \"household-treasury\"\n | \"personal\"\n | \"gameplay-allocation\"\n | \"hold\"\n | \"purchase-clearing\"\n | \"provider-clearing\"\n | \"system\";\n\nexport type WalletStatus = \"active\" | \"restricted\" | \"closed\";\nexport type WalletOwnerType = \"account\" | \"household\" | \"system\";\n\n/** Versioned authoritative wallet descriptor. */\nexport interface WalletV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly walletId: WalletId;\n readonly accountId: AccountId;\n readonly kind: WalletKind;\n readonly ownerType: WalletOwnerType;\n readonly ownerId: AccountId | HouseholdId | \"system\";\n readonly householdId?: HouseholdId;\n readonly status: WalletStatus;\n readonly version: number;\n readonly createdAt: IsoTimestamp;\n readonly closedAt?: IsoTimestamp;\n}\n\n/** Server-computed wallet totals. Clients must never derive authority from it. */\nexport interface WalletBalanceSummaryV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly walletId: WalletId;\n readonly available: TokenSubunitString;\n readonly reserved: TokenSubunitString;\n readonly held: TokenSubunitString;\n readonly rewardProgress: TokenSubunitString;\n readonly version: number;\n readonly asOf: IsoTimestamp;\n}\n\n/** Lifetime aggregates used by the Token profile. */\nexport interface WalletLifetimeTotalsV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly bought: TokenSubunitString;\n readonly earned: TokenSubunitString;\n readonly allocated: TokenSubunitString;\n readonly reclaimed: TokenSubunitString;\n readonly spent: TokenSubunitString;\n readonly reversed: TokenSubunitString;\n}\n\n/** Validates wallet ownership, lifecycle, and optimistic-version facts. */\nexport function assertWallet(wallet: WalletV1): void {\n economyAssert(\n wallet.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet contract version\",\n );\n assertEconomyIdentifier(wallet.walletId, \"walletId\");\n assertEconomyIdentifier(wallet.accountId, \"accountId\");\n economyAssert(\n [\n \"household-treasury\",\n \"personal\",\n \"gameplay-allocation\",\n \"hold\",\n \"purchase-clearing\",\n \"provider-clearing\",\n \"system\",\n ].includes(wallet.kind),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported kind\",\n );\n economyAssert(\n [\"account\", \"household\", \"system\"].includes(wallet.ownerType),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported owner type\",\n );\n economyAssert(\n [\"active\", \"restricted\", \"closed\"].includes(wallet.status),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported status\",\n );\n if (wallet.ownerType === \"system\") {\n economyAssert(\n wallet.ownerId === \"system\",\n \"INVALID_CONTRACT\",\n \"System wallets must be owned by the system\",\n );\n } else {\n assertEconomyIdentifier(wallet.ownerId, \"ownerId\");\n }\n if (wallet.householdId !== undefined) {\n assertEconomyIdentifier(wallet.householdId, \"householdId\");\n }\n if (wallet.ownerType === \"household\") {\n economyAssert(\n wallet.householdId === wallet.ownerId,\n \"INVALID_CONTRACT\",\n \"Household wallets must identify the same household owner\",\n );\n }\n if (wallet.kind === \"household-treasury\") {\n economyAssert(\n wallet.ownerType === \"household\" && wallet.householdId !== undefined,\n \"INVALID_CONTRACT\",\n \"Household treasuries must be owned by their household\",\n );\n }\n if (wallet.kind === \"personal\" || wallet.kind === \"gameplay-allocation\") {\n economyAssert(\n wallet.ownerType === \"account\",\n \"INVALID_CONTRACT\",\n \"Personal and gameplay-allocation wallets must be account-owned\",\n );\n }\n if (wallet.kind === \"gameplay-allocation\") {\n economyAssert(\n wallet.householdId !== undefined,\n \"INVALID_CONTRACT\",\n \"Gameplay-allocation wallets must retain household provenance\",\n );\n }\n if (\n wallet.kind === \"purchase-clearing\" ||\n wallet.kind === \"provider-clearing\" ||\n wallet.kind === \"system\"\n ) {\n economyAssert(\n wallet.ownerType === \"system\" && wallet.householdId === undefined,\n \"INVALID_CONTRACT\",\n \"Clearing and system wallets must be system-owned\",\n );\n }\n economyAssert(\n Number.isSafeInteger(wallet.version) && wallet.version >= 1,\n \"INVALID_CONTRACT\",\n \"Wallet version must be a positive safe integer\",\n );\n const createdAt = parseIsoTimestamp(wallet.createdAt);\n if (wallet.closedAt !== undefined) {\n economyAssert(\n parseIsoTimestamp(wallet.closedAt) >= createdAt &&\n wallet.status === \"closed\",\n \"INVALID_TIME_WINDOW\",\n \"Only closed wallets may have a valid closure time\",\n );\n } else {\n economyAssert(\n wallet.status !== \"closed\",\n \"INVALID_CONTRACT\",\n \"Closed wallets require a closure time\",\n );\n }\n}\n\n/** Validates non-negative server-computed wallet balance categories. */\nexport function assertWalletBalanceSummary(\n summary: WalletBalanceSummaryV1,\n): void {\n economyAssert(\n summary.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet summary contract version\",\n );\n assertEconomyIdentifier(summary.walletId, \"walletId\");\n for (const amount of [\n summary.available,\n summary.reserved,\n summary.held,\n summary.rewardProgress,\n ]) {\n economyAssert(\n parseTokenSubunits(amount) >= 0n,\n \"INVALID_AMOUNT\",\n \"Wallet summary categories cannot be negative\",\n );\n }\n economyAssert(\n Number.isSafeInteger(summary.version) && summary.version >= 1,\n \"INVALID_CONTRACT\",\n \"Wallet summary version must be a positive safe integer\",\n );\n parseIsoTimestamp(summary.asOf);\n}\n\n/** Validates non-negative lifetime aggregates exposed by the profile API. */\nexport function assertWalletLifetimeTotals(\n totals: WalletLifetimeTotalsV1,\n): void {\n economyAssert(\n totals.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet lifetime-total contract version\",\n );\n for (const amount of [\n totals.bought,\n totals.earned,\n totals.allocated,\n totals.reclaimed,\n totals.spent,\n totals.reversed,\n ]) {\n economyAssert(\n parseTokenSubunits(amount) >= 0n,\n \"INVALID_AMOUNT\",\n \"Wallet lifetime totals cannot be negative\",\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/amount.ts","../src/contracts.ts","../src/acquisition.ts","../src/allocations.ts","../src/early-backers.ts","../src/ledger.ts","../src/lots.ts","../src/operations.ts","../src/projection.ts","../src/recurrence.ts","../src/spend-requests.ts","../src/wallets.ts"],"sourcesContent":["export * from \"./acquisition.js\";\nexport * from \"./allocations.js\";\nexport * from \"./amount.js\";\nexport * from \"./contracts.js\";\nexport * from \"./early-backers.js\";\nexport * from \"./errors.js\";\nexport * from \"./ledger.js\";\nexport * from \"./lots.js\";\nexport * from \"./operations.js\";\nexport * from \"./ports/persistence.js\";\nexport * from \"./projection.js\";\nexport * from \"./recurrence.js\";\nexport * from \"./spend-requests.js\";\nexport * from \"./wallets.js\";\n","/** Stable machine-readable failures exposed by the economy domain. */\nexport type EconomyErrorCode =\n | \"INVALID_AMOUNT\"\n | \"AMOUNT_OUT_OF_RANGE\"\n | \"AMOUNT_NOT_WHOLE_TOKEN\"\n | \"INVALID_CONTRACT\"\n | \"UNBALANCED_TRANSACTION\"\n | \"DUPLICATE_IDENTIFIER\"\n | \"DUPLICATE_TRANSACTION\"\n | \"INSUFFICIENT_BALANCE\"\n | \"INSUFFICIENT_ELIGIBLE_LOTS\"\n | \"SOURCE_LOT_RESTRICTED\"\n | \"REVERSAL_ALREADY_EXISTS\"\n | \"NEGATIVE_PROJECTION\"\n | \"INVALID_TIME_WINDOW\";\n\nexport interface EconomyErrorEnvelopeV1 {\n readonly schemaVersion: \"1\";\n readonly error: {\n readonly code: EconomyErrorCode;\n readonly message: string;\n readonly requestId?: string;\n };\n}\n\n/**\n * Domain error with a stable code and deliberately non-sensitive message.\n * Provider evidence, identities, and payment details must not be included.\n */\nexport class EconomyError extends Error {\n readonly code: EconomyErrorCode;\n\n constructor(code: EconomyErrorCode, message: string) {\n super(message);\n this.name = \"EconomyError\";\n this.code = code;\n }\n}\n\n/** Throws a stable economy error when a domain assertion fails. */\nexport function economyAssert(\n condition: unknown,\n code: EconomyErrorCode,\n message: string,\n): asserts condition {\n if (!condition) {\n throw new EconomyError(code, message);\n }\n}\n\n/** Creates a bounded, non-sensitive error contract for an HTTP adapter. */\nexport function toEconomyErrorEnvelope(\n error: EconomyError,\n requestId?: string,\n): EconomyErrorEnvelopeV1 {\n return {\n schemaVersion: \"1\",\n error: {\n code: error.code,\n message: error.message.slice(0, 256),\n ...(requestId === undefined ? {} : { requestId }),\n },\n };\n}\n","import { EconomyError, economyAssert } from \"./errors.js\";\n\n/** Number of indivisible subunits in one public Token. */\nexport const TOKEN_SUBUNITS_PER_TOKEN = 1_000n;\n\n/** PostgreSQL-compatible signed bigint bounds. */\nexport const TOKEN_SUBUNITS_MIN = -(2n ** 63n);\nexport const TOKEN_SUBUNITS_MAX = 2n ** 63n - 1n;\n\ndeclare const tokenSubunitStringBrand: unique symbol;\n\n/** Canonical base-10 representation used at JSON and persistence boundaries. */\nexport type TokenSubunitString = string & {\n readonly [tokenSubunitStringBrand]: \"TokenSubunitString\";\n};\n\nconst CANONICAL_INTEGER = /^(?:0|-?[1-9][0-9]*)$/u;\n\nfunction assertInRange(amount: bigint): void {\n economyAssert(\n amount >= TOKEN_SUBUNITS_MIN && amount <= TOKEN_SUBUNITS_MAX,\n \"AMOUNT_OUT_OF_RANGE\",\n \"TokenSubunit amount is outside the signed 64-bit range\",\n );\n}\n\n/** Parses a canonical base-10 TokenSubunit string without floating point. */\nexport function parseTokenSubunits(value: string): bigint {\n economyAssert(\n typeof value === \"string\" && CANONICAL_INTEGER.test(value),\n \"INVALID_AMOUNT\",\n \"TokenSubunit amount must be a canonical base-10 integer string\",\n );\n\n try {\n const amount = BigInt(value);\n assertInRange(amount);\n return amount;\n } catch (error) {\n if (error instanceof EconomyError) {\n throw error;\n }\n throw new EconomyError(\"INVALID_AMOUNT\", \"TokenSubunit amount is invalid\");\n }\n}\n\n/** Serializes a signed 64-bit TokenSubunit amount to canonical base-10. */\nexport function serializeTokenSubunits(amount: bigint): TokenSubunitString {\n assertInRange(amount);\n return amount.toString(10) as TokenSubunitString;\n}\n\n/** Converts an exact whole-Token integer into TokenSubunits. */\nexport function wholeTokensToSubunits(tokens: bigint): bigint {\n const amount = tokens * TOKEN_SUBUNITS_PER_TOKEN;\n assertInRange(amount);\n return amount;\n}\n\n/** Returns true when a subunit amount represents an exact whole Token. */\nexport function isWholeTokenAmount(amount: bigint): boolean {\n return amount % TOKEN_SUBUNITS_PER_TOKEN === 0n;\n}\n\n/** Converts TokenSubunits to whole Tokens, rejecting fractional progress. */\nexport function subunitsToWholeTokens(amount: bigint): bigint {\n economyAssert(\n isWholeTokenAmount(amount),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Amount must contain whole Tokens\",\n );\n return amount / TOKEN_SUBUNITS_PER_TOKEN;\n}\n\n/** Sums amount strings with signed 64-bit overflow protection. */\nexport function sumTokenSubunits(values: readonly string[]): bigint {\n let total = 0n;\n for (const value of values) {\n total += parseTokenSubunits(value);\n assertInRange(total);\n }\n return total;\n}\n","import { economyAssert } from \"./errors.js\";\n\nexport const ECONOMY_CONTRACT_VERSION = \"1\" as const;\nexport type EconomyContractVersion = typeof ECONOMY_CONTRACT_VERSION;\n\nexport type AccountId = string;\nexport type AllocationId = string;\nexport type HouseholdId = string;\nexport type LotId = string;\nexport type PostingId = string;\nexport type ProviderEventId = string;\nexport type TransactionId = string;\nexport type WalletId = string;\nexport type IsoTimestamp = string;\n\nconst IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;\n\n/** Validates opaque pseudonymous domain identifiers. */\nexport function assertEconomyIdentifier(\n value: string,\n label = \"identifier\",\n): void {\n economyAssert(\n typeof value === \"string\" && IDENTIFIER.test(value),\n \"INVALID_CONTRACT\",\n `${label} must be a non-empty opaque identifier`,\n );\n}\n\n/** Parses a bounded ISO timestamp and returns milliseconds since epoch. */\nexport function parseIsoTimestamp(value: IsoTimestamp): number {\n economyAssert(\n typeof value === \"string\",\n \"INVALID_CONTRACT\",\n \"Timestamp must be an ISO-8601 UTC value\",\n );\n const match = /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(?:\\.(\\d{3}))?Z$/u.exec(\n value,\n );\n economyAssert(\n match !== null,\n \"INVALID_CONTRACT\",\n \"Timestamp must be an ISO-8601 UTC value\",\n );\n const milliseconds = Date.parse(value);\n const base = match[1];\n const fraction = match[2] ?? \"000\";\n economyAssert(\n Number.isFinite(milliseconds) &&\n base !== undefined &&\n new Date(milliseconds).toISOString() === `${base}.${fraction}Z`,\n \"INVALID_CONTRACT\",\n \"Timestamp must be valid\",\n );\n return milliseconds;\n}\n\n/** Returns a new record with keys sorted for canonical serialization. */\nexport function sortStringRecord(\n value: Readonly<Record<string, string>>,\n): Readonly<Record<string, string>> {\n return Object.fromEntries(\n Object.entries(value).sort(([left], [right]) => left.localeCompare(right)),\n );\n}\n","import {\n TOKEN_SUBUNITS_PER_TOKEN,\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type ProviderEventId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport type { ActivityStatus, ActivityType } from \"./ledger.js\";\n\nexport interface TokenPackV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly packId: string;\n readonly catalogVersion: string;\n readonly currency: \"GBP\";\n readonly priceMinorUnits: string;\n readonly grantAmount: TokenSubunitString;\n readonly active: boolean;\n}\n\n/** Product-copy reference only; it is not a redemption or exchange promise. */\nexport interface TokenReferenceRateV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly rateVersion: string;\n readonly currency: \"GBP\";\n readonly referenceMinorUnitsPerToken: string;\n readonly tokenSubunitsPerToken: string;\n readonly cashRedemptionAllowed: false;\n}\n\nexport const BASELINE_GBP_REFERENCE_RATE: TokenReferenceRateV1 = Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n rateVersion: \"gbp-reference-v1\",\n currency: \"GBP\",\n referenceMinorUnitsPerToken: \"10\",\n tokenSubunitsPerToken: TOKEN_SUBUNITS_PER_TOKEN.toString(10),\n cashRedemptionAllowed: false,\n});\n\nexport const BASELINE_GBP_CATALOG_VERSION = \"gbp-v1\" as const;\n\n/** Initial flat-price public catalog. Changes require a new catalog version. */\nexport const BASELINE_GBP_TOKEN_PACKS: readonly TokenPackV1[] = Object.freeze([\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_5_50_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"500\",\n grantAmount: serializeTokenSubunits(50_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_10_100_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"1000\",\n grantAmount: serializeTokenSubunits(100_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_25_250_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"2500\",\n grantAmount: serializeTokenSubunits(250_000n),\n active: true,\n }),\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n packId: \"gbp_50_500_v1\",\n catalogVersion: BASELINE_GBP_CATALOG_VERSION,\n currency: \"GBP\",\n priceMinorUnits: \"5000\",\n grantAmount: serializeTokenSubunits(500_000n),\n active: true,\n }),\n]);\n\nexport interface PurchaseLimitPolicyV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly maxOrderPriceMinorUnits: string;\n readonly rollingPayerPriceMinorUnits: string;\n readonly rollingHouseholdPriceMinorUnits: string;\n readonly rollingDays: number;\n}\n\n/** Default server limits; household controls may only lower these values. */\nexport const BASELINE_PURCHASE_LIMIT_POLICY: PurchaseLimitPolicyV1 =\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n maxOrderPriceMinorUnits: \"5000\",\n rollingPayerPriceMinorUnits: \"10000\",\n rollingHouseholdPriceMinorUnits: \"10000\",\n rollingDays: 30,\n });\n\nexport type PurchaseIntentStatus =\n | \"created\"\n | \"checkout-created\"\n | \"paid-unreconciled\"\n | \"credited\"\n | \"expired\"\n | \"cancelled\"\n | \"disputed\";\n\n/** Short-lived server authority binding checkout facts to a payer/household. */\nexport interface PurchaseIntentV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly intentId: string;\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly receivingWalletId: WalletId;\n readonly packId: string;\n readonly catalogVersion: string;\n readonly expectedCurrency: \"GBP\";\n readonly expectedPriceMinorUnits: string;\n readonly grantAmount: TokenSubunitString;\n readonly status: PurchaseIntentStatus;\n readonly createdAt: IsoTimestamp;\n readonly expiresAt: IsoTimestamp;\n readonly providerCheckoutReferenceHash?: string;\n}\n\nexport interface RewardRateV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly rateVersion: string;\n readonly provider: \"ayet\" | \"bitlabs\";\n /** TokenSubunits granted per denominator of authoritative GBP minor units. */\n readonly tokenSubunitsNumerator: string;\n readonly gbpMinorUnitsDenominator: string;\n readonly effectiveFrom: IsoTimestamp;\n readonly effectiveUntil?: IsoTimestamp;\n}\n\nexport interface FxSnapshotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly snapshotId: string;\n readonly sourceCurrency: string;\n readonly quoteCurrency: \"GBP\";\n /** Exact rational conversion to GBP minor units. */\n readonly gbpMinorUnitsNumerator: string;\n readonly sourceMinorUnitsDenominator: string;\n readonly capturedAt: IsoTimestamp;\n}\n\nexport type RewardConversionStatus =\n | \"pending\"\n | \"completed\"\n | \"reconciled\";\n\nexport type BitLabsConversionState =\n | \"PENDING\"\n | \"COMPLETED\"\n | \"RECONCILED\";\n\nexport interface RewardActivityTransitionV1 {\n readonly conversionStatus: RewardConversionStatus;\n readonly activityType: ActivityType;\n readonly activityStatus: ActivityStatus;\n}\n\nexport interface RewardConversionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly provider: \"ayet\" | \"bitlabs\";\n readonly providerEventId: ProviderEventId;\n readonly beneficiaryAccountId: AccountId;\n readonly walletId: WalletId;\n readonly status: RewardConversionStatus;\n readonly providerPayoutMinorUnits: string;\n readonly providerCurrency: string;\n readonly gbpMinorUnits: string;\n readonly tokenSubunits: TokenSubunitString;\n readonly rateVersion: string;\n readonly fxSnapshotId: string;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Validates a minimized, signed-provider conversion record before journaling. */\nexport function assertRewardConversion(\n conversion: RewardConversionV1,\n): void {\n economyAssert(\n conversion.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion contract version\",\n );\n economyAssert(\n conversion.provider === \"ayet\" || conversion.provider === \"bitlabs\",\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion provider\",\n );\n assertEconomyIdentifier(conversion.providerEventId, \"providerEventId\");\n assertEconomyIdentifier(\n conversion.beneficiaryAccountId,\n \"beneficiaryAccountId\",\n );\n assertEconomyIdentifier(conversion.walletId, \"walletId\");\n economyAssert(\n [\"pending\", \"completed\", \"reconciled\"].includes(conversion.status),\n \"INVALID_CONTRACT\",\n \"Unsupported reward-conversion status\",\n );\n economyAssert(\n /^[A-Z]{3}$/u.test(conversion.providerCurrency),\n \"INVALID_CONTRACT\",\n \"Reward payout currency must use an uppercase ISO code\",\n );\n economyAssert(\n parseNonNegativeInteger(\n conversion.providerPayoutMinorUnits,\n \"Provider payout\",\n ) > 0n &&\n parseNonNegativeInteger(conversion.gbpMinorUnits, \"GBP payout\") >= 0n &&\n parseTokenSubunits(conversion.tokenSubunits) > 0n,\n \"INVALID_AMOUNT\",\n \"Reward conversion must carry positive payout and Token values\",\n );\n assertEconomyIdentifier(conversion.rateVersion, \"rateVersion\");\n assertEconomyIdentifier(conversion.fxSnapshotId, \"fxSnapshotId\");\n parseIsoTimestamp(conversion.occurredAt);\n}\n\nfunction parseNonNegativeInteger(value: string, label: string): bigint {\n economyAssert(\n /^(?:0|[1-9][0-9]*)$/u.test(value),\n \"INVALID_AMOUNT\",\n `${label} must be a non-negative integer string`,\n );\n return BigInt(value);\n}\n\n/** Validates a paid pack; pack grants are whole Tokens in the baseline. */\nexport function assertTokenPack(pack: TokenPackV1): void {\n economyAssert(\n pack.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported Token pack contract version\",\n );\n assertEconomyIdentifier(pack.packId, \"packId\");\n assertEconomyIdentifier(pack.catalogVersion, \"catalogVersion\");\n economyAssert(\n pack.currency === \"GBP\" && typeof pack.active === \"boolean\",\n \"INVALID_CONTRACT\",\n \"Token packs must use GBP and declare whether they are active\",\n );\n economyAssert(\n parseNonNegativeInteger(pack.priceMinorUnits, \"Pack price\") > 0n,\n \"INVALID_AMOUNT\",\n \"Pack price must be positive\",\n );\n const grant = parseTokenSubunits(pack.grantAmount);\n economyAssert(\n grant > 0n && isWholeTokenAmount(grant),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Paid pack grants must contain whole Tokens\",\n );\n}\n\n/** Validates nominal reference metadata without creating redemption rights. */\nexport function assertTokenReferenceRate(\n rate: TokenReferenceRateV1,\n): void {\n economyAssert(\n rate.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported Token reference-rate contract version\",\n );\n assertEconomyIdentifier(rate.rateVersion, \"rateVersion\");\n const referenceMinorUnits = parseNonNegativeInteger(\n rate.referenceMinorUnitsPerToken,\n \"Reference minor units per Token\",\n );\n const subunitsPerToken = parseNonNegativeInteger(\n rate.tokenSubunitsPerToken,\n \"TokenSubunits per Token\",\n );\n economyAssert(\n rate.currency === \"GBP\" &&\n referenceMinorUnits > 0n &&\n subunitsPerToken === TOKEN_SUBUNITS_PER_TOKEN &&\n rate.cashRedemptionAllowed === false,\n \"INVALID_CONTRACT\",\n \"Token reference rate must preserve the GBP nominal, subunit, and no-redemption boundary\",\n );\n}\n\n/** Proves that every pack in one catalog uses the same flat nominal ratio. */\nexport function assertFlatTokenCatalog(\n packs: readonly TokenPackV1[],\n referenceRate: TokenReferenceRateV1,\n): void {\n assertTokenReferenceRate(referenceRate);\n economyAssert(\n packs.length > 0,\n \"INVALID_CONTRACT\",\n \"Token catalog must contain at least one pack\",\n );\n const packIds = new Set<string>();\n const catalogVersion = packs[0]?.catalogVersion;\n const referenceMinorUnits = BigInt(\n referenceRate.referenceMinorUnitsPerToken,\n );\n const subunitsPerToken = BigInt(referenceRate.tokenSubunitsPerToken);\n for (const pack of packs) {\n assertTokenPack(pack);\n economyAssert(\n !packIds.has(pack.packId),\n \"DUPLICATE_IDENTIFIER\",\n \"Token catalog pack IDs must be unique\",\n );\n economyAssert(\n pack.catalogVersion === catalogVersion,\n \"INVALID_CONTRACT\",\n \"Token catalog packs must share one catalog version\",\n );\n packIds.add(pack.packId);\n const scaledReference =\n parseTokenSubunits(pack.grantAmount) * referenceMinorUnits;\n economyAssert(\n scaledReference % subunitsPerToken === 0n &&\n scaledReference / subunitsPerToken === BigInt(pack.priceMinorUnits),\n \"INVALID_CONTRACT\",\n \"Token catalog must use the declared flat nominal reference ratio\",\n );\n }\n}\n\n/** Validates server-side order and rolling acquisition ceilings. */\nexport function assertPurchaseLimitPolicy(\n policy: PurchaseLimitPolicyV1,\n): void {\n economyAssert(\n policy.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported purchase-limit contract version\",\n );\n const maxOrder = parseNonNegativeInteger(\n policy.maxOrderPriceMinorUnits,\n \"Maximum order\",\n );\n const payer = parseNonNegativeInteger(\n policy.rollingPayerPriceMinorUnits,\n \"Rolling payer limit\",\n );\n const household = parseNonNegativeInteger(\n policy.rollingHouseholdPriceMinorUnits,\n \"Rolling household limit\",\n );\n economyAssert(\n maxOrder > 0n && payer >= maxOrder && household >= maxOrder,\n \"INVALID_AMOUNT\",\n \"Rolling purchase limits must cover at least one maximum order\",\n );\n economyAssert(\n Number.isSafeInteger(policy.rollingDays) &&\n policy.rollingDays >= 1 &&\n policy.rollingDays <= 365,\n \"INVALID_CONTRACT\",\n \"Purchase-limit rolling window must be a bounded whole-day count\",\n );\n}\n\n/** Validates the immutable server-side facts bound into a purchase intent. */\nexport function assertPurchaseIntentBinding(\n intent: PurchaseIntentV1,\n pack: TokenPackV1,\n): void {\n assertTokenPack(pack);\n economyAssert(\n intent.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported purchase-intent contract version\",\n );\n assertEconomyIdentifier(intent.intentId, \"intentId\");\n assertEconomyIdentifier(intent.payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(intent.receivingHouseholdId, \"receivingHouseholdId\");\n assertEconomyIdentifier(intent.receivingWalletId, \"receivingWalletId\");\n assertEconomyIdentifier(intent.packId, \"packId\");\n assertEconomyIdentifier(intent.catalogVersion, \"catalogVersion\");\n\n const createdAt = parseIsoTimestamp(intent.createdAt);\n const expiresAt = parseIsoTimestamp(intent.expiresAt);\n economyAssert(\n expiresAt > createdAt,\n \"INVALID_TIME_WINDOW\",\n \"Purchase intent expiry must follow its creation time\",\n );\n economyAssert(\n intent.expectedCurrency === \"GBP\" &&\n intent.packId === pack.packId &&\n intent.catalogVersion === pack.catalogVersion &&\n intent.expectedCurrency === pack.currency &&\n intent.expectedPriceMinorUnits === pack.priceMinorUnits &&\n intent.grantAmount === pack.grantAmount,\n \"INVALID_CONTRACT\",\n \"Purchase intent does not match its authoritative catalog pack\",\n );\n parseNonNegativeInteger(intent.expectedPriceMinorUnits, \"Expected price\");\n parseTokenSubunits(intent.grantAmount);\n economyAssert(\n [\n \"created\",\n \"checkout-created\",\n \"paid-unreconciled\",\n \"credited\",\n \"expired\",\n \"cancelled\",\n \"disputed\",\n ].includes(intent.status),\n \"INVALID_CONTRACT\",\n \"Purchase intent has an unsupported status\",\n );\n if (intent.providerCheckoutReferenceHash !== undefined) {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(intent.providerCheckoutReferenceHash),\n \"INVALID_CONTRACT\",\n \"Checkout references must be stored as sanitized SHA-256 hashes\",\n );\n }\n}\n\n/** Rejects stale, inactive, or already-consumed intents before checkout creation. */\nexport function assertOpenPurchaseIntent(\n intent: PurchaseIntentV1,\n pack: TokenPackV1,\n checkedAt: IsoTimestamp,\n): void {\n assertPurchaseIntentBinding(intent, pack);\n const checkedAtValue = parseIsoTimestamp(checkedAt);\n economyAssert(\n pack.active &&\n (intent.status === \"created\" || intent.status === \"checkout-created\") &&\n checkedAtValue >= parseIsoTimestamp(intent.createdAt) &&\n checkedAtValue < parseIsoTimestamp(intent.expiresAt),\n \"INVALID_TIME_WINDOW\",\n \"Purchase intent is inactive, expired, or not open for checkout\",\n );\n}\n\nexport function assertRewardRate(rate: RewardRateV1): void {\n economyAssert(\n rate.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported reward-rate contract version\",\n );\n assertEconomyIdentifier(rate.rateVersion, \"rateVersion\");\n economyAssert(\n rate.provider === \"ayet\" || rate.provider === \"bitlabs\",\n \"INVALID_CONTRACT\",\n \"Unsupported reward provider\",\n );\n const effectiveFrom = parseIsoTimestamp(rate.effectiveFrom);\n if (rate.effectiveUntil !== undefined) {\n economyAssert(\n parseIsoTimestamp(rate.effectiveUntil) > effectiveFrom,\n \"INVALID_TIME_WINDOW\",\n \"Reward-rate expiry must follow its effective time\",\n );\n }\n}\n\nexport function assertFxSnapshot(fx: FxSnapshotV1): void {\n economyAssert(\n fx.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported FX snapshot contract version\",\n );\n assertEconomyIdentifier(fx.snapshotId, \"snapshotId\");\n economyAssert(\n /^[A-Z]{3}$/u.test(fx.sourceCurrency) && fx.quoteCurrency === \"GBP\",\n \"INVALID_CONTRACT\",\n \"FX snapshots must convert an ISO currency into GBP\",\n );\n parseIsoTimestamp(fx.capturedAt);\n}\n\n/** Converts provider payout using exact rational FX and rate snapshots. */\nexport function convertRewardPayout(\n providerPayoutMinorUnits: string,\n rate: RewardRateV1,\n fx: FxSnapshotV1,\n): { readonly gbpMinorUnits: string; readonly tokenSubunits: TokenSubunitString } {\n assertRewardRate(rate);\n assertFxSnapshot(fx);\n const payout = parseNonNegativeInteger(\n providerPayoutMinorUnits,\n \"Provider payout\",\n );\n const fxNumerator = parseNonNegativeInteger(\n fx.gbpMinorUnitsNumerator,\n \"FX numerator\",\n );\n const fxDenominator = parseNonNegativeInteger(\n fx.sourceMinorUnitsDenominator,\n \"FX denominator\",\n );\n const tokenNumerator = parseNonNegativeInteger(\n rate.tokenSubunitsNumerator,\n \"Rate numerator\",\n );\n const tokenDenominator = parseNonNegativeInteger(\n rate.gbpMinorUnitsDenominator,\n \"Rate denominator\",\n );\n economyAssert(\n fxDenominator > 0n && tokenDenominator > 0n,\n \"INVALID_AMOUNT\",\n \"FX and reward-rate denominators must be positive\",\n );\n economyAssert(\n fxNumerator > 0n && tokenNumerator > 0n,\n \"INVALID_AMOUNT\",\n \"FX and reward-rate numerators must be positive\",\n );\n\n const gbpMinorUnits = (payout * fxNumerator) / fxDenominator;\n const tokenSubunits = (gbpMinorUnits * tokenNumerator) / tokenDenominator;\n return {\n gbpMinorUnits: gbpMinorUnits.toString(10),\n tokenSubunits: serializeTokenSubunits(tokenSubunits),\n };\n}\n\n/** Maps BitLabs' signed callback state into an immutable journal transition. */\nexport function mapBitLabsConversionState(\n state: string,\n): RewardActivityTransitionV1 {\n const transitions: Readonly<\n Record<BitLabsConversionState, RewardActivityTransitionV1>\n > = {\n PENDING: {\n conversionStatus: \"pending\",\n activityType: \"hold\",\n activityStatus: \"held\",\n },\n COMPLETED: {\n conversionStatus: \"completed\",\n activityType: \"offerwall\",\n activityStatus: \"settled\",\n },\n RECONCILED: {\n conversionStatus: \"reconciled\",\n activityType: \"reversal\",\n activityStatus: \"reversed\",\n },\n };\n const transition = transitions[state as BitLabsConversionState];\n economyAssert(\n transition !== undefined,\n \"INVALID_CONTRACT\",\n \"Unsupported BitLabs conversion state\",\n );\n return transition;\n}\n","import {\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n sumTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type AllocationId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport type { SourceLotSliceV1 } from \"./lots.js\";\n\nexport type AllocationStatus = \"active\" | \"closed\";\nexport type PeriodicLimitWindow = \"daily\" | \"weekly\" | \"monthly\";\n\nexport interface GameplayLimitsV1 {\n readonly perTransaction: TokenSubunitString;\n readonly periodic: TokenSubunitString;\n readonly periodicWindow: PeriodicLimitWindow;\n}\n\n/** Guardian-funded, child-visible reservation. This is not a gameplay ledger. */\nexport interface GameplayAllocationV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly allocationId: AllocationId;\n readonly householdId: HouseholdId;\n readonly hostWalletId: WalletId;\n readonly childWalletId: WalletId;\n readonly childAccountId: AccountId;\n readonly status: AllocationStatus;\n readonly reservedAmount: TokenSubunitString;\n readonly remainingAmount: TokenSubunitString;\n readonly reclaimedAmount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly reclaimedSlices: readonly SourceLotSliceV1[];\n readonly limits: GameplayLimitsV1;\n readonly version: number;\n readonly createdAt: IsoTimestamp;\n readonly updatedAt: IsoTimestamp;\n}\n\nfunction assertWholePositive(amount: TokenSubunitString, label: string): bigint {\n const parsed = parseTokenSubunits(amount);\n economyAssert(parsed > 0n, \"INVALID_AMOUNT\", `${label} must be positive`);\n economyAssert(\n isWholeTokenAmount(parsed),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n `${label} must contain whole Tokens`,\n );\n return parsed;\n}\n\nfunction assertSlices(\n slices: readonly SourceLotSliceV1[],\n expectedAmount: bigint,\n label: string,\n): void {\n economyAssert(slices.length > 0, \"INVALID_CONTRACT\", `${label} are required`);\n const lotIds = new Set<string>();\n for (const slice of slices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n economyAssert(\n !lotIds.has(slice.lotId),\n \"DUPLICATE_IDENTIFIER\",\n `${label} must not repeat a lot`,\n );\n lotIds.add(slice.lotId);\n economyAssert(\n parseTokenSubunits(slice.amount) > 0n,\n \"INVALID_AMOUNT\",\n `${label} amounts must be positive`,\n );\n }\n economyAssert(\n sumTokenSubunits(slices.map((slice) => slice.amount)) === expectedAmount,\n \"INVALID_CONTRACT\",\n `${label} must sum to the command amount`,\n );\n}\n\n/** Validates allocation arithmetic and whole-Token reservation policy. */\nexport function assertGameplayAllocation(\n allocation: GameplayAllocationV1,\n): void {\n economyAssert(\n allocation.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported allocation contract version\",\n );\n assertEconomyIdentifier(allocation.allocationId, \"allocationId\");\n assertEconomyIdentifier(allocation.householdId, \"householdId\");\n assertEconomyIdentifier(allocation.hostWalletId, \"hostWalletId\");\n assertEconomyIdentifier(allocation.childWalletId, \"childWalletId\");\n assertEconomyIdentifier(allocation.childAccountId, \"childAccountId\");\n const createdAt = parseIsoTimestamp(allocation.createdAt);\n const updatedAt = parseIsoTimestamp(allocation.updatedAt);\n economyAssert(\n updatedAt >= createdAt,\n \"INVALID_TIME_WINDOW\",\n \"Allocation update time cannot precede its creation time\",\n );\n economyAssert(\n allocation.status === \"active\" || allocation.status === \"closed\",\n \"INVALID_CONTRACT\",\n \"Allocation has an unsupported status\",\n );\n\n const reserved = parseTokenSubunits(allocation.reservedAmount);\n const remaining = parseTokenSubunits(allocation.remainingAmount);\n const reclaimed = parseTokenSubunits(allocation.reclaimedAmount);\n economyAssert(\n reserved > 0n &&\n remaining >= 0n &&\n reclaimed >= 0n &&\n isWholeTokenAmount(reserved) &&\n isWholeTokenAmount(remaining) &&\n isWholeTokenAmount(reclaimed),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Allocation reservations and reclaims must contain whole Tokens\",\n );\n economyAssert(\n remaining + reclaimed <= reserved,\n \"INVALID_CONTRACT\",\n \"Allocation remaining and reclaimed amounts exceed its reservation\",\n );\n\n const fundingByLot = new Map<string, bigint>();\n let funded = 0n;\n for (const slice of allocation.fundingSlices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n const amount = parseTokenSubunits(slice.amount);\n economyAssert(\n amount > 0n,\n \"INVALID_AMOUNT\",\n \"Allocation funding slices must be positive\",\n );\n funded += amount;\n fundingByLot.set(\n slice.lotId,\n (fundingByLot.get(slice.lotId) ?? 0n) + amount,\n );\n }\n economyAssert(\n funded === reserved,\n \"INVALID_CONTRACT\",\n \"Allocation funding provenance must equal its total reservation\",\n );\n\n const reclaimedByLot = new Map<string, bigint>();\n let reclaimedFromSlices = 0n;\n for (const slice of allocation.reclaimedSlices) {\n assertEconomyIdentifier(slice.lotId, \"lotId\");\n const amount = parseTokenSubunits(slice.amount);\n economyAssert(\n amount > 0n,\n \"INVALID_AMOUNT\",\n \"Allocation reclaim slices must be positive\",\n );\n reclaimedFromSlices += amount;\n reclaimedByLot.set(\n slice.lotId,\n (reclaimedByLot.get(slice.lotId) ?? 0n) + amount,\n );\n }\n economyAssert(\n reclaimedFromSlices === reclaimed,\n \"INVALID_CONTRACT\",\n \"Allocation reclaim provenance must equal its reclaimed amount\",\n );\n for (const [lotId, amount] of reclaimedByLot) {\n economyAssert(\n amount <= (fundingByLot.get(lotId) ?? 0n),\n \"SOURCE_LOT_RESTRICTED\",\n \"Reclaimed provenance cannot exceed allocation funding\",\n );\n }\n economyAssert(\n allocation.version >= 1 && Number.isSafeInteger(allocation.version),\n \"INVALID_CONTRACT\",\n \"Allocation version must be a positive safe integer\",\n );\n\n const perTransaction = parseTokenSubunits(allocation.limits.perTransaction);\n const periodic = parseTokenSubunits(allocation.limits.periodic);\n economyAssert(\n [\"daily\", \"weekly\", \"monthly\"].includes(allocation.limits.periodicWindow),\n \"INVALID_CONTRACT\",\n \"Gameplay limit has an unsupported period\",\n );\n economyAssert(\n perTransaction >= 0n &&\n periodic >= 0n &&\n isWholeTokenAmount(perTransaction) &&\n isWholeTokenAmount(periodic),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Gameplay limits must contain whole Tokens\",\n );\n economyAssert(\n perTransaction <= periodic || periodic === 0n,\n \"INVALID_CONTRACT\",\n \"Per-transaction limit cannot exceed an enabled periodic limit\",\n );\n}\n\nexport interface CreateGameplayAllocationInputV1 {\n readonly allocationId: AllocationId;\n readonly householdId: HouseholdId;\n readonly hostWalletId: WalletId;\n readonly childWalletId: WalletId;\n readonly childAccountId: AccountId;\n readonly amount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly limits: GameplayLimitsV1;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Creates a new whole-Token reservation from already-selected source lots. */\nexport function createGameplayAllocation(\n input: CreateGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n const amount = assertWholePositive(input.amount, \"Allocation amount\");\n assertSlices(input.fundingSlices, amount, \"Allocation funding slices\");\n const allocation: GameplayAllocationV1 = {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n allocationId: input.allocationId,\n householdId: input.householdId,\n hostWalletId: input.hostWalletId,\n childWalletId: input.childWalletId,\n childAccountId: input.childAccountId,\n status: \"active\",\n reservedAmount: input.amount,\n remainingAmount: input.amount,\n reclaimedAmount: serializeTokenSubunits(0n),\n fundingSlices: input.fundingSlices,\n reclaimedSlices: [],\n limits: input.limits,\n version: 1,\n createdAt: input.occurredAt,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(allocation);\n return allocation;\n}\n\nexport interface BoostGameplayAllocationInputV1 {\n readonly amount: TokenSubunitString;\n readonly fundingSlices: readonly SourceLotSliceV1[];\n readonly expectedVersion: number;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Returns the next immutable allocation state after a whole-Token boost. */\nexport function boostGameplayAllocation(\n allocation: GameplayAllocationV1,\n input: BoostGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n assertGameplayAllocation(allocation);\n economyAssert(\n allocation.status === \"active\" && allocation.version === input.expectedVersion,\n \"INVALID_CONTRACT\",\n \"Allocation is closed or its optimistic version is stale\",\n );\n const amount = assertWholePositive(input.amount, \"Boost amount\");\n assertSlices(input.fundingSlices, amount, \"Boost funding slices\");\n\n const next: GameplayAllocationV1 = {\n ...allocation,\n reservedAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.reservedAmount) + amount,\n ),\n remainingAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.remainingAmount) + amount,\n ),\n fundingSlices: [...allocation.fundingSlices, ...input.fundingSlices],\n version: allocation.version + 1,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(next);\n return next;\n}\n\nexport interface ReclaimGameplayAllocationInputV1 {\n readonly amount: TokenSubunitString;\n readonly sourceSlices: readonly SourceLotSliceV1[];\n readonly expectedVersion: number;\n readonly occurredAt: IsoTimestamp;\n}\n\n/** Reclaims unused whole Tokens without changing spent history. */\nexport function reclaimGameplayAllocation(\n allocation: GameplayAllocationV1,\n input: ReclaimGameplayAllocationInputV1,\n): GameplayAllocationV1 {\n assertGameplayAllocation(allocation);\n economyAssert(\n allocation.status === \"active\" && allocation.version === input.expectedVersion,\n \"INVALID_CONTRACT\",\n \"Allocation is closed or its optimistic version is stale\",\n );\n const amount = assertWholePositive(input.amount, \"Reclaim amount\");\n economyAssert(\n amount <= parseTokenSubunits(allocation.remainingAmount),\n \"INSUFFICIENT_BALANCE\",\n \"Cannot reclaim more than the unused allocation\",\n );\n assertSlices(input.sourceSlices, amount, \"Reclaim source slices\");\n const fundedLotIds = new Set(\n allocation.fundingSlices.map((slice) => slice.lotId),\n );\n economyAssert(\n input.sourceSlices.every((slice) => fundedLotIds.has(slice.lotId)),\n \"SOURCE_LOT_RESTRICTED\",\n \"Reclaim slices must originate from the allocation\",\n );\n\n const remaining = parseTokenSubunits(allocation.remainingAmount) - amount;\n const next: GameplayAllocationV1 = {\n ...allocation,\n remainingAmount: serializeTokenSubunits(remaining),\n reclaimedAmount: serializeTokenSubunits(\n parseTokenSubunits(allocation.reclaimedAmount) + amount,\n ),\n reclaimedSlices: [...allocation.reclaimedSlices, ...input.sourceSlices],\n status: remaining === 0n ? \"closed\" : allocation.status,\n version: allocation.version + 1,\n updatedAt: input.occurredAt,\n };\n assertGameplayAllocation(next);\n return next;\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type LotId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport const PRE_UTILITY_BACKER_COHORT = \"pre_utility_backer_v1\" as const;\n\nexport interface EarlyBackerWindowV1 {\n readonly publicTokensLaunchAt: IsoTimestamp;\n readonly firstPublicSpendLiveAt?: IsoTimestamp;\n}\n\n/** Paid-lot facts required to recalculate retained early-backer basis. */\nexport interface PaidLotRetentionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly lotId: LotId;\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly purchaseId: string;\n readonly catalogVersion: string;\n readonly purchasedAt: IsoTimestamp;\n readonly settledAt: IsoTimestamp;\n readonly creditedAt: IsoTimestamp;\n readonly retainedAmount: TokenSubunitString;\n}\n\nexport interface EarlyBackerEvaluationV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly cohortKey: typeof PRE_UTILITY_BACKER_COHORT;\n readonly status: \"not-qualified\" | \"provisional\";\n readonly payerAccountId: AccountId;\n readonly receivingHouseholdId: HouseholdId;\n readonly netRetainedAmount: TokenSubunitString;\n readonly contributingLotIds: readonly LotId[];\n readonly evaluatedAt: IsoTimestamp;\n}\n\nfunction isWithinWindow(\n timestamp: IsoTimestamp,\n launch: number,\n cutoff: number | undefined,\n): boolean {\n const value = parseIsoTimestamp(timestamp);\n return value >= launch && (cutoff === undefined || value < cutoff);\n}\n\n/**\n * Recalculates provisional cohort basis from retained paid lots. It promises no\n * future reward and deliberately has no permanent entitled state.\n */\nexport function evaluateEarlyBacker(\n payerAccountId: AccountId,\n receivingHouseholdId: HouseholdId,\n paidLots: readonly PaidLotRetentionV1[],\n window: EarlyBackerWindowV1,\n evaluatedAt: IsoTimestamp,\n): EarlyBackerEvaluationV1 {\n assertEconomyIdentifier(payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(receivingHouseholdId, \"receivingHouseholdId\");\n const launch = parseIsoTimestamp(window.publicTokensLaunchAt);\n const cutoff =\n window.firstPublicSpendLiveAt === undefined\n ? undefined\n : parseIsoTimestamp(window.firstPublicSpendLiveAt);\n economyAssert(\n cutoff === undefined || cutoff > launch,\n \"INVALID_TIME_WINDOW\",\n \"First public spend must occur after public Token launch\",\n );\n parseIsoTimestamp(evaluatedAt);\n\n let retained = 0n;\n const contributingLotIds: LotId[] = [];\n const seenLotIds = new Set<string>();\n for (const lot of paidLots) {\n economyAssert(\n lot.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported paid-lot retention contract version\",\n );\n assertEconomyIdentifier(lot.lotId, \"lotId\");\n economyAssert(\n !seenLotIds.has(lot.lotId),\n \"DUPLICATE_IDENTIFIER\",\n \"Paid-lot retention input must not repeat a source lot\",\n );\n seenLotIds.add(lot.lotId);\n assertEconomyIdentifier(lot.payerAccountId, \"payerAccountId\");\n assertEconomyIdentifier(lot.receivingHouseholdId, \"receivingHouseholdId\");\n assertEconomyIdentifier(lot.purchaseId, \"purchaseId\");\n assertEconomyIdentifier(lot.catalogVersion, \"catalogVersion\");\n const purchasedAt = parseIsoTimestamp(lot.purchasedAt);\n const settledAt = parseIsoTimestamp(lot.settledAt);\n const creditedAt = parseIsoTimestamp(lot.creditedAt);\n economyAssert(\n purchasedAt <= settledAt && settledAt <= creditedAt,\n \"INVALID_TIME_WINDOW\",\n \"Paid-lot timestamps must follow purchase, settlement, then credit order\",\n );\n if (\n lot.payerAccountId !== payerAccountId ||\n lot.receivingHouseholdId !== receivingHouseholdId\n ) {\n continue;\n }\n const inWindow =\n isWithinWindow(lot.purchasedAt, launch, cutoff) &&\n isWithinWindow(lot.settledAt, launch, cutoff) &&\n isWithinWindow(lot.creditedAt, launch, cutoff);\n const amount = parseTokenSubunits(lot.retainedAmount);\n economyAssert(\n amount >= 0n,\n \"INVALID_AMOUNT\",\n \"Retained paid-lot basis cannot be negative\",\n );\n if (inWindow && amount > 0n) {\n retained += amount;\n contributingLotIds.push(lot.lotId);\n }\n }\n\n return {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n cohortKey: PRE_UTILITY_BACKER_COHORT,\n status: retained > 0n ? \"provisional\" : \"not-qualified\",\n payerAccountId,\n receivingHouseholdId,\n netRetainedAmount: serializeTokenSubunits(retained),\n contributingLotIds: contributingLotIds.sort((left, right) =>\n left.localeCompare(right),\n ),\n evaluatedAt,\n };\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n sumTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n sortStringRecord,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type LotId,\n type PostingId,\n type ProviderEventId,\n type TransactionId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport type { TokenSource } from \"./lots.js\";\n\nexport type ActivityType =\n | \"purchase\"\n | \"subscription\"\n | \"rewarded-ad\"\n | \"offerwall\"\n | \"allocation\"\n | \"boost\"\n | \"reclaim\"\n | \"spend\"\n | \"hold\"\n | \"refund\"\n | \"chargeback\"\n | \"adjustment\"\n | \"reversal\"\n | \"event\"\n | \"competition\";\n\nexport type ActivityStatus =\n | \"pending\"\n | \"held\"\n | \"settled\"\n | \"reversed\"\n | \"failed\";\n\nconst ACTIVITY_TYPES = new Set<ActivityType>([\n \"purchase\",\n \"subscription\",\n \"rewarded-ad\",\n \"offerwall\",\n \"allocation\",\n \"boost\",\n \"reclaim\",\n \"spend\",\n \"hold\",\n \"refund\",\n \"chargeback\",\n \"adjustment\",\n \"reversal\",\n \"event\",\n \"competition\",\n]);\n\nconst ACTIVITY_STATUSES = new Set<ActivityStatus>([\n \"pending\",\n \"held\",\n \"settled\",\n \"reversed\",\n \"failed\",\n]);\n\nconst ACTIVITY_SOURCES = new Set<TokenSource>([\n \"shopify\",\n \"ayet\",\n \"bitlabs\",\n \"subscription\",\n \"event\",\n \"competition\",\n \"adjustment\",\n]);\n\nfunction assertCanonicalHash(value: string, label: string): void {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(value),\n \"INVALID_CONTRACT\",\n `${label} must be a canonical SHA-256 reference`,\n );\n}\n\nfunction hasControlCharacters(value: string): boolean {\n return [...value].some((character) => {\n const code = character.charCodeAt(0);\n return code <= 31 || code === 127;\n });\n}\n\n/** One signed side of an immutable double-entry transaction. */\nexport interface LedgerPostingV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly postingId: PostingId;\n readonly transactionId: TransactionId;\n readonly accountId: AccountId;\n readonly walletId?: WalletId;\n readonly lotId?: LotId;\n readonly amount: TokenSubunitString;\n}\n\n/** Immutable transaction envelope. Posting amounts must sum to exactly zero. */\nexport interface LedgerTransactionV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly transactionId: TransactionId;\n readonly activityType: ActivityType;\n readonly status: ActivityStatus;\n readonly idempotencyKey: string;\n readonly providerEventId?: ProviderEventId;\n readonly reversesTransactionId?: TransactionId;\n readonly effectiveAt: IsoTimestamp;\n readonly recordedAt: IsoTimestamp;\n readonly previousCanonicalHash?: string;\n readonly canonicalHash?: string;\n readonly metadata: Readonly<Record<string, string>>;\n readonly postings: readonly LedgerPostingV1[];\n}\n\n/** Privacy-safe, display-oriented journal entry returned by an API adapter. */\nexport interface ActivityEntryV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly transactionId: TransactionId;\n readonly activityType: ActivityType;\n readonly status: ActivityStatus;\n readonly occurredAt: IsoTimestamp;\n readonly amount: TokenSubunitString;\n /** Stable source identity used for filtering and provenance presentation. */\n readonly source: TokenSource;\n readonly beneficiaryAccountId?: AccountId;\n readonly maskedReference?: string;\n readonly sourceLabel: string;\n}\n\n/** Validates one privacy-safe activity row returned by an HTTP adapter. */\nexport function assertActivityEntry(entry: ActivityEntryV1): void {\n economyAssert(\n entry.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported activity-entry contract version\",\n );\n assertEconomyIdentifier(entry.transactionId, \"transactionId\");\n economyAssert(\n ACTIVITY_TYPES.has(entry.activityType) &&\n ACTIVITY_STATUSES.has(entry.status) &&\n ACTIVITY_SOURCES.has(entry.source),\n \"INVALID_CONTRACT\",\n \"Activity type, status, or source is unsupported\",\n );\n parseIsoTimestamp(entry.occurredAt);\n economyAssert(\n parseTokenSubunits(entry.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Activity entries cannot contain a zero amount\",\n );\n if (entry.beneficiaryAccountId !== undefined) {\n assertEconomyIdentifier(\n entry.beneficiaryAccountId,\n \"beneficiaryAccountId\",\n );\n }\n if (entry.maskedReference !== undefined) {\n economyAssert(\n typeof entry.maskedReference === \"string\" &&\n entry.maskedReference.length > 0 &&\n entry.maskedReference.length <= 128 &&\n !hasControlCharacters(entry.maskedReference),\n \"INVALID_CONTRACT\",\n \"Masked activity references must be bounded and safe for display\",\n );\n }\n economyAssert(\n typeof entry.sourceLabel === \"string\" &&\n entry.sourceLabel.trim().length > 0 &&\n entry.sourceLabel.length <= 128 &&\n !hasControlCharacters(entry.sourceLabel),\n \"INVALID_CONTRACT\",\n \"Activity source labels must be bounded and safe for display\",\n );\n}\n\n/** Proves the structural and arithmetic invariants of one transaction. */\nexport function assertBalancedTransaction(\n transaction: LedgerTransactionV1,\n): void {\n economyAssert(\n transaction.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported ledger contract version\",\n );\n assertEconomyIdentifier(transaction.transactionId, \"transactionId\");\n assertEconomyIdentifier(transaction.idempotencyKey, \"idempotencyKey\");\n economyAssert(\n ACTIVITY_TYPES.has(transaction.activityType) &&\n ACTIVITY_STATUSES.has(transaction.status),\n \"INVALID_CONTRACT\",\n \"Transaction activity type or status is unsupported\",\n );\n if (transaction.providerEventId !== undefined) {\n assertEconomyIdentifier(transaction.providerEventId, \"providerEventId\");\n }\n if (transaction.reversesTransactionId !== undefined) {\n assertEconomyIdentifier(\n transaction.reversesTransactionId,\n \"reversesTransactionId\",\n );\n }\n economyAssert(\n (transaction.activityType === \"reversal\") ===\n (transaction.reversesTransactionId !== undefined),\n \"INVALID_CONTRACT\",\n \"Reversal transactions must identify exactly one original transaction\",\n );\n const effectiveAt = parseIsoTimestamp(transaction.effectiveAt);\n const recordedAt = parseIsoTimestamp(transaction.recordedAt);\n economyAssert(\n recordedAt >= effectiveAt,\n \"INVALID_TIME_WINDOW\",\n \"Transaction recording time cannot precede its effective time\",\n );\n if (transaction.previousCanonicalHash !== undefined) {\n assertCanonicalHash(\n transaction.previousCanonicalHash,\n \"Previous canonical hash\",\n );\n }\n if (transaction.canonicalHash !== undefined) {\n assertCanonicalHash(transaction.canonicalHash, \"Canonical hash\");\n }\n const metadataEntries = Object.entries(transaction.metadata);\n economyAssert(\n metadataEntries.length <= 32 &&\n metadataEntries.every(\n ([key, value]) =>\n /^[A-Za-z][A-Za-z0-9_.-]{0,63}$/u.test(key) &&\n value.length <= 512 &&\n !hasControlCharacters(value),\n ),\n \"INVALID_CONTRACT\",\n \"Transaction metadata must be bounded and free of control characters\",\n );\n economyAssert(\n transaction.postings.length >= 2,\n \"UNBALANCED_TRANSACTION\",\n \"A ledger transaction needs at least two postings\",\n );\n\n const postingIds = new Set<string>();\n for (const posting of transaction.postings) {\n economyAssert(\n posting.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported posting contract version\",\n );\n assertEconomyIdentifier(posting.postingId, \"postingId\");\n assertEconomyIdentifier(posting.accountId, \"accountId\");\n if (posting.walletId !== undefined) {\n assertEconomyIdentifier(posting.walletId, \"walletId\");\n }\n if (posting.lotId !== undefined) {\n assertEconomyIdentifier(posting.lotId, \"lotId\");\n }\n economyAssert(\n posting.transactionId === transaction.transactionId,\n \"INVALID_CONTRACT\",\n \"Posting transactionId must match its transaction\",\n );\n economyAssert(\n !postingIds.has(posting.postingId),\n \"DUPLICATE_IDENTIFIER\",\n \"Posting identifiers must be unique within a transaction\",\n );\n postingIds.add(posting.postingId);\n economyAssert(\n parseTokenSubunits(posting.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Zero-value postings are not permitted\",\n );\n }\n\n economyAssert(\n sumTokenSubunits(transaction.postings.map((posting) => posting.amount)) ===\n 0n,\n \"UNBALANCED_TRANSACTION\",\n \"Ledger postings must sum to zero TokenSubunits\",\n );\n}\n\n/**\n * Produces deterministic UTF-8 JSON for an approved SHA-256/HSM adapter.\n * Hashing itself deliberately remains outside this provider-neutral package.\n */\nexport function canonicalTransactionPayload(\n transaction: LedgerTransactionV1,\n): string {\n assertBalancedTransaction(transaction);\n const postings = [...transaction.postings]\n .sort((left, right) => left.postingId.localeCompare(right.postingId))\n .map((posting) => ({\n schemaVersion: posting.schemaVersion,\n postingId: posting.postingId,\n transactionId: posting.transactionId,\n accountId: posting.accountId,\n ...(posting.walletId === undefined ? {} : { walletId: posting.walletId }),\n ...(posting.lotId === undefined ? {} : { lotId: posting.lotId }),\n amount: posting.amount,\n }));\n\n return JSON.stringify({\n schemaVersion: transaction.schemaVersion,\n transactionId: transaction.transactionId,\n activityType: transaction.activityType,\n status: transaction.status,\n idempotencyKey: transaction.idempotencyKey,\n ...(transaction.providerEventId === undefined\n ? {}\n : { providerEventId: transaction.providerEventId }),\n ...(transaction.reversesTransactionId === undefined\n ? {}\n : { reversesTransactionId: transaction.reversesTransactionId }),\n effectiveAt: transaction.effectiveAt,\n recordedAt: transaction.recordedAt,\n ...(transaction.previousCanonicalHash === undefined\n ? {}\n : { previousCanonicalHash: transaction.previousCanonicalHash }),\n metadata: sortStringRecord(transaction.metadata),\n postings,\n });\n}\n\nexport interface ReversalInputV1 {\n readonly transactionId: TransactionId;\n readonly postingIds: readonly PostingId[];\n readonly idempotencyKey: string;\n readonly effectiveAt: IsoTimestamp;\n readonly recordedAt: IsoTimestamp;\n readonly metadata?: Readonly<Record<string, string>>;\n readonly previousCanonicalHash?: string;\n}\n\n/** Creates an immutable compensating transaction; it never edits the original. */\nexport function createReversalTransaction(\n original: LedgerTransactionV1,\n input: ReversalInputV1,\n): LedgerTransactionV1 {\n assertBalancedTransaction(original);\n economyAssert(\n original.reversesTransactionId === undefined,\n \"INVALID_CONTRACT\",\n \"A reversal cannot itself be reversed by this helper\",\n );\n economyAssert(\n input.postingIds.length === original.postings.length,\n \"INVALID_CONTRACT\",\n \"A reversal needs one new posting identifier per original posting\",\n );\n\n const postings = original.postings.map((posting, index) => {\n const postingId = input.postingIds[index];\n economyAssert(\n postingId !== undefined,\n \"INVALID_CONTRACT\",\n \"Missing reversal posting identifier\",\n );\n return {\n ...posting,\n postingId,\n transactionId: input.transactionId,\n amount: serializeTokenSubunits(-parseTokenSubunits(posting.amount)),\n } satisfies LedgerPostingV1;\n });\n\n const transaction: LedgerTransactionV1 = {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n transactionId: input.transactionId,\n activityType: \"reversal\",\n status: \"settled\",\n idempotencyKey: input.idempotencyKey,\n reversesTransactionId: original.transactionId,\n effectiveAt: input.effectiveAt,\n recordedAt: input.recordedAt,\n ...(input.previousCanonicalHash === undefined\n ? {}\n : { previousCanonicalHash: input.previousCanonicalHash }),\n metadata: input.metadata ?? {},\n postings,\n };\n assertBalancedTransaction(transaction);\n return transaction;\n}\n\n/** Rejects a second effective reversal for the same original transaction. */\nexport function assertReversalAvailable(\n originalTransactionId: TransactionId,\n existingTransactions: readonly LedgerTransactionV1[],\n): void {\n assertEconomyIdentifier(originalTransactionId, \"originalTransactionId\");\n economyAssert(\n !existingTransactions.some(\n (transaction) =>\n transaction.reversesTransactionId === originalTransactionId &&\n transaction.status !== \"failed\",\n ),\n \"REVERSAL_ALREADY_EXISTS\",\n \"The transaction already has an effective reversal\",\n );\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type LotId,\n type ProviderEventId,\n type WalletId,\n} from \"./contracts.js\";\nimport { EconomyError, economyAssert } from \"./errors.js\";\n\nexport type TokenSource =\n | \"shopify\"\n | \"ayet\"\n | \"bitlabs\"\n | \"subscription\"\n | \"event\"\n | \"competition\"\n | \"adjustment\";\n\nexport type LotTransferPolicy =\n | \"household-allocatable\"\n | \"same-user-only\"\n | \"non-transferable\";\n\nexport type LotRefundState =\n | \"none\"\n | \"partial\"\n | \"refunded\"\n | \"disputed\"\n | \"chargeback-lost\";\n\nexport interface SourceLotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly lotId: LotId;\n readonly walletId: WalletId;\n readonly beneficiaryAccountId: AccountId;\n readonly householdId?: HouseholdId;\n readonly payerAccountId?: AccountId;\n readonly source: TokenSource;\n readonly providerEventId?: ProviderEventId;\n readonly rateVersion: string;\n readonly settlementEvidenceHash: string;\n readonly transferPolicy: LotTransferPolicy;\n readonly refundState: LotRefundState;\n readonly originalAmount: TokenSubunitString;\n readonly remainingAmount: TokenSubunitString;\n readonly heldAmount: TokenSubunitString;\n readonly reversedAmount: TokenSubunitString;\n readonly settledAt: IsoTimestamp;\n readonly creditedAt: IsoTimestamp;\n readonly cohortKey?: string;\n}\n\nexport type LotUseOperation = \"allocate\" | \"spend\" | \"reclaim\" | \"refund\";\n\nexport interface LotUseContextV1 {\n readonly operation: LotUseOperation;\n readonly beneficiaryAccountId: AccountId;\n readonly householdId?: HouseholdId;\n}\n\nexport interface SourceLotSliceV1 {\n readonly lotId: LotId;\n readonly amount: TokenSubunitString;\n}\n\n/** Validates source-lot arithmetic, evidence, and immutable provenance fields. */\nexport function assertSourceLot(lot: SourceLotV1): void {\n economyAssert(\n lot.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported source-lot contract version\",\n );\n assertEconomyIdentifier(lot.lotId, \"lotId\");\n assertEconomyIdentifier(lot.walletId, \"walletId\");\n assertEconomyIdentifier(lot.beneficiaryAccountId, \"beneficiaryAccountId\");\n if (lot.householdId !== undefined) {\n assertEconomyIdentifier(lot.householdId, \"householdId\");\n }\n if (lot.payerAccountId !== undefined) {\n assertEconomyIdentifier(lot.payerAccountId, \"payerAccountId\");\n }\n if (lot.providerEventId !== undefined) {\n assertEconomyIdentifier(lot.providerEventId, \"providerEventId\");\n }\n assertEconomyIdentifier(lot.rateVersion, \"rateVersion\");\n economyAssert(\n [\n \"shopify\",\n \"ayet\",\n \"bitlabs\",\n \"subscription\",\n \"event\",\n \"competition\",\n \"adjustment\",\n ].includes(lot.source),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported source\",\n );\n economyAssert(\n [\"household-allocatable\", \"same-user-only\", \"non-transferable\"].includes(\n lot.transferPolicy,\n ),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported transfer policy\",\n );\n economyAssert(\n [\"none\", \"partial\", \"refunded\", \"disputed\", \"chargeback-lost\"].includes(\n lot.refundState,\n ),\n \"INVALID_CONTRACT\",\n \"Source lot has an unsupported refund state\",\n );\n if (lot.source === \"ayet\" || lot.source === \"bitlabs\") {\n economyAssert(\n lot.transferPolicy === \"same-user-only\" &&\n lot.providerEventId !== undefined,\n \"SOURCE_LOT_RESTRICTED\",\n \"Reward-provider lots must remain with the earning account\",\n );\n }\n if (lot.source === \"shopify\") {\n economyAssert(\n lot.transferPolicy === \"household-allocatable\" &&\n lot.householdId !== undefined &&\n lot.payerAccountId !== undefined,\n \"INVALID_CONTRACT\",\n \"Shopify lots must retain payer and receiving-household provenance\",\n );\n }\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(lot.settlementEvidenceHash),\n \"INVALID_CONTRACT\",\n \"Settlement evidence must be a sanitized SHA-256 reference\",\n );\n const settledAt = parseIsoTimestamp(lot.settledAt);\n const creditedAt = parseIsoTimestamp(lot.creditedAt);\n economyAssert(\n creditedAt >= settledAt,\n \"INVALID_TIME_WINDOW\",\n \"Source-lot credit time cannot precede settlement\",\n );\n if (lot.cohortKey !== undefined) {\n assertEconomyIdentifier(lot.cohortKey, \"cohortKey\");\n }\n\n const original = parseTokenSubunits(lot.originalAmount);\n const remaining = parseTokenSubunits(lot.remainingAmount);\n const held = parseTokenSubunits(lot.heldAmount);\n const reversed = parseTokenSubunits(lot.reversedAmount);\n economyAssert(\n original > 0n && remaining >= 0n && held >= 0n && reversed >= 0n,\n \"INVALID_AMOUNT\",\n \"Source-lot amounts must be non-negative and original must be positive\",\n );\n economyAssert(\n remaining <= original && held <= remaining && reversed <= original,\n \"INVALID_CONTRACT\",\n \"Source-lot amount components exceed the original or remaining amount\",\n );\n economyAssert(\n remaining + reversed <= original,\n \"INVALID_CONTRACT\",\n \"Remaining and reversed source-lot amounts exceed the original\",\n );\n}\n\n/** Returns unheld, unconsumed TokenSubunits in a source lot. */\nexport function availableSourceLotAmount(lot: SourceLotV1): bigint {\n assertSourceLot(lot);\n return (\n parseTokenSubunits(lot.remainingAmount) - parseTokenSubunits(lot.heldAmount)\n );\n}\n\n/** Evaluates provider/source restrictions without trusting a browser claim. */\nexport function canUseSourceLot(\n lot: SourceLotV1,\n context: LotUseContextV1,\n): boolean {\n if (context.operation === \"refund\") {\n return true;\n }\n\n if (context.operation === \"allocate\" || context.operation === \"reclaim\") {\n return (\n lot.transferPolicy === \"household-allocatable\" &&\n lot.householdId !== undefined &&\n lot.householdId === context.householdId\n );\n }\n\n if (lot.transferPolicy === \"household-allocatable\") {\n return (\n lot.householdId !== undefined && lot.householdId === context.householdId\n );\n }\n\n return lot.beneficiaryAccountId === context.beneficiaryAccountId;\n}\n\n/**\n * Selects eligible lots deterministically in credited-time/lot-id order.\n * The returned slices are a proposal; persistence must consume them atomically.\n */\nexport function selectSourceLots(\n lots: readonly SourceLotV1[],\n requestedAmount: TokenSubunitString,\n context: LotUseContextV1,\n): readonly SourceLotSliceV1[] {\n const requested = parseTokenSubunits(requestedAmount);\n economyAssert(\n requested > 0n,\n \"INVALID_AMOUNT\",\n \"Requested source-lot amount must be positive\",\n );\n assertEconomyIdentifier(context.beneficiaryAccountId, \"beneficiaryAccountId\");\n\n const ordered = [...lots].sort((left, right) => {\n const timeDifference =\n parseIsoTimestamp(left.creditedAt) - parseIsoTimestamp(right.creditedAt);\n return timeDifference === 0\n ? left.lotId.localeCompare(right.lotId)\n : timeDifference;\n });\n\n let allAvailable = 0n;\n let remaining = requested;\n const slices: SourceLotSliceV1[] = [];\n\n for (const lot of ordered) {\n const available = availableSourceLotAmount(lot);\n allAvailable += available;\n if (available === 0n || !canUseSourceLot(lot, context)) {\n continue;\n }\n const selected = available < remaining ? available : remaining;\n slices.push({ lotId: lot.lotId, amount: serializeTokenSubunits(selected) });\n remaining -= selected;\n if (remaining === 0n) {\n return slices;\n }\n }\n\n if (allAvailable >= requested) {\n throw new EconomyError(\n \"SOURCE_LOT_RESTRICTED\",\n \"Available source lots do not permit this operation\",\n );\n }\n throw new EconomyError(\n \"INSUFFICIENT_ELIGIBLE_LOTS\",\n \"Insufficient eligible source-lot balance\",\n );\n}\n","import { parseTokenSubunits, type TokenSubunitString } from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n type WalletId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type AdjustmentStatus =\n | \"draft\"\n | \"pending-approval\"\n | \"approved\"\n | \"rejected\"\n | \"executed\"\n | \"expired\";\n\n/** Dual-control request; the resulting change is always a ledger transaction. */\nexport interface AdjustmentRequestV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly adjustmentId: string;\n readonly walletId: WalletId;\n readonly amount: TokenSubunitString;\n readonly reason: string;\n readonly ticketReference: string;\n readonly status: AdjustmentStatus;\n readonly initiatedByAccountId: AccountId;\n readonly initiatedAt: IsoTimestamp;\n readonly approvedByAccountId?: AccountId;\n readonly approvedAt?: IsoTimestamp;\n readonly resultingTransactionId?: TransactionId;\n}\n\n/** Proves that production adjustment approval was performed by another actor. */\nexport function assertDistinctAdjustmentApproval(\n request: AdjustmentRequestV1,\n): void {\n economyAssert(\n request.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported adjustment contract version\",\n );\n assertEconomyIdentifier(request.adjustmentId, \"adjustmentId\");\n assertEconomyIdentifier(request.walletId, \"walletId\");\n assertEconomyIdentifier(request.initiatedByAccountId, \"initiatedByAccountId\");\n economyAssert(\n parseTokenSubunits(request.amount) !== 0n,\n \"INVALID_AMOUNT\",\n \"Adjustment amount cannot be zero\",\n );\n economyAssert(\n request.reason.trim().length > 0 && request.reason.length <= 512,\n \"INVALID_CONTRACT\",\n \"Adjustment reason is required and must be bounded\",\n );\n assertEconomyIdentifier(request.ticketReference, \"ticketReference\");\n const initiatedAt = parseIsoTimestamp(request.initiatedAt);\n economyAssert(\n request.approvedByAccountId !== undefined &&\n request.approvedByAccountId !== request.initiatedByAccountId,\n \"INVALID_CONTRACT\",\n \"Adjustment approval requires a distinct authorized operator\",\n );\n assertEconomyIdentifier(request.approvedByAccountId, \"approvedByAccountId\");\n economyAssert(\n request.approvedAt !== undefined &&\n parseIsoTimestamp(request.approvedAt) >= initiatedAt,\n \"INVALID_TIME_WINDOW\",\n \"Adjustment approval time must follow initiation\",\n );\n economyAssert(\n request.status === \"approved\" || request.status === \"executed\",\n \"INVALID_CONTRACT\",\n \"Only approved adjustments satisfy dual-control approval\",\n );\n if (request.resultingTransactionId !== undefined) {\n assertEconomyIdentifier(\n request.resultingTransactionId,\n \"resultingTransactionId\",\n );\n }\n}\n","import {\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\nimport {\n assertBalancedTransaction,\n type LedgerTransactionV1,\n} from \"./ledger.js\";\n\nexport type BalanceProjection = Readonly<Record<AccountId, TokenSubunitString>>;\n\nexport interface BalanceProjectionSnapshotV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly balances: BalanceProjection;\n readonly lastTransactionId?: TransactionId;\n readonly rebuiltAt: IsoTimestamp;\n}\n\n/** Applies one balanced transaction without mutating the existing projection. */\nexport function applyTransactionToProjection(\n current: BalanceProjection,\n transaction: LedgerTransactionV1,\n): BalanceProjection {\n assertBalancedTransaction(transaction);\n const next: Record<AccountId, TokenSubunitString> = { ...current };\n for (const posting of transaction.postings) {\n const prior = parseTokenSubunits(next[posting.accountId] ?? \"0\");\n next[posting.accountId] = serializeTokenSubunits(\n prior + parseTokenSubunits(posting.amount),\n );\n }\n return next;\n}\n\n/**\n * Rebuilds balances deterministically and rejects duplicate economic envelopes.\n */\nexport function rebuildBalanceProjection(\n transactions: readonly LedgerTransactionV1[],\n): BalanceProjection {\n let projection: BalanceProjection = {};\n const transactionIds = new Set<string>();\n const idempotencyKeys = new Set<string>();\n const providerEvents = new Set<string>();\n\n for (const transaction of transactions) {\n economyAssert(\n !transactionIds.has(transaction.transactionId),\n \"DUPLICATE_TRANSACTION\",\n \"Transaction identifiers must be unique\",\n );\n economyAssert(\n !idempotencyKeys.has(transaction.idempotencyKey),\n \"DUPLICATE_TRANSACTION\",\n \"Idempotency keys must be unique\",\n );\n if (transaction.providerEventId !== undefined) {\n economyAssert(\n !providerEvents.has(transaction.providerEventId),\n \"DUPLICATE_TRANSACTION\",\n \"Provider event identifiers must be unique\",\n );\n providerEvents.add(transaction.providerEventId);\n }\n transactionIds.add(transaction.transactionId);\n idempotencyKeys.add(transaction.idempotencyKey);\n projection = applyTransactionToProjection(projection, transaction);\n }\n\n return projection;\n}\n\n/** Enforces non-negative balances only for spendable/reservable accounts. */\nexport function assertNonNegativeAccounts(\n projection: BalanceProjection,\n protectedAccountIds: readonly AccountId[],\n): void {\n for (const accountId of protectedAccountIds) {\n economyAssert(\n parseTokenSubunits(projection[accountId] ?? \"0\") >= 0n,\n \"NEGATIVE_PROJECTION\",\n \"A protected economy account would become negative\",\n );\n }\n}\n\n/** Creates a versioned snapshot after a deterministic rebuild. */\nexport function createProjectionSnapshot(\n transactions: readonly LedgerTransactionV1[],\n rebuiltAt: IsoTimestamp,\n): BalanceProjectionSnapshotV1 {\n parseIsoTimestamp(rebuiltAt);\n const last = transactions.at(-1);\n return {\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n balances: rebuildBalanceProjection(transactions),\n ...(last === undefined ? {} : { lastTransactionId: last.transactionId }),\n rebuiltAt,\n };\n}\n","import {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type EconomyContractVersion,\n type IsoTimestamp,\n} from \"./contracts.js\";\nimport {\n isWholeTokenAmount,\n parseTokenSubunits,\n serializeTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type RecurrenceInterval = \"daily\" | \"weekly\" | \"monthly\";\n\n/** Provider-neutral subscription contract. Site policy controls enablement. */\nexport interface TokenSubscriptionPlanV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly planId: string;\n readonly catalogVersion: string;\n readonly interval: RecurrenceInterval;\n readonly priceMinorUnits: string;\n readonly currency: \"GBP\";\n readonly grantAmount: TokenSubunitString;\n readonly enabled: boolean;\n readonly effectiveFrom: IsoTimestamp;\n}\n\n/** Future convenience plan contract; disabled until public spend is live. */\nexport const BASELINE_MONTHLY_SUBSCRIPTION_PLAN: TokenSubscriptionPlanV1 =\n Object.freeze({\n schemaVersion: ECONOMY_CONTRACT_VERSION,\n planId: \"monthly-10-100-v1\",\n catalogVersion: \"gbp-subscriptions-v1\",\n interval: \"monthly\",\n priceMinorUnits: \"1000\",\n currency: \"GBP\",\n grantAmount: serializeTokenSubunits(100_000n),\n enabled: false,\n effectiveFrom: \"2026-07-15T00:00:00.000Z\",\n });\n\n/** Validates future provider-neutral recurrence without enabling it. */\nexport function assertTokenSubscriptionPlan(\n plan: TokenSubscriptionPlanV1,\n): void {\n economyAssert(\n plan.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported subscription-plan contract version\",\n );\n assertEconomyIdentifier(plan.planId, \"planId\");\n assertEconomyIdentifier(plan.catalogVersion, \"catalogVersion\");\n economyAssert(\n [\"daily\", \"weekly\", \"monthly\"].includes(plan.interval) &&\n plan.currency === \"GBP\" &&\n typeof plan.enabled === \"boolean\",\n \"INVALID_CONTRACT\",\n \"Subscription recurrence, currency, or enabled state is invalid\",\n );\n economyAssert(\n /^(?:0|[1-9][0-9]*)$/u.test(plan.priceMinorUnits) &&\n BigInt(plan.priceMinorUnits) > 0n,\n \"INVALID_AMOUNT\",\n \"Subscription price must be a positive integer minor-unit string\",\n );\n const grantAmount = parseTokenSubunits(plan.grantAmount);\n economyAssert(\n grantAmount > 0n && isWholeTokenAmount(grantAmount),\n \"AMOUNT_NOT_WHOLE_TOKEN\",\n \"Subscription grants must contain whole Tokens\",\n );\n parseIsoTimestamp(plan.effectiveFrom);\n}\n","import { parseTokenSubunits, type TokenSubunitString } from \"./amount.js\";\nimport {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type AllocationId,\n type EconomyContractVersion,\n type IsoTimestamp,\n type TransactionId,\n} from \"./contracts.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type SpendRequestPurpose = \"gameplay-conversion\" | \"non-gameplay\";\nexport type SpendRequestStatus =\n | \"requested\"\n | \"approved\"\n | \"rejected\"\n | \"expired\"\n | \"executed\"\n | \"cancelled\";\n\n/** Future child request; baseline adapters must reject creation while disabled. */\nexport interface SpendRequestV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly requestId: string;\n readonly childAccountId: AccountId;\n readonly allocationId: AllocationId;\n readonly purpose: SpendRequestPurpose;\n readonly amount: TokenSubunitString;\n readonly status: SpendRequestStatus;\n readonly requestedAt: IsoTimestamp;\n readonly expiresAt: IsoTimestamp;\n readonly decidedByAccountId?: AccountId;\n readonly decidedAt?: IsoTimestamp;\n readonly approvalNonceHash?: string;\n readonly resultingTransactionId?: TransactionId;\n}\n\n/** Validates future child requests while creation remains policy-disabled. */\nexport function assertSpendRequest(request: SpendRequestV1): void {\n economyAssert(\n request.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported spend-request contract version\",\n );\n assertEconomyIdentifier(request.requestId, \"requestId\");\n assertEconomyIdentifier(request.childAccountId, \"childAccountId\");\n assertEconomyIdentifier(request.allocationId, \"allocationId\");\n economyAssert(\n request.purpose === \"gameplay-conversion\" ||\n request.purpose === \"non-gameplay\",\n \"INVALID_CONTRACT\",\n \"Spend request has an unsupported purpose\",\n );\n economyAssert(\n [\n \"requested\",\n \"approved\",\n \"rejected\",\n \"expired\",\n \"executed\",\n \"cancelled\",\n ].includes(request.status),\n \"INVALID_CONTRACT\",\n \"Spend request has an unsupported status\",\n );\n economyAssert(\n parseTokenSubunits(request.amount) > 0n,\n \"INVALID_AMOUNT\",\n \"Spend-request amount must be positive\",\n );\n const requestedAt = parseIsoTimestamp(request.requestedAt);\n const expiresAt = parseIsoTimestamp(request.expiresAt);\n economyAssert(\n expiresAt > requestedAt,\n \"INVALID_TIME_WINDOW\",\n \"Spend-request expiry must follow creation\",\n );\n\n const decisionRequired = [\"approved\", \"rejected\", \"executed\"].includes(\n request.status,\n );\n economyAssert(\n !decisionRequired ||\n (request.decidedByAccountId !== undefined &&\n request.decidedAt !== undefined),\n \"INVALID_CONTRACT\",\n \"Decided spend requests require a guardian actor and timestamp\",\n );\n if (request.decidedByAccountId !== undefined) {\n assertEconomyIdentifier(request.decidedByAccountId, \"decidedByAccountId\");\n }\n if (request.decidedAt !== undefined) {\n const decidedAt = parseIsoTimestamp(request.decidedAt);\n economyAssert(\n decidedAt >= requestedAt && decidedAt <= expiresAt,\n \"INVALID_TIME_WINDOW\",\n \"Spend-request decision must occur before expiry\",\n );\n }\n if (request.approvalNonceHash !== undefined) {\n economyAssert(\n /^sha256:[a-f0-9]{64}$/u.test(request.approvalNonceHash),\n \"INVALID_CONTRACT\",\n \"Approval nonces must be stored as SHA-256 hashes\",\n );\n }\n if (request.status === \"approved\" || request.status === \"executed\") {\n economyAssert(\n request.approvalNonceHash !== undefined,\n \"INVALID_CONTRACT\",\n \"Approved spend requests require a one-time approval nonce hash\",\n );\n }\n if (request.resultingTransactionId !== undefined) {\n assertEconomyIdentifier(\n request.resultingTransactionId,\n \"resultingTransactionId\",\n );\n economyAssert(\n request.status === \"executed\",\n \"INVALID_CONTRACT\",\n \"Only executed spend requests may reference a ledger transaction\",\n );\n }\n}\n","import {\n ECONOMY_CONTRACT_VERSION,\n assertEconomyIdentifier,\n parseIsoTimestamp,\n type AccountId,\n type EconomyContractVersion,\n type HouseholdId,\n type IsoTimestamp,\n type WalletId,\n} from \"./contracts.js\";\nimport {\n parseTokenSubunits,\n type TokenSubunitString,\n} from \"./amount.js\";\nimport { economyAssert } from \"./errors.js\";\n\nexport type WalletKind =\n | \"household-treasury\"\n | \"personal\"\n | \"gameplay-allocation\"\n | \"hold\"\n | \"purchase-clearing\"\n | \"provider-clearing\"\n | \"system\";\n\nexport type WalletStatus = \"active\" | \"restricted\" | \"closed\";\nexport type WalletOwnerType = \"account\" | \"household\" | \"system\";\n\n/** Versioned authoritative wallet descriptor. */\nexport interface WalletV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly walletId: WalletId;\n readonly accountId: AccountId;\n readonly kind: WalletKind;\n readonly ownerType: WalletOwnerType;\n readonly ownerId: AccountId | HouseholdId | \"system\";\n readonly householdId?: HouseholdId;\n readonly status: WalletStatus;\n readonly version: number;\n readonly createdAt: IsoTimestamp;\n readonly closedAt?: IsoTimestamp;\n}\n\n/** Server-computed wallet totals. Clients must never derive authority from it. */\nexport interface WalletBalanceSummaryV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly walletId: WalletId;\n readonly available: TokenSubunitString;\n readonly reserved: TokenSubunitString;\n readonly held: TokenSubunitString;\n readonly rewardProgress: TokenSubunitString;\n readonly version: number;\n readonly asOf: IsoTimestamp;\n}\n\n/** Lifetime aggregates used by the Token profile. */\nexport interface WalletLifetimeTotalsV1 {\n readonly schemaVersion: EconomyContractVersion;\n readonly bought: TokenSubunitString;\n readonly earned: TokenSubunitString;\n readonly allocated: TokenSubunitString;\n readonly reclaimed: TokenSubunitString;\n readonly spent: TokenSubunitString;\n readonly reversed: TokenSubunitString;\n}\n\n/** Validates wallet ownership, lifecycle, and optimistic-version facts. */\nexport function assertWallet(wallet: WalletV1): void {\n economyAssert(\n wallet.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet contract version\",\n );\n assertEconomyIdentifier(wallet.walletId, \"walletId\");\n assertEconomyIdentifier(wallet.accountId, \"accountId\");\n economyAssert(\n [\n \"household-treasury\",\n \"personal\",\n \"gameplay-allocation\",\n \"hold\",\n \"purchase-clearing\",\n \"provider-clearing\",\n \"system\",\n ].includes(wallet.kind),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported kind\",\n );\n economyAssert(\n [\"account\", \"household\", \"system\"].includes(wallet.ownerType),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported owner type\",\n );\n economyAssert(\n [\"active\", \"restricted\", \"closed\"].includes(wallet.status),\n \"INVALID_CONTRACT\",\n \"Wallet has an unsupported status\",\n );\n if (wallet.ownerType === \"system\") {\n economyAssert(\n wallet.ownerId === \"system\",\n \"INVALID_CONTRACT\",\n \"System wallets must be owned by the system\",\n );\n } else {\n assertEconomyIdentifier(wallet.ownerId, \"ownerId\");\n }\n if (wallet.householdId !== undefined) {\n assertEconomyIdentifier(wallet.householdId, \"householdId\");\n }\n if (wallet.ownerType === \"household\") {\n economyAssert(\n wallet.householdId === wallet.ownerId,\n \"INVALID_CONTRACT\",\n \"Household wallets must identify the same household owner\",\n );\n }\n if (wallet.kind === \"household-treasury\") {\n economyAssert(\n wallet.ownerType === \"household\" && wallet.householdId !== undefined,\n \"INVALID_CONTRACT\",\n \"Household treasuries must be owned by their household\",\n );\n }\n if (wallet.kind === \"personal\" || wallet.kind === \"gameplay-allocation\") {\n economyAssert(\n wallet.ownerType === \"account\",\n \"INVALID_CONTRACT\",\n \"Personal and gameplay-allocation wallets must be account-owned\",\n );\n }\n if (wallet.kind === \"gameplay-allocation\") {\n economyAssert(\n wallet.householdId !== undefined,\n \"INVALID_CONTRACT\",\n \"Gameplay-allocation wallets must retain household provenance\",\n );\n }\n if (\n wallet.kind === \"purchase-clearing\" ||\n wallet.kind === \"provider-clearing\" ||\n wallet.kind === \"system\"\n ) {\n economyAssert(\n wallet.ownerType === \"system\" && wallet.householdId === undefined,\n \"INVALID_CONTRACT\",\n \"Clearing and system wallets must be system-owned\",\n );\n }\n economyAssert(\n Number.isSafeInteger(wallet.version) && wallet.version >= 1,\n \"INVALID_CONTRACT\",\n \"Wallet version must be a positive safe integer\",\n );\n const createdAt = parseIsoTimestamp(wallet.createdAt);\n if (wallet.closedAt !== undefined) {\n economyAssert(\n parseIsoTimestamp(wallet.closedAt) >= createdAt &&\n wallet.status === \"closed\",\n \"INVALID_TIME_WINDOW\",\n \"Only closed wallets may have a valid closure time\",\n );\n } else {\n economyAssert(\n wallet.status !== \"closed\",\n \"INVALID_CONTRACT\",\n \"Closed wallets require a closure time\",\n );\n }\n}\n\n/** Validates non-negative server-computed wallet balance categories. */\nexport function assertWalletBalanceSummary(\n summary: WalletBalanceSummaryV1,\n): void {\n economyAssert(\n summary.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet summary contract version\",\n );\n assertEconomyIdentifier(summary.walletId, \"walletId\");\n for (const amount of [\n summary.available,\n summary.reserved,\n summary.held,\n summary.rewardProgress,\n ]) {\n economyAssert(\n parseTokenSubunits(amount) >= 0n,\n \"INVALID_AMOUNT\",\n \"Wallet summary categories cannot be negative\",\n );\n }\n economyAssert(\n Number.isSafeInteger(summary.version) && summary.version >= 1,\n \"INVALID_CONTRACT\",\n \"Wallet summary version must be a positive safe integer\",\n );\n parseIsoTimestamp(summary.asOf);\n}\n\n/** Validates non-negative lifetime aggregates exposed by the profile API. */\nexport function assertWalletLifetimeTotals(\n totals: WalletLifetimeTotalsV1,\n): void {\n economyAssert(\n totals.schemaVersion === ECONOMY_CONTRACT_VERSION,\n \"INVALID_CONTRACT\",\n \"Unsupported wallet lifetime-total contract version\",\n );\n for (const amount of [\n totals.bought,\n totals.earned,\n totals.allocated,\n totals.reclaimed,\n totals.spent,\n totals.reversed,\n ]) {\n economyAssert(\n parseTokenSubunits(amount) >= 0n,\n \"INVALID_AMOUNT\",\n \"Wallet lifetime totals cannot be negative\",\n );\n }\n}\n"],"mappings":"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","names":[]}
|