@peable.to/contracts 5.5.0 → 5.6.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.
@@ -148,7 +148,7 @@ exports.socialRoutes = [
148
148
  path: '/v1/social/{username}/next_address',
149
149
  tag: 'Social payments',
150
150
  summary: 'Reserve an address to pay a person',
151
- description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`; paying yourself is refused.",
151
+ description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`, and one whose wallet watches no further address (every index below its watched bound is taken) 503 `faircoin_receive_tree_full`; paying yourself is refused.",
152
152
  auth: 'user',
153
153
  params: { username: 'The recipient’s Oxy username.' },
154
154
  body: exports.socialNextAddressParams,
@@ -135,6 +135,7 @@ exports.ERROR_CODE_DESCRIPTIONS = {
135
135
  faircoin_wallet_missing: "The Peable wallet that receives this payment (the merchant owner's, or the seller's) isn't set up yet, so it cannot be paid in FairCoin. The other payment methods still work.",
136
136
  faircoin_network_closed: 'FairCoin payments on this network are not open on this deployment yet. The other payment methods still work.',
137
137
  faircoin_capacity_reached: 'Too many FairCoin payments to this recipient are waiting to be paid right now, so no new FairCoin address can be handed out. The other payment methods still work; try FairCoin again shortly.',
138
+ faircoin_receive_tree_full: "Every FairCoin address the recipient's Peable wallet watches has been handed out, so no new one can be derived for them. Nothing was reserved.",
138
139
  faircoin_amount_too_small: "One seller's share of this order is below the smallest amount the FairCoin network relays, so it cannot be paid in FairCoin. The other payment methods still work.",
139
140
  credit_note_exceeds_invoice: "The credit note's amount exceeds what the invoice can still credit.",
140
141
  test_clock_unexpected_state: 'The test clock is advancing; wait until it is ready.',
@@ -38,3 +38,4 @@ __exportStar(require("./identity"), exports);
38
38
  __exportStar(require("./merchants"), exports);
39
39
  __exportStar(require("./paymentMethodConfigurations"), exports);
40
40
  __exportStar(require("./realtime"), exports);
41
+ __exportStar(require("./receiveTree"), exports);
@@ -33,17 +33,21 @@ exports.PAYMENT_INTENT_STATUSES = [
33
33
  'canceled',
34
34
  ];
35
35
  /**
36
- * Why an intent was cancelled — Stripe's reasons, plus two FairCoin-only ones:
37
- * `underpaid` (a transaction paid less than the amount) and
36
+ * Why an intent was cancelled — Stripe's reasons, plus three FairCoin-only ones:
37
+ * `underpaid` (a transaction paid less than the amount),
38
38
  * `recipient_key_changed` (the recipient's identity key was replaced after the
39
39
  * address was reserved, so the address is no longer in the wallet it pays —
40
40
  * ADR 0002, amended 2026-11-06; nothing had been broadcast, and the order stays
41
- * open for a fresh address).
41
+ * open for a fresh address) and `faircoin_network_closed` (the deployment
42
+ * closed the payment's FairCoin network — ADR 0002's gate — before anything was
43
+ * broadcast; the order stays open, and FairCoin on it says the network is
44
+ * closed).
42
45
  */
43
46
  exports.PAYMENT_INTENT_CANCELLATION_REASONS = [
44
47
  'abandoned',
45
48
  'automatic',
46
49
  'duplicate',
50
+ 'faircoin_network_closed',
47
51
  'fraudulent',
48
52
  'recipient_key_changed',
49
53
  'requested_by_customer',
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * The size of a recipient's FairCoin receive tree (ADR 0021 D9, amended
4
+ * 2026-11-06) — ONE answer, read by the gateway that hands out indices and by
5
+ * the Peable wallet that watches them.
6
+ *
7
+ * Every FairCoin address the gateway reserves for an account — a merchant
8
+ * payment, a marketplace seller's, an invoice's, `@username` — is index `i` of
9
+ * that account's identity tree (ADR 0002, ADR 0021 D5). The wallet watches a
10
+ * contiguous window, indices `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`, reaching
11
+ * {@link SOCIAL_RECEIVE_GAP_LIMIT} past the highest index reserved
12
+ * (`planSocialReceiveWindow` in `packages/frontend/src/wallet/social-receive.ts`),
13
+ * and stops offering `@username` once that reach would pass its bound. So an
14
+ * index is reserved only when the wallet, after reserving it, still reaches
15
+ * the gap above it inside its bound:
16
+ *
17
+ * index + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1
18
+ * index < SOCIAL_RECEIVE_INDEX_LIMIT
19
+ *
20
+ * The gateway refuses to mint `index >= SOCIAL_RECEIVE_INDEX_LIMIT` (in the
21
+ * reservation's own statement), so every address it hands out is inside the
22
+ * window the wallet watches. Zod-free and dependency-free: the wallet bundles
23
+ * this module alone (`@peable.to/contracts/vocabulary/receiveTree`).
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.SOCIAL_RECEIVE_NEARLY_FULL_REMAINING = exports.SOCIAL_RECEIVE_INDEX_LIMIT = exports.SOCIAL_RECEIVE_GAP_LIMIT = exports.SOCIAL_RECEIVE_MAX_WATCHED = void 0;
27
+ /** The most indices the wallet watches: `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`. */
28
+ exports.SOCIAL_RECEIVE_MAX_WATCHED = 2000;
29
+ /**
30
+ * How many unused addresses the wallet watches beyond the highest index used
31
+ * or reserved — the FairCoin BIP44 external-chain gap limit.
32
+ */
33
+ exports.SOCIAL_RECEIVE_GAP_LIMIT = 20;
34
+ /**
35
+ * The first index the gateway never mints (exclusive bound): `1 980`. Every
36
+ * minted index `i` satisfies `i < SOCIAL_RECEIVE_INDEX_LIMIT`, i.e.
37
+ * `i + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1`.
38
+ */
39
+ exports.SOCIAL_RECEIVE_INDEX_LIMIT = exports.SOCIAL_RECEIVE_MAX_WATCHED - exports.SOCIAL_RECEIVE_GAP_LIMIT;
40
+ /**
41
+ * How close to {@link SOCIAL_RECEIVE_INDEX_LIMIT} a tree is "nearly full":
42
+ * Orbit warns the owners once fewer fresh indices than this are left.
43
+ */
44
+ exports.SOCIAL_RECEIVE_NEARLY_FULL_REMAINING = 200;
@@ -145,7 +145,7 @@ export const socialRoutes = [
145
145
  path: '/v1/social/{username}/next_address',
146
146
  tag: 'Social payments',
147
147
  summary: 'Reserve an address to pay a person',
148
- description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`; paying yourself is refused.",
148
+ description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`, and one whose wallet watches no further address (every index below its watched bound is taken) 503 `faircoin_receive_tree_full`; paying yourself is refused.",
149
149
  auth: 'user',
150
150
  params: { username: 'The recipient’s Oxy username.' },
151
151
  body: socialNextAddressParams,
@@ -130,6 +130,7 @@ export const ERROR_CODE_DESCRIPTIONS = {
130
130
  faircoin_wallet_missing: "The Peable wallet that receives this payment (the merchant owner's, or the seller's) isn't set up yet, so it cannot be paid in FairCoin. The other payment methods still work.",
131
131
  faircoin_network_closed: 'FairCoin payments on this network are not open on this deployment yet. The other payment methods still work.',
132
132
  faircoin_capacity_reached: 'Too many FairCoin payments to this recipient are waiting to be paid right now, so no new FairCoin address can be handed out. The other payment methods still work; try FairCoin again shortly.',
133
+ faircoin_receive_tree_full: "Every FairCoin address the recipient's Peable wallet watches has been handed out, so no new one can be derived for them. Nothing was reserved.",
133
134
  faircoin_amount_too_small: "One seller's share of this order is below the smallest amount the FairCoin network relays, so it cannot be paid in FairCoin. The other payment methods still work.",
134
135
  credit_note_exceeds_invoice: "The credit note's amount exceeds what the invoice can still credit.",
135
136
  test_clock_unexpected_state: 'The test clock is advancing; wait until it is ready.',
@@ -22,3 +22,4 @@ export * from './identity.js';
22
22
  export * from './merchants.js';
23
23
  export * from './paymentMethodConfigurations.js';
24
24
  export * from './realtime.js';
25
+ export * from './receiveTree.js';
@@ -30,17 +30,21 @@ export const PAYMENT_INTENT_STATUSES = [
30
30
  'canceled',
31
31
  ];
32
32
  /**
33
- * Why an intent was cancelled — Stripe's reasons, plus two FairCoin-only ones:
34
- * `underpaid` (a transaction paid less than the amount) and
33
+ * Why an intent was cancelled — Stripe's reasons, plus three FairCoin-only ones:
34
+ * `underpaid` (a transaction paid less than the amount),
35
35
  * `recipient_key_changed` (the recipient's identity key was replaced after the
36
36
  * address was reserved, so the address is no longer in the wallet it pays —
37
37
  * ADR 0002, amended 2026-11-06; nothing had been broadcast, and the order stays
38
- * open for a fresh address).
38
+ * open for a fresh address) and `faircoin_network_closed` (the deployment
39
+ * closed the payment's FairCoin network — ADR 0002's gate — before anything was
40
+ * broadcast; the order stays open, and FairCoin on it says the network is
41
+ * closed).
39
42
  */
40
43
  export const PAYMENT_INTENT_CANCELLATION_REASONS = [
41
44
  'abandoned',
42
45
  'automatic',
43
46
  'duplicate',
47
+ 'faircoin_network_closed',
44
48
  'fraudulent',
45
49
  'recipient_key_changed',
46
50
  'requested_by_customer',
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The size of a recipient's FairCoin receive tree (ADR 0021 D9, amended
3
+ * 2026-11-06) — ONE answer, read by the gateway that hands out indices and by
4
+ * the Peable wallet that watches them.
5
+ *
6
+ * Every FairCoin address the gateway reserves for an account — a merchant
7
+ * payment, a marketplace seller's, an invoice's, `@username` — is index `i` of
8
+ * that account's identity tree (ADR 0002, ADR 0021 D5). The wallet watches a
9
+ * contiguous window, indices `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`, reaching
10
+ * {@link SOCIAL_RECEIVE_GAP_LIMIT} past the highest index reserved
11
+ * (`planSocialReceiveWindow` in `packages/frontend/src/wallet/social-receive.ts`),
12
+ * and stops offering `@username` once that reach would pass its bound. So an
13
+ * index is reserved only when the wallet, after reserving it, still reaches
14
+ * the gap above it inside its bound:
15
+ *
16
+ * index + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1
17
+ * index < SOCIAL_RECEIVE_INDEX_LIMIT
18
+ *
19
+ * The gateway refuses to mint `index >= SOCIAL_RECEIVE_INDEX_LIMIT` (in the
20
+ * reservation's own statement), so every address it hands out is inside the
21
+ * window the wallet watches. Zod-free and dependency-free: the wallet bundles
22
+ * this module alone (`@peable.to/contracts/vocabulary/receiveTree`).
23
+ */
24
+ /** The most indices the wallet watches: `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`. */
25
+ export const SOCIAL_RECEIVE_MAX_WATCHED = 2000;
26
+ /**
27
+ * How many unused addresses the wallet watches beyond the highest index used
28
+ * or reserved — the FairCoin BIP44 external-chain gap limit.
29
+ */
30
+ export const SOCIAL_RECEIVE_GAP_LIMIT = 20;
31
+ /**
32
+ * The first index the gateway never mints (exclusive bound): `1 980`. Every
33
+ * minted index `i` satisfies `i < SOCIAL_RECEIVE_INDEX_LIMIT`, i.e.
34
+ * `i + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1`.
35
+ */
36
+ export const SOCIAL_RECEIVE_INDEX_LIMIT = SOCIAL_RECEIVE_MAX_WATCHED - SOCIAL_RECEIVE_GAP_LIMIT;
37
+ /**
38
+ * How close to {@link SOCIAL_RECEIVE_INDEX_LIMIT} a tree is "nearly full":
39
+ * Orbit warns the owners once fewer fresh indices than this are left.
40
+ */
41
+ export const SOCIAL_RECEIVE_NEARLY_FULL_REMAINING = 200;
@@ -178,6 +178,7 @@ export declare const paymentsRoutes: readonly [{
178
178
  message: import("zod").ZodString;
179
179
  }, import("zod/v4/core").$strict>>;
180
180
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
181
+ faircoin_network_closed: "faircoin_network_closed";
181
182
  duplicate: "duplicate";
182
183
  fraudulent: "fraudulent";
183
184
  abandoned: "abandoned";
@@ -402,6 +403,7 @@ export declare const paymentsRoutes: readonly [{
402
403
  message: import("zod").ZodString;
403
404
  }, import("zod/v4/core").$strict>>;
404
405
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
406
+ faircoin_network_closed: "faircoin_network_closed";
405
407
  duplicate: "duplicate";
406
408
  fraudulent: "fraudulent";
407
409
  abandoned: "abandoned";
@@ -607,6 +609,7 @@ export declare const paymentsRoutes: readonly [{
607
609
  message: import("zod").ZodString;
608
610
  }, import("zod/v4/core").$strict>>;
609
611
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
612
+ faircoin_network_closed: "faircoin_network_closed";
610
613
  duplicate: "duplicate";
611
614
  fraudulent: "fraudulent";
612
615
  abandoned: "abandoned";
@@ -826,6 +829,7 @@ export declare const paymentsRoutes: readonly [{
826
829
  message: import("zod").ZodString;
827
830
  }, import("zod/v4/core").$strict>>;
828
831
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
832
+ faircoin_network_closed: "faircoin_network_closed";
829
833
  duplicate: "duplicate";
830
834
  fraudulent: "fraudulent";
831
835
  abandoned: "abandoned";
@@ -1075,6 +1079,7 @@ export declare const paymentsRoutes: readonly [{
1075
1079
  message: import("zod").ZodString;
1076
1080
  }, import("zod/v4/core").$strict>>;
1077
1081
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
1082
+ faircoin_network_closed: "faircoin_network_closed";
1078
1083
  duplicate: "duplicate";
1079
1084
  fraudulent: "fraudulent";
1080
1085
  abandoned: "abandoned";
@@ -1278,6 +1283,7 @@ export declare const paymentsRoutes: readonly [{
1278
1283
  message: import("zod").ZodString;
1279
1284
  }, import("zod/v4/core").$strict>>;
1280
1285
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
1286
+ faircoin_network_closed: "faircoin_network_closed";
1281
1287
  duplicate: "duplicate";
1282
1288
  fraudulent: "fraudulent";
1283
1289
  abandoned: "abandoned";
@@ -1486,6 +1492,7 @@ export declare const paymentsRoutes: readonly [{
1486
1492
  message: import("zod").ZodString;
1487
1493
  }, import("zod/v4/core").$strict>>;
1488
1494
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
1495
+ faircoin_network_closed: "faircoin_network_closed";
1489
1496
  duplicate: "duplicate";
1490
1497
  fraudulent: "fraudulent";
1491
1498
  abandoned: "abandoned";
@@ -1687,6 +1694,7 @@ export declare const paymentsRoutes: readonly [{
1687
1694
  message: import("zod").ZodString;
1688
1695
  }, import("zod/v4/core").$strict>>;
1689
1696
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
1697
+ faircoin_network_closed: "faircoin_network_closed";
1690
1698
  duplicate: "duplicate";
1691
1699
  fraudulent: "fraudulent";
1692
1700
  abandoned: "abandoned";
@@ -1888,6 +1896,7 @@ export declare const paymentsRoutes: readonly [{
1888
1896
  message: import("zod").ZodString;
1889
1897
  }, import("zod/v4/core").$strict>>;
1890
1898
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
1899
+ faircoin_network_closed: "faircoin_network_closed";
1891
1900
  duplicate: "duplicate";
1892
1901
  fraudulent: "fraudulent";
1893
1902
  abandoned: "abandoned";
@@ -3703,7 +3712,7 @@ export declare const paymentsRoutes: readonly [{
3703
3712
  readonly path: "/v1/social/{username}/next_address";
3704
3713
  readonly tag: "Social payments";
3705
3714
  readonly summary: "Reserve an address to pay a person";
3706
- readonly description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`; paying yourself is refused.";
3715
+ readonly description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`, and one whose wallet watches no further address (every index below its watched bound is taken) 503 `faircoin_receive_tree_full`; paying yourself is refused.";
3707
3716
  readonly auth: "user";
3708
3717
  readonly params: {
3709
3718
  readonly username: "The recipient’s Oxy username.";
@@ -3911,6 +3920,7 @@ export declare const paymentsRoutes: readonly [{
3911
3920
  message: import("zod").ZodString;
3912
3921
  }, import("zod/v4/core").$strict>>;
3913
3922
  cancellation_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
3923
+ faircoin_network_closed: "faircoin_network_closed";
3914
3924
  duplicate: "duplicate";
3915
3925
  fraudulent: "fraudulent";
3916
3926
  abandoned: "abandoned";
@@ -262,6 +262,7 @@ export declare const paymentIntentSchema: z.ZodObject<{
262
262
  message: z.ZodString;
263
263
  }, z.core.$strict>>;
264
264
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
265
+ faircoin_network_closed: "faircoin_network_closed";
265
266
  duplicate: "duplicate";
266
267
  fraudulent: "fraudulent";
267
268
  abandoned: "abandoned";
@@ -770,6 +771,7 @@ export declare const paymentIntentRoutes: readonly [{
770
771
  message: z.ZodString;
771
772
  }, z.core.$strict>>;
772
773
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
774
+ faircoin_network_closed: "faircoin_network_closed";
773
775
  duplicate: "duplicate";
774
776
  fraudulent: "fraudulent";
775
777
  abandoned: "abandoned";
@@ -994,6 +996,7 @@ export declare const paymentIntentRoutes: readonly [{
994
996
  message: z.ZodString;
995
997
  }, z.core.$strict>>;
996
998
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
999
+ faircoin_network_closed: "faircoin_network_closed";
997
1000
  duplicate: "duplicate";
998
1001
  fraudulent: "fraudulent";
999
1002
  abandoned: "abandoned";
@@ -1199,6 +1202,7 @@ export declare const paymentIntentRoutes: readonly [{
1199
1202
  message: z.ZodString;
1200
1203
  }, z.core.$strict>>;
1201
1204
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
1205
+ faircoin_network_closed: "faircoin_network_closed";
1202
1206
  duplicate: "duplicate";
1203
1207
  fraudulent: "fraudulent";
1204
1208
  abandoned: "abandoned";
@@ -1418,6 +1422,7 @@ export declare const paymentIntentRoutes: readonly [{
1418
1422
  message: z.ZodString;
1419
1423
  }, z.core.$strict>>;
1420
1424
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
1425
+ faircoin_network_closed: "faircoin_network_closed";
1421
1426
  duplicate: "duplicate";
1422
1427
  fraudulent: "fraudulent";
1423
1428
  abandoned: "abandoned";
@@ -1667,6 +1672,7 @@ export declare const paymentIntentRoutes: readonly [{
1667
1672
  message: z.ZodString;
1668
1673
  }, z.core.$strict>>;
1669
1674
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
1675
+ faircoin_network_closed: "faircoin_network_closed";
1670
1676
  duplicate: "duplicate";
1671
1677
  fraudulent: "fraudulent";
1672
1678
  abandoned: "abandoned";
@@ -1870,6 +1876,7 @@ export declare const paymentIntentRoutes: readonly [{
1870
1876
  message: z.ZodString;
1871
1877
  }, z.core.$strict>>;
1872
1878
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
1879
+ faircoin_network_closed: "faircoin_network_closed";
1873
1880
  duplicate: "duplicate";
1874
1881
  fraudulent: "fraudulent";
1875
1882
  abandoned: "abandoned";
@@ -2078,6 +2085,7 @@ export declare const paymentIntentRoutes: readonly [{
2078
2085
  message: z.ZodString;
2079
2086
  }, z.core.$strict>>;
2080
2087
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
2088
+ faircoin_network_closed: "faircoin_network_closed";
2081
2089
  duplicate: "duplicate";
2082
2090
  fraudulent: "fraudulent";
2083
2091
  abandoned: "abandoned";
@@ -2279,6 +2287,7 @@ export declare const paymentIntentRoutes: readonly [{
2279
2287
  message: z.ZodString;
2280
2288
  }, z.core.$strict>>;
2281
2289
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
2290
+ faircoin_network_closed: "faircoin_network_closed";
2282
2291
  duplicate: "duplicate";
2283
2292
  fraudulent: "fraudulent";
2284
2293
  abandoned: "abandoned";
@@ -2480,6 +2489,7 @@ export declare const paymentIntentRoutes: readonly [{
2480
2489
  message: z.ZodString;
2481
2490
  }, z.core.$strict>>;
2482
2491
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
2492
+ faircoin_network_closed: "faircoin_network_closed";
2483
2493
  duplicate: "duplicate";
2484
2494
  fraudulent: "fraudulent";
2485
2495
  abandoned: "abandoned";
@@ -166,7 +166,7 @@ export declare const socialRoutes: readonly [{
166
166
  readonly path: "/v1/social/{username}/next_address";
167
167
  readonly tag: "Social payments";
168
168
  readonly summary: "Reserve an address to pay a person";
169
- readonly description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`; paying yourself is refused.";
169
+ readonly description: "A fresh address of the recipient's, derived from their Oxy identity key. Limited per (sender, recipient) pair; a recipient without an identity answers 409 `keyless_recipient`, and one whose wallet watches no further address (every index below its watched bound is taken) 503 `faircoin_receive_tree_full`; paying yourself is refused.";
170
170
  readonly auth: "user";
171
171
  readonly params: {
172
172
  readonly username: "The recipient’s Oxy username.";
@@ -120,6 +120,7 @@ export declare const paymentIntentTestHelperRoutes: readonly [{
120
120
  message: z.ZodString;
121
121
  }, z.core.$strict>>;
122
122
  cancellation_reason: z.ZodNullable<z.ZodEnum<{
123
+ faircoin_network_closed: "faircoin_network_closed";
123
124
  duplicate: "duplicate";
124
125
  fraudulent: "fraudulent";
125
126
  abandoned: "abandoned";
@@ -109,6 +109,7 @@ export declare const ERROR_CODE_DESCRIPTIONS: {
109
109
  readonly faircoin_wallet_missing: "The Peable wallet that receives this payment (the merchant owner's, or the seller's) isn't set up yet, so it cannot be paid in FairCoin. The other payment methods still work.";
110
110
  readonly faircoin_network_closed: "FairCoin payments on this network are not open on this deployment yet. The other payment methods still work.";
111
111
  readonly faircoin_capacity_reached: "Too many FairCoin payments to this recipient are waiting to be paid right now, so no new FairCoin address can be handed out. The other payment methods still work; try FairCoin again shortly.";
112
+ readonly faircoin_receive_tree_full: "Every FairCoin address the recipient's Peable wallet watches has been handed out, so no new one can be derived for them. Nothing was reserved.";
112
113
  readonly faircoin_amount_too_small: "One seller's share of this order is below the smallest amount the FairCoin network relays, so it cannot be paid in FairCoin. The other payment methods still work.";
113
114
  readonly credit_note_exceeds_invoice: "The credit note's amount exceeds what the invoice can still credit.";
114
115
  readonly test_clock_unexpected_state: "The test clock is advancing; wait until it is ready.";
@@ -18,3 +18,4 @@ export * from './identity';
18
18
  export * from './merchants';
19
19
  export * from './paymentMethodConfigurations';
20
20
  export * from './realtime';
21
+ export * from './receiveTree';
@@ -20,14 +20,17 @@ export declare const PAYMENT_INTENT_MAX_EXPIRES_IN_SECONDS: number;
20
20
  export declare const PAYMENT_INTENT_STATUSES: readonly ["requires_payment_method", "requires_confirmation", "requires_action", "processing", "requires_capture", "succeeded", "canceled"];
21
21
  export type PaymentIntentStatus = (typeof PAYMENT_INTENT_STATUSES)[number];
22
22
  /**
23
- * Why an intent was cancelled — Stripe's reasons, plus two FairCoin-only ones:
24
- * `underpaid` (a transaction paid less than the amount) and
23
+ * Why an intent was cancelled — Stripe's reasons, plus three FairCoin-only ones:
24
+ * `underpaid` (a transaction paid less than the amount),
25
25
  * `recipient_key_changed` (the recipient's identity key was replaced after the
26
26
  * address was reserved, so the address is no longer in the wallet it pays —
27
27
  * ADR 0002, amended 2026-11-06; nothing had been broadcast, and the order stays
28
- * open for a fresh address).
28
+ * open for a fresh address) and `faircoin_network_closed` (the deployment
29
+ * closed the payment's FairCoin network — ADR 0002's gate — before anything was
30
+ * broadcast; the order stays open, and FairCoin on it says the network is
31
+ * closed).
29
32
  */
30
- export declare const PAYMENT_INTENT_CANCELLATION_REASONS: readonly ["abandoned", "automatic", "duplicate", "fraudulent", "recipient_key_changed", "requested_by_customer", "underpaid"];
33
+ export declare const PAYMENT_INTENT_CANCELLATION_REASONS: readonly ["abandoned", "automatic", "duplicate", "faircoin_network_closed", "fraudulent", "recipient_key_changed", "requested_by_customer", "underpaid"];
31
34
  export type PaymentIntentCancellationReason = (typeof PAYMENT_INTENT_CANCELLATION_REASONS)[number];
32
35
  /** The reasons a MERCHANT may give `POST /v1/payment_intents/:id/cancel`. */
33
36
  export declare const MERCHANT_CANCELLATION_REASONS: readonly ["abandoned", "duplicate", "fraudulent", "requested_by_customer"];
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The size of a recipient's FairCoin receive tree (ADR 0021 D9, amended
3
+ * 2026-11-06) — ONE answer, read by the gateway that hands out indices and by
4
+ * the Peable wallet that watches them.
5
+ *
6
+ * Every FairCoin address the gateway reserves for an account — a merchant
7
+ * payment, a marketplace seller's, an invoice's, `@username` — is index `i` of
8
+ * that account's identity tree (ADR 0002, ADR 0021 D5). The wallet watches a
9
+ * contiguous window, indices `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`, reaching
10
+ * {@link SOCIAL_RECEIVE_GAP_LIMIT} past the highest index reserved
11
+ * (`planSocialReceiveWindow` in `packages/frontend/src/wallet/social-receive.ts`),
12
+ * and stops offering `@username` once that reach would pass its bound. So an
13
+ * index is reserved only when the wallet, after reserving it, still reaches
14
+ * the gap above it inside its bound:
15
+ *
16
+ * index + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1
17
+ * index < SOCIAL_RECEIVE_INDEX_LIMIT
18
+ *
19
+ * The gateway refuses to mint `index >= SOCIAL_RECEIVE_INDEX_LIMIT` (in the
20
+ * reservation's own statement), so every address it hands out is inside the
21
+ * window the wallet watches. Zod-free and dependency-free: the wallet bundles
22
+ * this module alone (`@peable.to/contracts/vocabulary/receiveTree`).
23
+ */
24
+ /** The most indices the wallet watches: `0 .. SOCIAL_RECEIVE_MAX_WATCHED - 1`. */
25
+ export declare const SOCIAL_RECEIVE_MAX_WATCHED = 2000;
26
+ /**
27
+ * How many unused addresses the wallet watches beyond the highest index used
28
+ * or reserved — the FairCoin BIP44 external-chain gap limit.
29
+ */
30
+ export declare const SOCIAL_RECEIVE_GAP_LIMIT = 20;
31
+ /**
32
+ * The first index the gateway never mints (exclusive bound): `1 980`. Every
33
+ * minted index `i` satisfies `i < SOCIAL_RECEIVE_INDEX_LIMIT`, i.e.
34
+ * `i + SOCIAL_RECEIVE_GAP_LIMIT <= SOCIAL_RECEIVE_MAX_WATCHED - 1`.
35
+ */
36
+ export declare const SOCIAL_RECEIVE_INDEX_LIMIT: number;
37
+ /**
38
+ * How close to {@link SOCIAL_RECEIVE_INDEX_LIMIT} a tree is "nearly full":
39
+ * Orbit warns the owners once fewer fresh indices than this are left.
40
+ */
41
+ export declare const SOCIAL_RECEIVE_NEARLY_FULL_REMAINING = 200;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peable.to/contracts",
3
- "version": "5.5.0",
3
+ "version": "5.6.0",
4
4
  "description": "The Peable wire, declared once: Zod contracts of every public route, the OpenAPI 3.1 generator and the closed value sets (ADR 0014 D5).",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",