@percayso-community/cayso-contracts 0.29.0 → 1.0.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 +72 -28
- package/dist/assertion.d.ts +55 -2
- package/dist/assurance.js +37 -0
- package/dist/authority.d.ts +221 -0
- package/dist/authority.js +49 -0
- package/dist/client.d.ts +68 -6
- package/dist/client.js +35 -4
- package/dist/cloud-settlement.d.ts +339 -20
- package/dist/contract-schema.generated.js +1092 -38
- package/dist/errors.d.ts +67 -3
- package/dist/index.d.ts +129 -5
- package/dist/index.js +127 -4
- package/dist/operator.d.ts +142 -6
- package/dist/operator.js +8 -1
- package/dist/routes.d.ts +68 -3
- package/dist/routes.js +65 -3
- package/dist/schema-types.d.ts +15 -5
- package/dist/schema.d.ts +20 -8
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -24,6 +24,23 @@
|
|
|
24
24
|
* so each attempt gets a fresh one. That the retry re-fetches is a decision, not
|
|
25
25
|
* an accident.
|
|
26
26
|
*
|
|
27
|
+
* ## A second assertion, on the Organisation operations alone
|
|
28
|
+
*
|
|
29
|
+
* An act on an Organisation Wallet needs BizID's authority assertion beside Percayso
|
|
30
|
+
* ID's (CAY-0100 §4). The three methods that can be one take an optional
|
|
31
|
+
* {@link AuthorityAssertionProvider} as their last argument, and nothing else does.
|
|
32
|
+
* Its `getAuthorityAssertion()` is called under exactly the discipline above: inside
|
|
33
|
+
* each attempt, beside `getAssertion()`, never cached, and re-fetched on a retry,
|
|
34
|
+
* because the authority assertion is short-lived and single-use too. It travels in
|
|
35
|
+
* its own header, {@link AUTHORITY_ASSERTION_HEADER}, never in `Authorization`.
|
|
36
|
+
*
|
|
37
|
+
* It is per CALL rather than a client option, and that is the point. BizID mints an
|
|
38
|
+
* authority for one operation and one Organisation, and these methods name no
|
|
39
|
+
* Organisation, so only the caller knows which Organisation this act is for. A
|
|
40
|
+
* client-wide provider would have to guess, or would hand every Organisation
|
|
41
|
+
* operation the same authority. Passing none sends no header, and the request is
|
|
42
|
+
* exactly the request a `0.30.0` client sent.
|
|
43
|
+
*
|
|
27
44
|
* ## One method per route, no method that is not
|
|
28
45
|
*
|
|
29
46
|
* Every method reads its method and path from `ROUTES` — no URL is hand-written
|
|
@@ -69,7 +86,7 @@
|
|
|
69
86
|
*/
|
|
70
87
|
import type { BuyBackMade, BuyBackRequest, CitizenMarketViewed, QuotePlaced, QuoteRequest, QuoteWithdrawalRequest, QuoteWithdrawn } from './citizen-market.js';
|
|
71
88
|
import type { CitizenshipFounderClaimed, CitizenshipView } from './citizenship.js';
|
|
72
|
-
import type { StandingAuthorisationAcknowledged, StandingAuthorisationRequest } from './cloud-settlement.js';
|
|
89
|
+
import type { StandingAuthorisationAcknowledged, StandingAuthorisationRequest, StandingAuthorisationRevocationRequest, StandingAuthorisationRevoked, NodeBindingRequest, NodeBound } from './cloud-settlement.js';
|
|
73
90
|
import type { CitizenTransferMade, CitizenTransferRequest } from './citizen-transfer.js';
|
|
74
91
|
import type { CommercialPaymentMade, CommercialPaymentRequest } from './commercial-payment.js';
|
|
75
92
|
import type { HandleChangeCharged, HandleChangeReceiptReadResponse } from './handle-change.js';
|
|
@@ -107,6 +124,19 @@ export interface CaysoClientOptions {
|
|
|
107
124
|
*/
|
|
108
125
|
warn?: (message: string) => void;
|
|
109
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Where an Organisation operation gets BizID's authority assertion for this one act
|
|
129
|
+
* (CAY-0100 §4): the second credential, beside the one `getAssertion` supplies.
|
|
130
|
+
*
|
|
131
|
+
* Called before EVERY attempt, never once and never cached, for the reason
|
|
132
|
+
* `getAssertion` is: the credential is short-lived and single-use, so one minted for
|
|
133
|
+
* a first attempt must not be presented again by a retry. The value is the compact
|
|
134
|
+
* JWS BizID minted, sent in {@link AUTHORITY_ASSERTION_HEADER} exactly as returned.
|
|
135
|
+
*/
|
|
136
|
+
export interface AuthorityAssertionProvider {
|
|
137
|
+
/** Called before every attempt. Authority assertions are short-lived, so never cache one. */
|
|
138
|
+
getAuthorityAssertion(): Promise<string>;
|
|
139
|
+
}
|
|
110
140
|
/**
|
|
111
141
|
* One method per entry in `ROUTES`, and no method that is not. `getMyWallet`
|
|
112
142
|
* answers `null` where the contract says a wallet may not exist yet, rather than
|
|
@@ -166,8 +196,12 @@ export interface CaysoClient {
|
|
|
166
196
|
* carries no idempotency key and a repeat is the same act rather than a second
|
|
167
197
|
* one. A credential carrying no organisation authority is refused; absence
|
|
168
198
|
* provisions nothing.
|
|
199
|
+
*
|
|
200
|
+
* `authority` supplies BizID's authority assertion for `provision-organisation`
|
|
201
|
+
* (CAY-0100 §4). Optional, and sent only when given: no route reads it until the
|
|
202
|
+
* binding is served, and from then an Organisation operation without it is refused.
|
|
169
203
|
*/
|
|
170
|
-
provisionOrganisation(): Promise<OrganisationView>;
|
|
204
|
+
provisionOrganisation(authority?: AuthorityAssertionProvider): Promise<OrganisationView>;
|
|
171
205
|
/**
|
|
172
206
|
* Authorise a purchase — or REPLAY one (CAY-0032). Posting the same
|
|
173
207
|
* `idempotencyKey` twice returns the ORIGINAL authorisation, at the original
|
|
@@ -184,8 +218,12 @@ export interface CaysoClient {
|
|
|
184
218
|
* `'terminal'` means the key's purchase has finished and will not change: a
|
|
185
219
|
* repeat of it will keep answering `'terminal'` forever, and the remedy is a new
|
|
186
220
|
* purchase under a NEW key.
|
|
221
|
+
*
|
|
222
|
+
* `authority` supplies BizID's authority assertion for a purchase on behalf of an
|
|
223
|
+
* Organisation Wallet, when `onBehalfOfWalletId` names one (CAY-0100 §4a). A
|
|
224
|
+
* Citizen's own purchase needs none and passes none.
|
|
187
225
|
*/
|
|
188
|
-
authorisePurchase(req: PurchaseRequest): Promise<PurchaseAuthorised | PurchaseTerminal>;
|
|
226
|
+
authorisePurchase(req: PurchaseRequest, authority?: AuthorityAssertionProvider): Promise<PurchaseAuthorised | PurchaseTerminal>;
|
|
189
227
|
getPurchase(purchaseId: string): Promise<PurchaseResult>;
|
|
190
228
|
/**
|
|
191
229
|
* Cancel a purchase the caller started, releasing its reservation (CAY-0032).
|
|
@@ -213,8 +251,11 @@ export interface CaysoClient {
|
|
|
213
251
|
* thrown {@link CaysoApiError} whose `code` is a `CommercialPaymentRefusal`
|
|
214
252
|
* member, one of the gate's codes, or a seam code, as {@link authorisePurchase}'s
|
|
215
253
|
* refusals do. A refusal means nothing moved.
|
|
254
|
+
*
|
|
255
|
+
* `authority` supplies BizID's authority assertion on the `'mandate'` route
|
|
256
|
+
* (CAY-0100 §4a). The `'payment-allowance'` route needs none and passes none.
|
|
216
257
|
*/
|
|
217
|
-
makeCommercialPayment(req: CommercialPaymentRequest): Promise<CommercialPaymentMade>;
|
|
258
|
+
makeCommercialPayment(req: CommercialPaymentRequest, authority?: AuthorityAssertionProvider): Promise<CommercialPaymentMade>;
|
|
218
259
|
/**
|
|
219
260
|
* Transfer unrestricted cents from the caller's own Citizen Wallet to another
|
|
220
261
|
* Citizen Wallet — or REPLAY a transfer already made under the same key (CAY-0088).
|
|
@@ -304,10 +345,31 @@ export interface CaysoClient {
|
|
|
304
345
|
* Safe to repeat: the authorisation's `jti` is its own key, and presenting the same
|
|
305
346
|
* authorisation again binds nothing twice. A refusal arrives as a thrown
|
|
306
347
|
* {@link CaysoApiError} whose `code` is a `StandingAuthorisationRefusal` member, one
|
|
307
|
-
* of the gate's codes, or a seam code, and means nothing was bound.
|
|
308
|
-
*
|
|
348
|
+
* of the gate's codes, or a seam code, and means nothing was bound. Each
|
|
349
|
+
* presentation answers a freshly signed acknowledgement.
|
|
309
350
|
*/
|
|
310
351
|
presentStandingAuthorisation(req: StandingAuthorisationRequest): Promise<StandingAuthorisationAcknowledged>;
|
|
352
|
+
/**
|
|
353
|
+
* Revoke a standing authorisation the caller's wallet holds, named by its `jti`,
|
|
354
|
+
* under the owner's assertion (`revoke-standing-authorisation`, CAY-0094).
|
|
355
|
+
*
|
|
356
|
+
* Safe to repeat: revoking a revoked authorisation answers `revoked` again and
|
|
357
|
+
* writes nothing. A refusal arrives as a thrown {@link CaysoApiError} whose `code`
|
|
358
|
+
* is a `StandingAuthorisationRevocationRefusal` member, one of the gate's codes, or
|
|
359
|
+
* a seam code, and means nothing was written.
|
|
360
|
+
*/
|
|
361
|
+
revokeStandingAuthorisation(req: StandingAuthorisationRevocationRequest): Promise<StandingAuthorisationRevoked>;
|
|
362
|
+
/**
|
|
363
|
+
* Bind a Node to the wallet the presenting Instance key is already bound to, under
|
|
364
|
+
* the owner's assertion (`bind-node`, CAY-0095). The key must have been bound to the
|
|
365
|
+
* caller's wallet by a standing authorisation it presented; this binds no key.
|
|
366
|
+
*
|
|
367
|
+
* Safe to repeat: binding a bound Node to the same wallet answers `bound` again and
|
|
368
|
+
* writes nothing. A refusal arrives as a thrown {@link CaysoApiError} whose `code` is
|
|
369
|
+
* a `NodeBindingRefusal` member, one of the gate's codes, or a seam code, and means
|
|
370
|
+
* nothing was bound.
|
|
371
|
+
*/
|
|
372
|
+
bindNode(req: NodeBindingRequest): Promise<NodeBound>;
|
|
311
373
|
getVersion(): Promise<CaysoVersion>;
|
|
312
374
|
}
|
|
313
375
|
/**
|
package/dist/client.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { CONTRACT_VERSION, NOT_PROVISIONED } from './index.js';
|
|
16
|
+
import { AUTHORITY_ASSERTION_HEADER, CONTRACT_VERSION, NOT_PROVISIONED } from './index.js';
|
|
17
17
|
import { ROUTES } from './routes.js';
|
|
18
18
|
// --- The retry mechanism -----------------------------------------------------
|
|
19
19
|
// These are this slice's own mechanism, not economics: an attempt count, a
|
|
@@ -110,6 +110,16 @@ function buildClient(options, internals) {
|
|
|
110
110
|
if (spec.idempotencyKey !== undefined && spec.idempotencyKey.length > 0) {
|
|
111
111
|
headers['Idempotency-Key'] = spec.idempotencyKey;
|
|
112
112
|
}
|
|
113
|
+
// The second credential, under the first one's discipline: per attempt, never
|
|
114
|
+
// cached, and in a header of its own (CAY-0100 §4). Absent unless the caller
|
|
115
|
+
// passed a provider, so every other request is unchanged. An empty value is sent
|
|
116
|
+
// as no header, as an empty key is above, so the server reads it as missing
|
|
117
|
+
// rather than as present and malformed.
|
|
118
|
+
if (spec.authority !== undefined) {
|
|
119
|
+
const authority = await spec.authority.getAuthorityAssertion();
|
|
120
|
+
if (authority.length > 0)
|
|
121
|
+
headers[AUTHORITY_ASSERTION_HEADER] = authority;
|
|
122
|
+
}
|
|
113
123
|
const init = { method: spec.method, headers };
|
|
114
124
|
if (spec.body !== undefined)
|
|
115
125
|
init.body = JSON.stringify(spec.body);
|
|
@@ -190,7 +200,7 @@ function buildClient(options, internals) {
|
|
|
190
200
|
idempotent: true,
|
|
191
201
|
});
|
|
192
202
|
},
|
|
193
|
-
async provisionOrganisation() {
|
|
203
|
+
async provisionOrganisation(authority) {
|
|
194
204
|
return requestJson({
|
|
195
205
|
method: ROUTES.organisationProvision.method,
|
|
196
206
|
path: ROUTES.organisationProvision.path,
|
|
@@ -198,9 +208,10 @@ function buildClient(options, internals) {
|
|
|
198
208
|
// is: the operation is idempotent on the attested Organisation ID, so a
|
|
199
209
|
// repeat is the same act rather than a second one.
|
|
200
210
|
idempotent: true,
|
|
211
|
+
authority,
|
|
201
212
|
});
|
|
202
213
|
},
|
|
203
|
-
async authorisePurchase(req) {
|
|
214
|
+
async authorisePurchase(req, authority) {
|
|
204
215
|
return requestJson({
|
|
205
216
|
method: ROUTES.purchaseAuthorise.method,
|
|
206
217
|
path: ROUTES.purchaseAuthorise.path,
|
|
@@ -208,9 +219,10 @@ function buildClient(options, internals) {
|
|
|
208
219
|
idempotent: typeof req.idempotencyKey === 'string' && req.idempotencyKey.length > 0,
|
|
209
220
|
body: req,
|
|
210
221
|
idempotencyKey: req.idempotencyKey,
|
|
222
|
+
authority,
|
|
211
223
|
});
|
|
212
224
|
},
|
|
213
|
-
async makeCommercialPayment(req) {
|
|
225
|
+
async makeCommercialPayment(req, authority) {
|
|
214
226
|
return requestJson({
|
|
215
227
|
method: ROUTES.commercialPayment.method,
|
|
216
228
|
path: ROUTES.commercialPayment.path,
|
|
@@ -219,6 +231,7 @@ function buildClient(options, internals) {
|
|
|
219
231
|
idempotent: typeof req.idempotencyKey === 'string' && req.idempotencyKey.length > 0,
|
|
220
232
|
body: req,
|
|
221
233
|
idempotencyKey: req.idempotencyKey,
|
|
234
|
+
authority,
|
|
222
235
|
});
|
|
223
236
|
},
|
|
224
237
|
async makeCitizenTransfer(req) {
|
|
@@ -309,6 +322,24 @@ function buildClient(options, internals) {
|
|
|
309
322
|
body: req,
|
|
310
323
|
});
|
|
311
324
|
},
|
|
325
|
+
async revokeStandingAuthorisation(req) {
|
|
326
|
+
return requestJson({
|
|
327
|
+
method: ROUTES.revokeStandingAuthorisation.method,
|
|
328
|
+
path: ROUTES.revokeStandingAuthorisation.path,
|
|
329
|
+
// Safe to repeat: a revoked authorisation revoked again answers the same.
|
|
330
|
+
idempotent: true,
|
|
331
|
+
body: req,
|
|
332
|
+
});
|
|
333
|
+
},
|
|
334
|
+
async bindNode(req) {
|
|
335
|
+
return requestJson({
|
|
336
|
+
method: ROUTES.bindNode.method,
|
|
337
|
+
path: ROUTES.bindNode.path,
|
|
338
|
+
// Safe to repeat: the same Node bound to the same wallet answers the same.
|
|
339
|
+
idempotent: true,
|
|
340
|
+
body: req,
|
|
341
|
+
});
|
|
342
|
+
},
|
|
312
343
|
async getPurchase(purchaseId) {
|
|
313
344
|
return requestJson({
|
|
314
345
|
method: ROUTES.purchaseResult.method,
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
* assertion** the Contribution Store signs once per period and Cayso fails closed
|
|
5
5
|
* on (CMTY-0018, as Cayso amended it on 5 October 2026).
|
|
6
6
|
*
|
|
7
|
-
* **
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* **Both seams are served.** `present-standing-authorisation` binds an Instance key
|
|
8
|
+
* to the presenting holder's wallet and answers a signed acknowledgement, and
|
|
9
|
+
* `revoke-standing-authorisation` withdraws one (CAY-0094). `bind-node` binds a
|
|
10
|
+
* Node to the wallet its Instance key is already bound to, and the Store asks
|
|
11
|
+
* whether a Node is bound at {@link NODE_BINDING_QUERY_ROUTE} (CAY-0095). The Store
|
|
12
|
+
* presents each period's settlement assertion at {@link CLOUD_SETTLEMENT_ROUTE},
|
|
13
|
+
* and Cayso settles it whole, as one `contribution_settlement` movement per paid
|
|
14
|
+
* contribution row and one `consumption_settlement` movement per consumption row,
|
|
15
|
+
* or refuses it whole (CAY-0096). What is published is what the Cloud generates its
|
|
16
|
+
* own types from (CMTY-0018 §3), so that neither side redeclares the other's half.
|
|
12
17
|
*
|
|
13
18
|
* ## Two seams, two authorities
|
|
14
19
|
*
|
|
@@ -21,6 +26,10 @@
|
|
|
21
26
|
* Cayso issuer key, which the Instance hands to the Cloud. An Instance mediates and
|
|
22
27
|
* does not vouch (CAY-0057): the acknowledgement is how Cayso vouches for an
|
|
23
28
|
* Instance key the Cloud has never seen, without the Cloud learning whose it is.
|
|
29
|
+
* The owner withdraws it from the Instance the same way, under their money-grade
|
|
30
|
+
* assertion (`revoke-standing-authorisation`,
|
|
31
|
+
* `ROUTES.revokeStandingAuthorisation`); the Cloud learns of it when the last
|
|
32
|
+
* acknowledgement it holds expires, at the end of the next period.
|
|
24
33
|
*
|
|
25
34
|
* **The settlement assertion** is the Contribution Store's statement of one
|
|
26
35
|
* period: contribution by Node, consumption by authorisation. It is presented by
|
|
@@ -54,6 +63,24 @@
|
|
|
54
63
|
* package, not the record, is the shape the Cloud generates from (CAY-0026,
|
|
55
64
|
* Amendment 3).
|
|
56
65
|
*
|
|
66
|
+
* ## A Node is bound to the wallet its Instance key is bound to (CMTY-0018 §4)
|
|
67
|
+
*
|
|
68
|
+
* A Contributor's Node earns for its owner. The owner's Instance presents the Node
|
|
69
|
+
* under the owner's money-grade assertion (`bind-node`, `ROUTES.bindNode`), signed by
|
|
70
|
+
* the Instance key, and Cayso binds the Node to the wallet that key is already bound
|
|
71
|
+
* to — which must be the verified holder's own. Binding a Node binds no Instance key:
|
|
72
|
+
* a key is bound only by the first standing authorisation it presents (CAY-0094). A
|
|
73
|
+
* Node is bound once and never re-pointed, and there is no unbinding.
|
|
74
|
+
*
|
|
75
|
+
* A Core Node's owner is the Operator, so it is never bound to a Citizen Wallet
|
|
76
|
+
* (`core_node_not_bound`). Nothing in a Node ID says it is a Core Node; a deployment
|
|
77
|
+
* is told its Core Node IDs by configuration.
|
|
78
|
+
*
|
|
79
|
+
* The Store learns only whether a Node is bound ({@link NodeBindingStatus}), at
|
|
80
|
+
* {@link NODE_BINDING_QUERY_ROUTE}, authenticated by the registered Store issuer
|
|
81
|
+
* exactly as the settlement assertion is, and never by a person. The answer cannot
|
|
82
|
+
* name a wallet.
|
|
83
|
+
*
|
|
57
84
|
* ## Fail closed on the whole assertion
|
|
58
85
|
*
|
|
59
86
|
* A settlement assertion is settled whole or not at all (CAY-0021, CMTY-0018 §2).
|
|
@@ -68,6 +95,15 @@
|
|
|
68
95
|
* period's id and the idempotency key, and a replay answers what the first
|
|
69
96
|
* presentation answered.
|
|
70
97
|
*
|
|
98
|
+
* A **withheld** contribution row is carried and settles nothing: it writes no
|
|
99
|
+
* movement and does not refuse the period. How a later period pays what was withheld
|
|
100
|
+
* is open (CAY-0096 §5). A row of nought cents writes no movement either, though every
|
|
101
|
+
* check on it still runs. A **Core Node**'s qualified row of any amount but nought is
|
|
102
|
+
* refused with its own member, `contribution_node_is_a_core_node`: a Core Node's owner is
|
|
103
|
+
* the Operator, and where its contribution settles, if anywhere, is not designed
|
|
104
|
+
* (CAY-0096 §4). A Core Node row of nought cents is skipped and settles nothing, an
|
|
105
|
+
* interim rule pending that design (30 October 2026, cloud.platform#357).
|
|
106
|
+
*
|
|
71
107
|
* ## What is not here
|
|
72
108
|
*
|
|
73
109
|
* - **No Instance ID**, in any claim, row, request, answer or refusal (CAY-0059 §6).
|
|
@@ -79,14 +115,22 @@
|
|
|
79
115
|
* - **No figure.** The cap's ceiling, the authorisation's longest life, the
|
|
80
116
|
* period's length and rule, and every rate are canon figures read from one
|
|
81
117
|
* place. `period` is an opaque identifier; this package sets no value for it.
|
|
82
|
-
* - **No unconfigured adapter in
|
|
118
|
+
* - **No unconfigured adapter in any union.** A seam this deployment has not
|
|
83
119
|
* been told about — no Store issuer registered, no Cayso acknowledgement key, no
|
|
84
|
-
* ceiling configured — is a `503`
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
120
|
+
* ceiling configured — is a `503` with a `CaysoApiErrorCode` of its own, never a
|
|
121
|
+
* member here: `acknowledgement_signing_not_configured`,
|
|
122
|
+
* `standing_authorisation_cap_ceiling_not_configured`,
|
|
123
|
+
* `standing_authorisation_life_ceiling_not_configured` and
|
|
124
|
+
* `standing_authorisation_store_not_configured` for the standing authorisation;
|
|
125
|
+
* `node_binding_store_not_configured` and `core_node_ids_not_configured` for
|
|
126
|
+
* binding a Node; `node_binding_store_not_configured`,
|
|
127
|
+
* `core_node_ids_not_configured` and `contribution_store_issuer_not_configured`
|
|
128
|
+
* for the Store's read; and, for the settlement assertion,
|
|
129
|
+
* `cloud_settlement_store_not_configured` — no Treasury, so nowhere to settle —
|
|
130
|
+
* `core_node_ids_not_configured` and `contribution_store_issuer_not_configured`.
|
|
131
|
+
* - **No movement kind in this package's unions.** The two kinds a settlement
|
|
132
|
+
* writes are `MovementKind` members like every other (CAY-0096); what crosses
|
|
133
|
+
* here is only whether the period settled, and why it did not.
|
|
90
134
|
* - **No chain height.** A period is bounded in UTC seconds until there is a chain
|
|
91
135
|
* to read (CAY-0016); the height a Store read is a later version's member.
|
|
92
136
|
*/
|
|
@@ -189,6 +233,38 @@ export interface AuthorisationAcknowledgementClaims {
|
|
|
189
233
|
/** Expiry, in **seconds** since the Unix epoch. */
|
|
190
234
|
readonly exp: number;
|
|
191
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* The id of one Cayso acknowledgement key: the RFC 7638 SHA-256 thumbprint of its
|
|
238
|
+
* public half, unpadded base64url, and the `kid` in an acknowledgement's header.
|
|
239
|
+
* Derived rather than minted, so a key id cannot be re-pointed at a different key.
|
|
240
|
+
* Opaque to a consumer: compare it, never parse it.
|
|
241
|
+
*/
|
|
242
|
+
export type AcknowledgementKeyId = string;
|
|
243
|
+
/**
|
|
244
|
+
* The public half of one key Cayso signs an {@link AuthorisationAcknowledgementClaims}
|
|
245
|
+
* with: an Ed25519 public JSON Web Key (RFC 8037), and nothing private. Its `kid` is
|
|
246
|
+
* the thumbprint of `crv`, `kty` and `x`, so a verifier can check that the key it
|
|
247
|
+
* selected is the key the header named.
|
|
248
|
+
*/
|
|
249
|
+
export interface AcknowledgementPublicKey {
|
|
250
|
+
readonly kty: 'OKP';
|
|
251
|
+
readonly crv: 'Ed25519';
|
|
252
|
+
/** The public key, unpadded base64url. */
|
|
253
|
+
readonly x: string;
|
|
254
|
+
readonly kid: AcknowledgementKeyId;
|
|
255
|
+
readonly alg: 'EdDSA';
|
|
256
|
+
readonly use: 'sig';
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Every key a Cayso acknowledgement may be verified under, as a JSON Web Key Set
|
|
260
|
+
* (CAY-0093). A key is listed before it signs and stays listed after it stops
|
|
261
|
+
* signing, so a verifier selects by `kid` and never by position. Answered at
|
|
262
|
+
* `ACKNOWLEDGEMENT_KEYS_ROUTE`; a deployment holding no key answers
|
|
263
|
+
* `503 acknowledgement_signing_not_configured`, never an empty set.
|
|
264
|
+
*/
|
|
265
|
+
export interface AcknowledgementKeySet {
|
|
266
|
+
readonly keys: readonly AcknowledgementPublicKey[];
|
|
267
|
+
}
|
|
192
268
|
/** Cayso holds the authorisation, and here is its acknowledgement for the Cloud. */
|
|
193
269
|
export interface StandingAuthorisationAcknowledged {
|
|
194
270
|
readonly outcome: 'acknowledged';
|
|
@@ -255,6 +331,208 @@ export type StandingAuthorisationRefusal =
|
|
|
255
331
|
| 'cap_not_delegable'
|
|
256
332
|
/** The Instance key is already bound to a different wallet, and a key spends from one. */
|
|
257
333
|
| 'instance_key_bound_to_another_wallet';
|
|
334
|
+
/**
|
|
335
|
+
* The owner withdrawing a standing authorisation from their Instance, under the
|
|
336
|
+
* owner's assertion (`revoke-standing-authorisation`, CAY-0094). It names the
|
|
337
|
+
* authorisation by its `jti` and nothing else: whose wallet it is comes from the
|
|
338
|
+
* assertion, never from the request.
|
|
339
|
+
*/
|
|
340
|
+
export interface StandingAuthorisationRevocationRequest {
|
|
341
|
+
/** The revoked authorisation's `jti`. */
|
|
342
|
+
readonly authorisation: string;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* The authorisation is revoked: presented again, it is refused
|
|
346
|
+
* `authorisation_revoked`. Its Instance key stays bound to the wallet, so the key
|
|
347
|
+
* cannot be re-pointed at another. Revoking it again answers this again.
|
|
348
|
+
*/
|
|
349
|
+
export interface StandingAuthorisationRevoked {
|
|
350
|
+
readonly outcome: 'revoked';
|
|
351
|
+
/** The `jti` the request named, echoed so a caller can match the answer to its act. */
|
|
352
|
+
readonly authorisation: string;
|
|
353
|
+
}
|
|
354
|
+
/** The revocation was refused, with one member of the closed union. Nothing was written. */
|
|
355
|
+
export interface StandingAuthorisationRevocationRefused {
|
|
356
|
+
readonly outcome: 'refused';
|
|
357
|
+
readonly error: StandingAuthorisationRevocationRefusal;
|
|
358
|
+
}
|
|
359
|
+
/** The ONE declared answer to `revoke-standing-authorisation`, discriminated by `outcome`. */
|
|
360
|
+
export type StandingAuthorisationRevocationResponse = StandingAuthorisationRevoked | StandingAuthorisationRevocationRefused;
|
|
361
|
+
/**
|
|
362
|
+
* Why a revocation was refused. Closed, like {@link StandingAuthorisationRefusal}:
|
|
363
|
+
* a new reason is a new member and a contract version.
|
|
364
|
+
*/
|
|
365
|
+
export type StandingAuthorisationRevocationRefusal =
|
|
366
|
+
/**
|
|
367
|
+
* The verification method is outside the money-grade assurance profile
|
|
368
|
+
* (`ASSURANCE_POLICY['revoke-standing-authorisation']`). `dev-bypass` is never
|
|
369
|
+
* inside it.
|
|
370
|
+
*/
|
|
371
|
+
'assurance_not_money_grade'
|
|
372
|
+
/** No wallet is bound to the verified holder now, so there is nothing they hold to revoke. */
|
|
373
|
+
| 'wallet_has_no_live_binding'
|
|
374
|
+
/**
|
|
375
|
+
* No authorisation with this `jti` is held for the caller's wallet: it was never
|
|
376
|
+
* presented, or it was presented for another wallet. One member for both, so the
|
|
377
|
+
* route is no oracle for which `jti`s exist.
|
|
378
|
+
*/
|
|
379
|
+
| 'authorisation_not_held_by_this_wallet';
|
|
380
|
+
/**
|
|
381
|
+
* The Instance key's statement naming one Node (CMTY-0018 §4, CAY-0095): signed by
|
|
382
|
+
* the Instance key in CAY-0072's format, whose header `kid` is `iss`. It says only
|
|
383
|
+
* "this key presents this Node". Which wallet the Node is bound to is not a claim:
|
|
384
|
+
* it is the wallet that Instance key is already bound to, on Cayso's side, which is
|
|
385
|
+
* the verified holder's own.
|
|
386
|
+
*/
|
|
387
|
+
export interface NodePresentationClaims {
|
|
388
|
+
/** The Instance key that signed it. The same value as the header's `kid`. */
|
|
389
|
+
readonly iss: InstanceKeyId;
|
|
390
|
+
/** Exactly `'cayso'`, and checked, not merely present. */
|
|
391
|
+
readonly aud: 'cayso';
|
|
392
|
+
/** The Node being bound, as the Cloud's Node Registry holds it. */
|
|
393
|
+
readonly node_id: NodeId;
|
|
394
|
+
/** Issued-at, in **seconds** since the Unix epoch. */
|
|
395
|
+
readonly iat: number;
|
|
396
|
+
/** Expiry, in **seconds** since the Unix epoch. */
|
|
397
|
+
readonly exp: number;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* The Instance binding a Node to its owner's wallet, under the owner's assertion
|
|
401
|
+
* (`bind-node`, CAY-0095). The Instance key must already be bound to the verified
|
|
402
|
+
* holder's wallet, by a standing authorisation it presented (CAY-0094): binding a
|
|
403
|
+
* Node binds no key.
|
|
404
|
+
*/
|
|
405
|
+
export interface NodeBindingRequest {
|
|
406
|
+
/** The compact {@link NodePresentationClaims}, exactly as the Instance key signed it. */
|
|
407
|
+
readonly nodePresentation: string;
|
|
408
|
+
/**
|
|
409
|
+
* The Instance key's public half, as the JSON text of a public JSON Web Key. Its
|
|
410
|
+
* RFC 7638 thumbprint must be the presentation's `kid`, so the key that verifies
|
|
411
|
+
* the presentation is the key it names, and no other.
|
|
412
|
+
*/
|
|
413
|
+
readonly instanceKey: string;
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* The Node is bound to the verified holder's wallet. Answered for the presentation
|
|
417
|
+
* that bound it and for every repeat of the same binding, in the same shape: a
|
|
418
|
+
* repeat writes nothing. It names the Node and no wallet.
|
|
419
|
+
*/
|
|
420
|
+
export interface NodeBound {
|
|
421
|
+
readonly outcome: 'bound';
|
|
422
|
+
/** The Node the presentation named, echoed so a caller can match the answer to its act. */
|
|
423
|
+
readonly nodeId: NodeId;
|
|
424
|
+
}
|
|
425
|
+
/** The binding was refused, with one member of the closed union. Nothing was bound. */
|
|
426
|
+
export interface NodeBindingRefused {
|
|
427
|
+
readonly outcome: 'refused';
|
|
428
|
+
readonly error: NodeBindingRefusal;
|
|
429
|
+
}
|
|
430
|
+
/** The ONE declared answer to `bind-node`, discriminated by `outcome`. */
|
|
431
|
+
export type NodeBindingResponse = NodeBound | NodeBindingRefused;
|
|
432
|
+
/**
|
|
433
|
+
* Why a Node binding was refused. Closed, like {@link StandingAuthorisationRefusal}:
|
|
434
|
+
* a new reason is a new member and a contract version. Every member means the same
|
|
435
|
+
* thing: nothing was bound. There is no unbinding, so no member is about one.
|
|
436
|
+
*/
|
|
437
|
+
export type NodeBindingRefusal =
|
|
438
|
+
/**
|
|
439
|
+
* The verification method is outside the money-grade assurance profile
|
|
440
|
+
* (`ASSURANCE_POLICY['bind-node']`). `dev-bypass` is never inside it.
|
|
441
|
+
*/
|
|
442
|
+
'assurance_not_money_grade'
|
|
443
|
+
/**
|
|
444
|
+
* Not a compact assertion in CAY-0072's format, or its claims are not exactly the
|
|
445
|
+
* closed set of {@link NodePresentationClaims} with `aud` `'cayso'`.
|
|
446
|
+
*/
|
|
447
|
+
| 'node_presentation_malformed'
|
|
448
|
+
/** The Instance key presented is not a public JSON Web Key Cayso can verify with. */
|
|
449
|
+
| 'instance_key_malformed'
|
|
450
|
+
/**
|
|
451
|
+
* The presented key's thumbprint is not the presentation's `kid`, `iss` is not that
|
|
452
|
+
* `kid`, or the signature does not verify over the bytes presented. One member for
|
|
453
|
+
* all three: in each, the key presented did not sign this presentation.
|
|
454
|
+
*/
|
|
455
|
+
| 'node_presentation_not_signed_by_its_instance_key'
|
|
456
|
+
/** `exp` is at or before now, or `iat` is further ahead of now than the clock-skew tolerance. */
|
|
457
|
+
| 'node_presentation_not_current'
|
|
458
|
+
/**
|
|
459
|
+
* The Instance key is not bound to the verified holder's wallet: it was never
|
|
460
|
+
* bound, it is bound to another wallet, or the holder has no wallet now. One member
|
|
461
|
+
* for all three, so the route is no oracle for whose a key is.
|
|
462
|
+
*/
|
|
463
|
+
| 'instance_key_not_bound_to_holder'
|
|
464
|
+
/**
|
|
465
|
+
* The Node is a Core Node, which this deployment is told of by configuration. A
|
|
466
|
+
* Core Node's owner is the Operator (CMTY-0018 §4), so it is bound to no Citizen
|
|
467
|
+
* Wallet.
|
|
468
|
+
*/
|
|
469
|
+
| 'core_node_not_bound'
|
|
470
|
+
/** The Node is already bound to a different wallet. A binding is never re-pointed. */
|
|
471
|
+
| 'node_bound_to_another_wallet';
|
|
472
|
+
/**
|
|
473
|
+
* The Contribution Store's question about one Node (CAY-0095): signed by a key of
|
|
474
|
+
* the registered Store issuer, in CAY-0072's format, whose header `kid` names that
|
|
475
|
+
* key. It asks whether the Node is bound, and nothing about to whom.
|
|
476
|
+
*/
|
|
477
|
+
export interface NodeBindingQueryClaims {
|
|
478
|
+
readonly iss: ContributionStoreIssuer;
|
|
479
|
+
/** Exactly `'cayso'`. */
|
|
480
|
+
readonly aud: 'cayso';
|
|
481
|
+
/** The Node asked about. */
|
|
482
|
+
readonly node_id: NodeId;
|
|
483
|
+
/** Issued-at, in **seconds** since the Unix epoch. */
|
|
484
|
+
readonly iat: number;
|
|
485
|
+
/** Expiry, in **seconds** since the Unix epoch. */
|
|
486
|
+
readonly exp: number;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* The Contribution Store asking whether a Node is bound, under its own registered
|
|
490
|
+
* issuer and no person's assertion, at `NODE_BINDING_QUERY_ROUTE`.
|
|
491
|
+
*/
|
|
492
|
+
export interface NodeBindingQueryRequest {
|
|
493
|
+
/** The compact {@link NodeBindingQueryClaims}, exactly as the Store signed it. */
|
|
494
|
+
readonly nodeBindingQuery: string;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Cayso's answer: whether the Node is bound to a wallet, and **nothing else**. No
|
|
498
|
+
* wallet, no holder, no Citizen, no date, no Instance ID (CAY-0006, CAY-0059 §6). A
|
|
499
|
+
* Store that learns a Node is bound pays its rows; which wallet is paid is Cayso's
|
|
500
|
+
* to resolve at settlement, on its own side. A Node this deployment is told is a Core
|
|
501
|
+
* Node is answered `bound: false`, even if a Citizen bound it before it was named
|
|
502
|
+
* Core. Exactly two members, and the contract tests pin that no third can be added
|
|
503
|
+
* unnoticed.
|
|
504
|
+
*/
|
|
505
|
+
export interface NodeBindingStatus {
|
|
506
|
+
readonly nodeId: NodeId;
|
|
507
|
+
readonly bound: boolean;
|
|
508
|
+
}
|
|
509
|
+
/** The query was refused, with one member of the closed union. Nothing was read. */
|
|
510
|
+
export interface NodeBindingQueryRefused {
|
|
511
|
+
readonly outcome: 'refused';
|
|
512
|
+
readonly error: NodeBindingQueryRefusal;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Why the Store's query was refused. Closed. A query signed by anybody but the
|
|
516
|
+
* registered Store issuer, a person issuer included, is `node_binding_query_issuer_not_recognised`.
|
|
517
|
+
*/
|
|
518
|
+
export type NodeBindingQueryRefusal =
|
|
519
|
+
/**
|
|
520
|
+
* Not a compact assertion in CAY-0072's format, or its claims are not exactly the
|
|
521
|
+
* closed set of {@link NodeBindingQueryClaims} with `aud` `'cayso'`.
|
|
522
|
+
*/
|
|
523
|
+
'node_binding_query_malformed'
|
|
524
|
+
/**
|
|
525
|
+
* `iss` is not the Store issuer this deployment's registry holds, the issuer or the
|
|
526
|
+
* `kid` is revoked, or the `kid` is not one of its keys. A person issuer is never
|
|
527
|
+
* the Store issuer.
|
|
528
|
+
*/
|
|
529
|
+
| 'node_binding_query_issuer_not_recognised'
|
|
530
|
+
/** `iss` names the Contribution Store of another environment. */
|
|
531
|
+
| 'node_binding_query_issuer_for_another_environment'
|
|
532
|
+
/** The signature does not verify over the bytes presented. */
|
|
533
|
+
| 'node_binding_query_signature_invalid'
|
|
534
|
+
/** `exp` is at or before now, or `iat` is further ahead of now than the clock-skew tolerance. */
|
|
535
|
+
| 'node_binding_query_not_current';
|
|
258
536
|
/** The kind of contribution a row measures: the three of the Community map's #3. Closed. */
|
|
259
537
|
export type ContributionType = 'storage' | 'compute' | 'full-node';
|
|
260
538
|
/**
|
|
@@ -429,30 +707,71 @@ export type SettlementAssertionLevelRefusal =
|
|
|
429
707
|
| 'settlement_issued_in_the_future'
|
|
430
708
|
/** `jti` is not the period's id. */
|
|
431
709
|
| 'settlement_jti_not_the_period'
|
|
710
|
+
/**
|
|
711
|
+
* The period is not one this deployment's period rules made: its id is not the id a
|
|
712
|
+
* recognised rule gives the period containing `starts_at`, or its instants are not
|
|
713
|
+
* that period's. A deployment that recognises no rule refuses every period.
|
|
714
|
+
*/
|
|
715
|
+
| 'settlement_period_not_recognised'
|
|
716
|
+
/** The period's `ends_at` is still ahead of now, beyond the clock-skew tolerance. */
|
|
717
|
+
| 'settlement_period_not_ended'
|
|
432
718
|
/**
|
|
433
719
|
* A different assertion already settled this period. The two cannot both be the
|
|
434
720
|
* period, so the second is refused, and the first stands.
|
|
435
721
|
*/
|
|
436
722
|
| 'settlement_period_already_settled_differently'
|
|
437
723
|
/** A leg's rows do not add to its total. Refused before any row is read. */
|
|
438
|
-
| 'settlement_totals_do_not_add'
|
|
724
|
+
| 'settlement_totals_do_not_add'
|
|
725
|
+
/**
|
|
726
|
+
* Another movement kept changing a wallet the settlement draws from, and the carve
|
|
727
|
+
* gave up. Nothing was written; presenting the same assertion again is safe.
|
|
728
|
+
*/
|
|
729
|
+
| 'settlement_carve_contended';
|
|
439
730
|
/** Why the first failing contribution row failed. */
|
|
440
731
|
export type ContributionRowRefusal =
|
|
441
732
|
/**
|
|
442
|
-
* A qualified row names a Node bound to no wallet
|
|
443
|
-
* carried withheld (`node_not_bound`) and
|
|
733
|
+
* A qualified row names a Node bound to no wallet, or to a wallet that no longer
|
|
734
|
+
* has a holder. An unbound Node's row is carried withheld (`node_not_bound`) and
|
|
735
|
+
* never settled to anybody.
|
|
736
|
+
*/
|
|
737
|
+
'contribution_node_not_bound'
|
|
738
|
+
/**
|
|
739
|
+
* A qualified row of more than nought cents names a Node this deployment is told is a
|
|
740
|
+
* Core Node. A Core Node's owner is the Operator (CMTY-0018 §4), so it settles to no
|
|
741
|
+
* Citizen Wallet. A nought row for a Core Node is skipped instead (interim, #357).
|
|
444
742
|
*/
|
|
445
|
-
'
|
|
743
|
+
| 'contribution_node_is_a_core_node'
|
|
744
|
+
/** The Treasury holds too few unrestricted cents to pay this row. */
|
|
745
|
+
| 'contribution_treasury_short';
|
|
446
746
|
/** Why the first failing consumption row failed. */
|
|
447
747
|
export type ConsumptionRowRefusal =
|
|
448
748
|
/** The row cites an authorisation Cayso never acknowledged. */
|
|
449
749
|
'consumption_authorisation_unknown'
|
|
450
|
-
/**
|
|
750
|
+
/**
|
|
751
|
+
* The row cites an authorisation its owner revoked before the period: no
|
|
752
|
+
* acknowledgement Cayso signed before the revocation covers any of it.
|
|
753
|
+
*/
|
|
451
754
|
| 'consumption_authorisation_revoked'
|
|
452
|
-
/**
|
|
755
|
+
/**
|
|
756
|
+
* The row cites an authorisation that was not in force in the period: issued after
|
|
757
|
+
* the period ended, or expired at or before it began.
|
|
758
|
+
*/
|
|
759
|
+
| 'consumption_authorisation_not_in_force'
|
|
760
|
+
/**
|
|
761
|
+
* The row's cap is not the cap the acknowledgement stated, or the authorisation's
|
|
762
|
+
* period rule is not the rule that made this period.
|
|
763
|
+
*/
|
|
453
764
|
| 'consumption_cap_not_the_acknowledged_cap'
|
|
454
|
-
/**
|
|
455
|
-
|
|
765
|
+
/**
|
|
766
|
+
* The authorisation's running total in this period passes its cap at this row. The
|
|
767
|
+
* Store clamps at the cap, so this is a Store defect, and it is never softened.
|
|
768
|
+
*/
|
|
769
|
+
| 'consumption_over_cap'
|
|
770
|
+
/**
|
|
771
|
+
* The paying wallet holds too few unrestricted cents for this row. Restricted cents
|
|
772
|
+
* never pay a consumption settlement (CAY-0096 §2).
|
|
773
|
+
*/
|
|
774
|
+
| 'consumption_wallet_short';
|
|
456
775
|
/**
|
|
457
776
|
* Every reason a settlement assertion can be refused: the assertion's own, and each
|
|
458
777
|
* leg's. Closed, so a consumer's map over it is total.
|