@obbyx/obyte 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"exact-unit.d.ts","sourceRoot":"","sources":["../../src/unit/exact-unit.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,OAAO,EAA8C,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,KAAK,aAAa,EAAoC,MAAM,8BAA8B,CAAC;AAEpG;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;CAehB,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB;;;CAA+C,CAAC;AAGhF,eAAO,MAAM,sBAAsB,QAAY,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7E,iFAAiF;IACjF,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CACxC;AA6BD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,aAAa,CAAA;CAAO,GACjD,OAAO,CAAC,cAAc,CAAC,CAiOzB;AAKD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAKtF;AAED,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACtC,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC,MAAM,CAGR"}
1
+ {"version":3,"file":"exact-unit.d.ts","sourceRoot":"","sources":["../../src/unit/exact-unit.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,OAAO,EAA8C,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,KAAK,aAAa,EAAoC,MAAM,8BAA8B,CAAC;AAEpG;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;CAehB,CAAC;AAEX,+CAA+C;AAC/C,eAAO,MAAM,mBAAmB;;;CAA+C,CAAC;AAGhF,eAAO,MAAM,sBAAsB,QAAY,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7E,iFAAiF;IACjF,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CACxC;AA6BD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IAAE,gBAAgB,CAAC,EAAE,aAAa,CAAA;CAAO,GACjD,OAAO,CAAC,cAAc,CAAC,CAoCzB;AA+PD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAKtF;AAED,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACtC,CAAC,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC,MAAM,CAGR"}
@@ -65,9 +65,49 @@ const isHash = (v) => typeof v === 'string' && HASH_RE.test(v);
65
65
  const isIndex = (v) => Number.isSafeInteger(v) && v >= 0;
66
66
  const isPositiveAmount = (v) => Number.isSafeInteger(v) && v > 0;
67
67
  export function validateExactUnit(unit, expect, options = {}) {
68
- const R = EXACT_REASONS;
69
- const unsupported = (why) => reject(R.unsupported, why);
70
- // --- structure & size ---------------------------------------------------
68
+ // The order of the checks is part of the contract: the first failing one
69
+ // decides the reason code.
70
+ const shaped = checkShape(unit, expect);
71
+ if (!shaped.ok)
72
+ return shaped;
73
+ const u = shaped.value;
74
+ const hashed = checkUnitHash(u);
75
+ if (!hashed.ok)
76
+ return hashed;
77
+ const { unitHash, messages, authors } = hashed.value;
78
+ const author = checkAuthor(u, authors, options.authorDefinition);
79
+ if (!author.ok)
80
+ return author;
81
+ const { payer, definitionFromLedger } = author.value;
82
+ const roles = checkPayer(payer, expect);
83
+ if (!roles.ok)
84
+ return roles;
85
+ const payments = checkMessages(messages, expect);
86
+ if (!payments.ok)
87
+ return payments;
88
+ const transfers = checkTransfers(payments.value, payer, expect);
89
+ if (!transfers.ok)
90
+ return transfers;
91
+ const commissions = expectedCommissions(u);
92
+ if (commissions.headers !== u['headers_commission'] ||
93
+ commissions.payload !== u['payload_commission']) {
94
+ return reject(EXACT_REASONS.commissions, 'Commissions do not match the unit size');
95
+ }
96
+ return accept({
97
+ unitHash,
98
+ payer,
99
+ inputs: transfers.value.inputs,
100
+ lastBallUnit: u['last_ball_unit'],
101
+ parentUnits: u['parent_units'],
102
+ timestamp: u['timestamp'],
103
+ outputTotals: transfers.value.outputTotals,
104
+ commissions,
105
+ definitionFromLedger,
106
+ });
107
+ }
108
+ const unsupported = (why) => reject(EXACT_REASONS.unsupported, why);
109
+ /** Structure, size, network and header fields. */
110
+ function checkShape(unit, expect) {
71
111
  if (!isPlainObject(unit))
72
112
  return unsupported('Unit must be an object');
73
113
  let serialized;
@@ -78,16 +118,14 @@ export function validateExactUnit(unit, expect, options = {}) {
78
118
  return unsupported('Unit is not serializable');
79
119
  }
80
120
  if (serialized.length > (expect.maxUnitBytes ?? DEFAULT_MAX_UNIT_BYTES)) {
81
- return reject(R.tooLarge, 'Unit exceeds the size limit');
121
+ return reject(EXACT_REASONS.tooLarge, 'Unit exceeds the size limit');
82
122
  }
83
123
  if (!hasOnlyKeys(unit, UNIT_KEYS))
84
124
  return unsupported('Unit has fields outside the profile');
85
- // --- network --------------------------------------------------------------
86
125
  const net = expect.network.name;
87
126
  if (unit['version'] !== EXACT_UNIT_VERSIONS[net] || unit['alt'] !== ALT[net]) {
88
- return reject(R.network, `Unit version/alt do not match ${expect.network.caip2}`);
127
+ return reject(EXACT_REASONS.network, `Unit version/alt do not match ${expect.network.caip2}`);
89
128
  }
90
- // --- headers --------------------------------------------------------------
91
129
  const parents = unit['parent_units'];
92
130
  if (!Array.isArray(parents) || parents.length === 0 || !parents.every(isHash)) {
93
131
  return unsupported('Invalid parent_units');
@@ -106,9 +144,12 @@ export function validateExactUnit(unit, expect, options = {}) {
106
144
  if (fee in unit && !isIndex(unit[fee]))
107
145
  return unsupported(`Invalid ${fee}`);
108
146
  }
109
- // --- unit hash --------------------------------------------------------------
147
+ return accept(unit);
148
+ }
149
+ /** The unit hash is present and matches the content. */
150
+ function checkUnitHash(unit) {
110
151
  if (!isHash(unit['unit']))
111
- return reject(R.unitHash, 'Missing unit hash');
152
+ return reject(EXACT_REASONS.unitHash, 'Missing unit hash');
112
153
  const messages = unit['messages'];
113
154
  const authors = unit['authors'];
114
155
  if (!Array.isArray(messages) || !Array.isArray(authors))
@@ -118,37 +159,33 @@ export function validateExactUnit(unit, expect, options = {}) {
118
159
  unitHash = getUnitHash(unit);
119
160
  }
120
161
  catch {
121
- return reject(R.unitHash, 'Unit cannot be hashed');
162
+ return reject(EXACT_REASONS.unitHash, 'Unit cannot be hashed');
163
+ }
164
+ if (unitHash !== unit['unit']) {
165
+ return reject(EXACT_REASONS.unitHash, 'Unit hash does not match content');
122
166
  }
123
- if (unitHash !== unit['unit'])
124
- return reject(R.unitHash, 'Unit hash does not match content');
125
- // --- author, definition, signature -----------------------------------------
167
+ return accept({ unitHash, messages, authors });
168
+ }
169
+ /** One author with a single-sig definition (embedded or from the ledger) and a valid signature. */
170
+ function checkAuthor(unit, authors, ledgerDefinition) {
171
+ const R = EXACT_REASONS;
126
172
  if (authors.length !== 1)
127
173
  return unsupported('Exactly one author is supported');
128
174
  const author = authors[0];
129
- if (!isPlainObject(author) || !hasOnlyKeys(author, AUTHOR_KEYS))
175
+ if (!isPlainObject(author) || !hasOnlyKeys(author, AUTHOR_KEYS)) {
130
176
  return unsupported('Malformed author');
177
+ }
131
178
  const payer = author['address'];
132
179
  if (!isAddress(payer))
133
180
  return unsupported('Invalid author address');
134
- let definition;
135
- let definitionFromLedger = false;
136
- if ('definition' in author) {
137
- if (!isSigDefinition(author['definition'])) {
138
- return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
139
- }
140
- definition = author['definition'];
141
- }
142
- else if (options.authorDefinition !== undefined) {
143
- if (!isSigDefinition(options.authorDefinition)) {
144
- return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
145
- }
146
- definition = options.authorDefinition;
147
- definitionFromLedger = true;
148
- }
149
- else {
181
+ const embedded = 'definition' in author;
182
+ const definition = embedded ? author['definition'] : ledgerDefinition;
183
+ if (definition === undefined) {
150
184
  return reject(R.definitionRequired, 'Author definition is not embedded; fetch it from the ledger');
151
185
  }
186
+ if (!isSigDefinition(definition)) {
187
+ return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
188
+ }
152
189
  if (obyte.utils.getChash160([...definition]) !== payer) {
153
190
  return reject(R.definition, 'Definition does not match the author address');
154
191
  }
@@ -159,13 +196,23 @@ export function validateExactUnit(unit, expect, options = {}) {
159
196
  if (!verifySignature(getUnitHashToSign(unit), authentifiers['r'], definition[1].pubkey)) {
160
197
  return reject(R.signature, 'Signature is invalid');
161
198
  }
162
- // --- payer / recipient sanity -------------------------------------------------
199
+ return accept({ payer, definitionFromLedger: !embedded });
200
+ }
201
+ /** The payer is neither the recipient nor the facilitator. */
202
+ function checkPayer(payer, expect) {
163
203
  if (payer === expect.payTo)
164
- return reject(R.payer, 'Payer and payTo must differ');
204
+ return reject(EXACT_REASONS.payer, 'Payer and payTo must differ');
165
205
  if (expect.facilitatorAddresses?.includes(payer)) {
166
- return reject(R.payer, 'A facilitator address must never be the payer');
206
+ return reject(EXACT_REASONS.payer, 'A facilitator address must never be the payer');
167
207
  }
168
- // --- messages -----------------------------------------------------------------
208
+ return accept(null);
209
+ }
210
+ /**
211
+ * Inline messages with matching hashes: exactly one data message carrying the
212
+ * binding, one payment per asset, bytes always and only the expected asset besides.
213
+ */
214
+ function checkMessages(messages, expect) {
215
+ const R = EXACT_REASONS;
169
216
  let dataCount = 0;
170
217
  const payments = new Map();
171
218
  for (const message of messages) {
@@ -186,34 +233,49 @@ export function validateExactUnit(unit, expect, options = {}) {
186
233
  return binding;
187
234
  }
188
235
  else if (message['app'] === 'payment') {
189
- if (!isPlainObject(payload) || !hasOnlyKeys(payload, PAYMENT_KEYS)) {
190
- return unsupported('Malformed payment');
191
- }
192
- const asset = 'asset' in payload ? payload['asset'] : 'base';
193
- if (asset === 'base' && 'asset' in payload)
194
- return unsupported('Bytes payment must omit asset');
195
- if (!isAssetId(asset))
196
- return unsupported('Invalid payment asset');
197
- if (payments.has(asset))
236
+ const asset = paymentAsset(payload);
237
+ if (!asset.ok)
238
+ return asset;
239
+ if (payments.has(asset.value))
198
240
  return unsupported('One payment message per asset');
199
- payments.set(asset, payload);
241
+ payments.set(asset.value, payload);
200
242
  }
201
243
  else {
202
244
  return unsupported('Only payment and data messages are supported');
203
245
  }
204
246
  }
205
- if (dataCount !== 1)
247
+ if (dataCount !== 1) {
206
248
  return reject(R.binding, 'Exactly one data message with the binding is required');
249
+ }
207
250
  if (!payments.has('base'))
208
251
  return unsupported('A bytes payment message is required');
209
- const allowedAssets = new Set(['base', expect.asset]);
210
252
  for (const asset of payments.keys()) {
211
- if (!allowedAssets.has(asset))
253
+ if (asset !== 'base' && asset !== expect.asset) {
212
254
  return reject(R.asset, 'Payment in an unexpected asset');
255
+ }
213
256
  }
214
257
  if (!payments.has(expect.asset))
215
258
  return reject(R.asset, 'No payment in the required asset');
216
- // --- inputs & outputs -----------------------------------------------------------
259
+ return accept(payments);
260
+ }
261
+ /** The asset of a payment message ('base' when omitted). */
262
+ function paymentAsset(payload) {
263
+ if (!isPlainObject(payload) || !hasOnlyKeys(payload, PAYMENT_KEYS)) {
264
+ return unsupported('Malformed payment');
265
+ }
266
+ const asset = 'asset' in payload ? payload['asset'] : 'base';
267
+ if (asset === 'base' && 'asset' in payload)
268
+ return unsupported('Bytes payment must omit asset');
269
+ if (!isAssetId(asset))
270
+ return unsupported('Invalid payment asset');
271
+ return accept(asset);
272
+ }
273
+ /**
274
+ * Transfer inputs only (no duplicates); sorted outputs that go to payTo
275
+ * (exactly once, the exact amount, the expected asset) or back to the payer.
276
+ */
277
+ function checkTransfers(payments, payer, expect) {
278
+ const R = EXACT_REASONS;
217
279
  const inputs = [];
218
280
  const seenInputs = new Set();
219
281
  const outputTotals = {};
@@ -226,23 +288,14 @@ export function validateExactUnit(unit, expect, options = {}) {
226
288
  return unsupported('Payment needs inputs and outputs');
227
289
  }
228
290
  for (const input of ins) {
229
- if (!isPlainObject(input) ||
230
- !hasOnlyKeys(input, INPUT_KEYS) ||
231
- !isHash(input['unit']) ||
232
- !isIndex(input['message_index']) ||
233
- !isIndex(input['output_index'])) {
291
+ const ref = transferInput(input, asset);
292
+ if (ref === undefined)
234
293
  return unsupported('Only transfer inputs are supported');
235
- }
236
- const key = `${input['unit']}:${input['message_index']}:${input['output_index']}`;
294
+ const key = `${ref.unit}:${ref.messageIndex}:${ref.outputIndex}`;
237
295
  if (seenInputs.has(key))
238
296
  return unsupported('Duplicate input');
239
297
  seenInputs.add(key);
240
- inputs.push({
241
- asset,
242
- unit: input['unit'],
243
- messageIndex: input['message_index'],
244
- outputIndex: input['output_index'],
245
- });
298
+ inputs.push(ref);
246
299
  }
247
300
  let total = 0n;
248
301
  let previous;
@@ -260,15 +313,14 @@ export function validateExactUnit(unit, expect, options = {}) {
260
313
  return unsupported('Outputs must be sorted by address and amount without duplicates');
261
314
  }
262
315
  previous = current;
263
- const amount = BigInt(output['amount']);
264
- total += amount;
265
- if (output['address'] === expect.payTo) {
316
+ total += BigInt(current.amount);
317
+ if (current.address === expect.payTo) {
266
318
  if (asset !== expect.asset)
267
319
  return reject(R.recipient, 'payTo receives an unexpected asset');
268
320
  outputsToPayTo += 1;
269
- paidToPayTo += amount;
321
+ paidToPayTo += BigInt(current.amount);
270
322
  }
271
- else if (output['address'] !== payer) {
323
+ else if (current.address !== payer) {
272
324
  return reject(R.recipient, 'Outputs may only go to payTo or back to the payer');
273
325
  }
274
326
  }
@@ -278,23 +330,23 @@ export function validateExactUnit(unit, expect, options = {}) {
278
330
  return reject(R.recipient, 'Exactly one output to payTo is required');
279
331
  if (paidToPayTo !== expect.amount)
280
332
  return reject(R.amount, 'Amount paid to payTo does not match');
281
- // --- commissions ------------------------------------------------------------------
282
- const commissions = expectedCommissions(unit);
283
- if (commissions.headers !== unit['headers_commission'] ||
284
- commissions.payload !== unit['payload_commission']) {
285
- return reject(R.commissions, 'Commissions do not match the unit size');
333
+ return accept({ inputs, outputTotals });
334
+ }
335
+ /** A transfer input (unit, message_index, output_index), or undefined for anything else. */
336
+ function transferInput(input, asset) {
337
+ if (!isPlainObject(input) ||
338
+ !hasOnlyKeys(input, INPUT_KEYS) ||
339
+ !isHash(input['unit']) ||
340
+ !isIndex(input['message_index']) ||
341
+ !isIndex(input['output_index'])) {
342
+ return undefined;
286
343
  }
287
- return accept({
288
- unitHash,
289
- payer,
290
- inputs,
291
- lastBallUnit: unit['last_ball_unit'],
292
- parentUnits: parents,
293
- timestamp: unit['timestamp'],
294
- outputTotals,
295
- commissions,
296
- definitionFromLedger,
297
- });
344
+ return {
345
+ asset,
346
+ unit: input['unit'],
347
+ messageIndex: input['message_index'],
348
+ outputIndex: input['output_index'],
349
+ };
298
350
  }
299
351
  /** Length of one base64 secp256k1 signature, as counted by obyte.js. */
300
352
  const SIGNATURE_SIZE = 88;
@@ -317,6 +369,7 @@ export function compareOutputs(a, b) {
317
369
  return a.address < b.address ? -1 : 1;
318
370
  return a.amount - b.amount;
319
371
  }
372
+ /** The data message is exactly `{x402: {binding, quoteId}}` of this operation (undefined when it is). */
320
373
  function checkBinding(payload, expect) {
321
374
  const R = EXACT_REASONS;
322
375
  if (!isPlainObject(payload) || !hasOnlyKeys(payload, new Set(['x402']))) {
@@ -1 +1 @@
1
- {"version":3,"file":"exact-unit.js","sourceRoot":"","sources":["../../src/unit/exact-unit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exact-unit.js","sourceRoot":"","sources":["../../src/unit/exact-unit.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@obbyx/obyte",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Obyte primitives for x402: networks (CAIP-2), BigInt amounts, unit and signed-message validation, wallet, logging",
5
5
  "keywords": [
6
6
  "obyte",
@@ -117,10 +117,47 @@ export function validateExactUnit(
117
117
  expect: ExactExpectation,
118
118
  options: { authorDefinition?: SigDefinition } = {},
119
119
  ): Verdict<ExactUnitFacts> {
120
- const R = EXACT_REASONS;
121
- const unsupported = (why: string) => reject<ExactUnitFacts>(R.unsupported, why);
120
+ // The order of the checks is part of the contract: the first failing one
121
+ // decides the reason code.
122
+ const shaped = checkShape(unit, expect);
123
+ if (!shaped.ok) return shaped;
124
+ const u = shaped.value;
125
+ const hashed = checkUnitHash(u);
126
+ if (!hashed.ok) return hashed;
127
+ const { unitHash, messages, authors } = hashed.value;
128
+ const author = checkAuthor(u, authors, options.authorDefinition);
129
+ if (!author.ok) return author;
130
+ const { payer, definitionFromLedger } = author.value;
131
+ const roles = checkPayer(payer, expect);
132
+ if (!roles.ok) return roles;
133
+ const payments = checkMessages(messages, expect);
134
+ if (!payments.ok) return payments;
135
+ const transfers = checkTransfers(payments.value, payer, expect);
136
+ if (!transfers.ok) return transfers;
137
+ const commissions = expectedCommissions(u);
138
+ if (
139
+ commissions.headers !== u['headers_commission'] ||
140
+ commissions.payload !== u['payload_commission']
141
+ ) {
142
+ return reject(EXACT_REASONS.commissions, 'Commissions do not match the unit size');
143
+ }
144
+ return accept({
145
+ unitHash,
146
+ payer,
147
+ inputs: transfers.value.inputs,
148
+ lastBallUnit: u['last_ball_unit'] as string,
149
+ parentUnits: u['parent_units'] as string[],
150
+ timestamp: u['timestamp'] as number,
151
+ outputTotals: transfers.value.outputTotals,
152
+ commissions,
153
+ definitionFromLedger,
154
+ });
155
+ }
156
+
157
+ const unsupported = (why: string) => reject<never>(EXACT_REASONS.unsupported, why);
122
158
 
123
- // --- structure & size ---------------------------------------------------
159
+ /** Structure, size, network and header fields. */
160
+ function checkShape(unit: unknown, expect: ExactExpectation): Verdict<Record<string, unknown>> {
124
161
  if (!isPlainObject(unit)) return unsupported('Unit must be an object');
125
162
  let serialized: string;
126
163
  try {
@@ -129,17 +166,15 @@ export function validateExactUnit(
129
166
  return unsupported('Unit is not serializable');
130
167
  }
131
168
  if (serialized.length > (expect.maxUnitBytes ?? DEFAULT_MAX_UNIT_BYTES)) {
132
- return reject(R.tooLarge, 'Unit exceeds the size limit');
169
+ return reject(EXACT_REASONS.tooLarge, 'Unit exceeds the size limit');
133
170
  }
134
171
  if (!hasOnlyKeys(unit, UNIT_KEYS)) return unsupported('Unit has fields outside the profile');
135
172
 
136
- // --- network --------------------------------------------------------------
137
173
  const net = expect.network.name;
138
174
  if (unit['version'] !== EXACT_UNIT_VERSIONS[net] || unit['alt'] !== ALT[net]) {
139
- return reject(R.network, `Unit version/alt do not match ${expect.network.caip2}`);
175
+ return reject(EXACT_REASONS.network, `Unit version/alt do not match ${expect.network.caip2}`);
140
176
  }
141
177
 
142
- // --- headers --------------------------------------------------------------
143
178
  const parents = unit['parent_units'];
144
179
  if (!Array.isArray(parents) || parents.length === 0 || !parents.every(isHash)) {
145
180
  return unsupported('Invalid parent_units');
@@ -156,9 +191,14 @@ export function validateExactUnit(
156
191
  for (const fee of ['tps_fee', 'burn_fee', 'max_aa_responses'] as const) {
157
192
  if (fee in unit && !isIndex(unit[fee])) return unsupported(`Invalid ${fee}`);
158
193
  }
194
+ return accept(unit);
195
+ }
159
196
 
160
- // --- unit hash --------------------------------------------------------------
161
- if (!isHash(unit['unit'])) return reject(R.unitHash, 'Missing unit hash');
197
+ /** The unit hash is present and matches the content. */
198
+ function checkUnitHash(
199
+ unit: Record<string, unknown>,
200
+ ): Verdict<{ unitHash: string; messages: unknown[]; authors: unknown[] }> {
201
+ if (!isHash(unit['unit'])) return reject(EXACT_REASONS.unitHash, 'Missing unit hash');
162
202
  const messages = unit['messages'];
163
203
  const authors = unit['authors'];
164
204
  if (!Array.isArray(messages) || !Array.isArray(authors)) return unsupported('Malformed unit');
@@ -166,37 +206,40 @@ export function validateExactUnit(
166
206
  try {
167
207
  unitHash = getUnitHash(unit);
168
208
  } catch {
169
- return reject(R.unitHash, 'Unit cannot be hashed');
209
+ return reject(EXACT_REASONS.unitHash, 'Unit cannot be hashed');
170
210
  }
171
- if (unitHash !== unit['unit']) return reject(R.unitHash, 'Unit hash does not match content');
211
+ if (unitHash !== unit['unit']) {
212
+ return reject(EXACT_REASONS.unitHash, 'Unit hash does not match content');
213
+ }
214
+ return accept({ unitHash, messages, authors });
215
+ }
172
216
 
173
- // --- author, definition, signature -----------------------------------------
217
+ /** One author with a single-sig definition (embedded or from the ledger) and a valid signature. */
218
+ function checkAuthor(
219
+ unit: Record<string, unknown>,
220
+ authors: unknown[],
221
+ ledgerDefinition: SigDefinition | undefined,
222
+ ): Verdict<{ payer: string; definitionFromLedger: boolean }> {
223
+ const R = EXACT_REASONS;
174
224
  if (authors.length !== 1) return unsupported('Exactly one author is supported');
175
225
  const author: unknown = authors[0];
176
- if (!isPlainObject(author) || !hasOnlyKeys(author, AUTHOR_KEYS))
226
+ if (!isPlainObject(author) || !hasOnlyKeys(author, AUTHOR_KEYS)) {
177
227
  return unsupported('Malformed author');
228
+ }
178
229
  const payer = author['address'];
179
230
  if (!isAddress(payer)) return unsupported('Invalid author address');
180
231
 
181
- let definition: SigDefinition;
182
- let definitionFromLedger = false;
183
- if ('definition' in author) {
184
- if (!isSigDefinition(author['definition'])) {
185
- return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
186
- }
187
- definition = author['definition'];
188
- } else if (options.authorDefinition !== undefined) {
189
- if (!isSigDefinition(options.authorDefinition)) {
190
- return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
191
- }
192
- definition = options.authorDefinition;
193
- definitionFromLedger = true;
194
- } else {
232
+ const embedded = 'definition' in author;
233
+ const definition: unknown = embedded ? author['definition'] : ledgerDefinition;
234
+ if (definition === undefined) {
195
235
  return reject(
196
236
  R.definitionRequired,
197
237
  'Author definition is not embedded; fetch it from the ledger',
198
238
  );
199
239
  }
240
+ if (!isSigDefinition(definition)) {
241
+ return reject(R.definition, "Only ['sig', {pubkey}] author definitions are supported");
242
+ }
200
243
  if (obyte.utils.getChash160([...definition]) !== payer) {
201
244
  return reject(R.definition, 'Definition does not match the author address');
202
245
  }
@@ -207,14 +250,27 @@ export function validateExactUnit(
207
250
  if (!verifySignature(getUnitHashToSign(unit), authentifiers['r'], definition[1].pubkey)) {
208
251
  return reject(R.signature, 'Signature is invalid');
209
252
  }
253
+ return accept({ payer, definitionFromLedger: !embedded });
254
+ }
210
255
 
211
- // --- payer / recipient sanity -------------------------------------------------
212
- if (payer === expect.payTo) return reject(R.payer, 'Payer and payTo must differ');
256
+ /** The payer is neither the recipient nor the facilitator. */
257
+ function checkPayer(payer: string, expect: ExactExpectation): Verdict<null> {
258
+ if (payer === expect.payTo) return reject(EXACT_REASONS.payer, 'Payer and payTo must differ');
213
259
  if (expect.facilitatorAddresses?.includes(payer)) {
214
- return reject(R.payer, 'A facilitator address must never be the payer');
260
+ return reject(EXACT_REASONS.payer, 'A facilitator address must never be the payer');
215
261
  }
262
+ return accept(null);
263
+ }
216
264
 
217
- // --- messages -----------------------------------------------------------------
265
+ /**
266
+ * Inline messages with matching hashes: exactly one data message carrying the
267
+ * binding, one payment per asset, bytes always and only the expected asset besides.
268
+ */
269
+ function checkMessages(
270
+ messages: unknown[],
271
+ expect: ExactExpectation,
272
+ ): Verdict<Map<string, Record<string, unknown>>> {
273
+ const R = EXACT_REASONS;
218
274
  let dataCount = 0;
219
275
  const payments = new Map<string, Record<string, unknown>>();
220
276
  for (const message of messages) {
@@ -233,29 +289,48 @@ export function validateExactUnit(
233
289
  const binding = checkBinding(payload, expect);
234
290
  if (binding !== undefined) return binding;
235
291
  } else if (message['app'] === 'payment') {
236
- if (!isPlainObject(payload) || !hasOnlyKeys(payload, PAYMENT_KEYS)) {
237
- return unsupported('Malformed payment');
238
- }
239
- const asset = 'asset' in payload ? payload['asset'] : 'base';
240
- if (asset === 'base' && 'asset' in payload)
241
- return unsupported('Bytes payment must omit asset');
242
- if (!isAssetId(asset)) return unsupported('Invalid payment asset');
243
- if (payments.has(asset)) return unsupported('One payment message per asset');
244
- payments.set(asset, payload);
292
+ const asset = paymentAsset(payload);
293
+ if (!asset.ok) return asset;
294
+ if (payments.has(asset.value)) return unsupported('One payment message per asset');
295
+ payments.set(asset.value, payload as Record<string, unknown>);
245
296
  } else {
246
297
  return unsupported('Only payment and data messages are supported');
247
298
  }
248
299
  }
249
- if (dataCount !== 1)
300
+ if (dataCount !== 1) {
250
301
  return reject(R.binding, 'Exactly one data message with the binding is required');
302
+ }
251
303
  if (!payments.has('base')) return unsupported('A bytes payment message is required');
252
- const allowedAssets = new Set(['base', expect.asset]);
253
304
  for (const asset of payments.keys()) {
254
- if (!allowedAssets.has(asset)) return reject(R.asset, 'Payment in an unexpected asset');
305
+ if (asset !== 'base' && asset !== expect.asset) {
306
+ return reject(R.asset, 'Payment in an unexpected asset');
307
+ }
255
308
  }
256
309
  if (!payments.has(expect.asset)) return reject(R.asset, 'No payment in the required asset');
310
+ return accept(payments);
311
+ }
312
+
313
+ /** The asset of a payment message ('base' when omitted). */
314
+ function paymentAsset(payload: unknown): Verdict<string> {
315
+ if (!isPlainObject(payload) || !hasOnlyKeys(payload, PAYMENT_KEYS)) {
316
+ return unsupported('Malformed payment');
317
+ }
318
+ const asset = 'asset' in payload ? payload['asset'] : 'base';
319
+ if (asset === 'base' && 'asset' in payload) return unsupported('Bytes payment must omit asset');
320
+ if (!isAssetId(asset)) return unsupported('Invalid payment asset');
321
+ return accept(asset);
322
+ }
257
323
 
258
- // --- inputs & outputs -----------------------------------------------------------
324
+ /**
325
+ * Transfer inputs only (no duplicates); sorted outputs that go to payTo
326
+ * (exactly once, the exact amount, the expected asset) or back to the payer.
327
+ */
328
+ function checkTransfers(
329
+ payments: Map<string, Record<string, unknown>>,
330
+ payer: string,
331
+ expect: ExactExpectation,
332
+ ): Verdict<{ inputs: InputRef[]; outputTotals: Record<string, bigint> }> {
333
+ const R = EXACT_REASONS;
259
334
  const inputs: InputRef[] = [];
260
335
  const seenInputs = new Set<string>();
261
336
  const outputTotals: Record<string, bigint> = {};
@@ -268,24 +343,12 @@ export function validateExactUnit(
268
343
  return unsupported('Payment needs inputs and outputs');
269
344
  }
270
345
  for (const input of ins) {
271
- if (
272
- !isPlainObject(input) ||
273
- !hasOnlyKeys(input, INPUT_KEYS) ||
274
- !isHash(input['unit']) ||
275
- !isIndex(input['message_index']) ||
276
- !isIndex(input['output_index'])
277
- ) {
278
- return unsupported('Only transfer inputs are supported');
279
- }
280
- const key = `${input['unit']}:${input['message_index']}:${input['output_index']}`;
346
+ const ref = transferInput(input, asset);
347
+ if (ref === undefined) return unsupported('Only transfer inputs are supported');
348
+ const key = `${ref.unit}:${ref.messageIndex}:${ref.outputIndex}`;
281
349
  if (seenInputs.has(key)) return unsupported('Duplicate input');
282
350
  seenInputs.add(key);
283
- inputs.push({
284
- asset,
285
- unit: input['unit'],
286
- messageIndex: input['message_index'],
287
- outputIndex: input['output_index'],
288
- });
351
+ inputs.push(ref);
289
352
  }
290
353
  let total = 0n;
291
354
  let previous: { address: string; amount: number } | undefined;
@@ -305,14 +368,13 @@ export function validateExactUnit(
305
368
  return unsupported('Outputs must be sorted by address and amount without duplicates');
306
369
  }
307
370
  previous = current;
308
- const amount = BigInt(output['amount']);
309
- total += amount;
310
- if (output['address'] === expect.payTo) {
371
+ total += BigInt(current.amount);
372
+ if (current.address === expect.payTo) {
311
373
  if (asset !== expect.asset)
312
374
  return reject(R.recipient, 'payTo receives an unexpected asset');
313
375
  outputsToPayTo += 1;
314
- paidToPayTo += amount;
315
- } else if (output['address'] !== payer) {
376
+ paidToPayTo += BigInt(current.amount);
377
+ } else if (current.address !== payer) {
316
378
  return reject(R.recipient, 'Outputs may only go to payTo or back to the payer');
317
379
  }
318
380
  }
@@ -320,27 +382,26 @@ export function validateExactUnit(
320
382
  }
321
383
  if (outputsToPayTo !== 1) return reject(R.recipient, 'Exactly one output to payTo is required');
322
384
  if (paidToPayTo !== expect.amount) return reject(R.amount, 'Amount paid to payTo does not match');
385
+ return accept({ inputs, outputTotals });
386
+ }
323
387
 
324
- // --- commissions ------------------------------------------------------------------
325
- const commissions = expectedCommissions(unit);
388
+ /** A transfer input (unit, message_index, output_index), or undefined for anything else. */
389
+ function transferInput(input: unknown, asset: string): InputRef | undefined {
326
390
  if (
327
- commissions.headers !== unit['headers_commission'] ||
328
- commissions.payload !== unit['payload_commission']
391
+ !isPlainObject(input) ||
392
+ !hasOnlyKeys(input, INPUT_KEYS) ||
393
+ !isHash(input['unit']) ||
394
+ !isIndex(input['message_index']) ||
395
+ !isIndex(input['output_index'])
329
396
  ) {
330
- return reject(R.commissions, 'Commissions do not match the unit size');
397
+ return undefined;
331
398
  }
332
-
333
- return accept({
334
- unitHash,
335
- payer,
336
- inputs,
337
- lastBallUnit: unit['last_ball_unit'],
338
- parentUnits: parents,
339
- timestamp: unit['timestamp'] as number,
340
- outputTotals,
341
- commissions,
342
- definitionFromLedger,
343
- });
399
+ return {
400
+ asset,
401
+ unit: input['unit'],
402
+ messageIndex: input['message_index'],
403
+ outputIndex: input['output_index'],
404
+ };
344
405
  }
345
406
 
346
407
  /** Length of one base64 secp256k1 signature, as counted by obyte.js. */
@@ -369,10 +430,8 @@ export function compareOutputs(
369
430
  return a.amount - b.amount;
370
431
  }
371
432
 
372
- function checkBinding(
373
- payload: unknown,
374
- expect: ExactExpectation,
375
- ): Verdict<ExactUnitFacts> | undefined {
433
+ /** The data message is exactly `{x402: {binding, quoteId}}` of this operation (undefined when it is). */
434
+ function checkBinding(payload: unknown, expect: ExactExpectation): Verdict<never> | undefined {
376
435
  const R = EXACT_REASONS;
377
436
  if (!isPlainObject(payload) || !hasOnlyKeys(payload, new Set(['x402']))) {
378
437
  return reject(R.binding, 'Data message must be exactly {x402: {binding, quoteId}}');