@txnod/sdk 1.0.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.
- package/AGENTS.md +29 -0
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +434 -0
- package/dist/_shared/index.d.ts +68 -0
- package/dist/client-sandbox.d.ts +396 -0
- package/dist/client-sandbox.d.ts.map +1 -0
- package/dist/client-sandbox.js +448 -0
- package/dist/client-sandbox.js.map +1 -0
- package/dist/client.d.ts +429 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +588 -0
- package/dist/client.js.map +1 -0
- package/dist/env.d.ts +29 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +44 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +1887 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +2107 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/internals/error-ctor-map.d.ts +11 -0
- package/dist/internals/error-ctor-map.d.ts.map +1 -0
- package/dist/internals/error-ctor-map.js +75 -0
- package/dist/internals/error-ctor-map.js.map +1 -0
- package/dist/internals/fetch-with-retry.d.ts +34 -0
- package/dist/internals/fetch-with-retry.d.ts.map +1 -0
- package/dist/internals/fetch-with-retry.js +233 -0
- package/dist/internals/fetch-with-retry.js.map +1 -0
- package/dist/internals/hmac.d.ts +2 -0
- package/dist/internals/hmac.d.ts.map +1 -0
- package/dist/internals/hmac.js +10 -0
- package/dist/internals/hmac.js.map +1 -0
- package/dist/internals/logger.d.ts +9 -0
- package/dist/internals/logger.d.ts.map +1 -0
- package/dist/internals/logger.js +16 -0
- package/dist/internals/logger.js.map +1 -0
- package/dist/internals/parse-problem-details.d.ts +3 -0
- package/dist/internals/parse-problem-details.d.ts.map +1 -0
- package/dist/internals/parse-problem-details.js +76 -0
- package/dist/internals/parse-problem-details.js.map +1 -0
- package/dist/internals/synthetic-details.d.ts +12 -0
- package/dist/internals/synthetic-details.d.ts.map +1 -0
- package/dist/internals/synthetic-details.js +19 -0
- package/dist/internals/synthetic-details.js.map +1 -0
- package/dist/verify/chains/bsc.d.ts +17 -0
- package/dist/verify/chains/bsc.d.ts.map +1 -0
- package/dist/verify/chains/bsc.js +15 -0
- package/dist/verify/chains/bsc.js.map +1 -0
- package/dist/verify/chains/btc.d.ts +22 -0
- package/dist/verify/chains/btc.d.ts.map +1 -0
- package/dist/verify/chains/btc.js +55 -0
- package/dist/verify/chains/btc.js.map +1 -0
- package/dist/verify/chains/cardano.d.ts +73 -0
- package/dist/verify/chains/cardano.d.ts.map +1 -0
- package/dist/verify/chains/cardano.js +175 -0
- package/dist/verify/chains/cardano.js.map +1 -0
- package/dist/verify/chains/evm.d.ts +21 -0
- package/dist/verify/chains/evm.d.ts.map +1 -0
- package/dist/verify/chains/evm.js +46 -0
- package/dist/verify/chains/evm.js.map +1 -0
- package/dist/verify/chains/polygon.d.ts +17 -0
- package/dist/verify/chains/polygon.d.ts.map +1 -0
- package/dist/verify/chains/polygon.js +15 -0
- package/dist/verify/chains/polygon.js.map +1 -0
- package/dist/verify/chains/secp256k1-bip32.d.ts +20 -0
- package/dist/verify/chains/secp256k1-bip32.d.ts.map +1 -0
- package/dist/verify/chains/secp256k1-bip32.js +88 -0
- package/dist/verify/chains/secp256k1-bip32.js.map +1 -0
- package/dist/verify/chains/ton-cell.d.ts +179 -0
- package/dist/verify/chains/ton-cell.d.ts.map +1 -0
- package/dist/verify/chains/ton-cell.js +614 -0
- package/dist/verify/chains/ton-cell.js.map +1 -0
- package/dist/verify/chains/ton.d.ts +84 -0
- package/dist/verify/chains/ton.d.ts.map +1 -0
- package/dist/verify/chains/ton.js +131 -0
- package/dist/verify/chains/ton.js.map +1 -0
- package/dist/verify/chains/tron.d.ts +21 -0
- package/dist/verify/chains/tron.d.ts.map +1 -0
- package/dist/verify/chains/tron.js +42 -0
- package/dist/verify/chains/tron.js.map +1 -0
- package/dist/verify/config.d.ts +41 -0
- package/dist/verify/config.d.ts.map +1 -0
- package/dist/verify/config.js +120 -0
- package/dist/verify/config.js.map +1 -0
- package/dist/verify/errors.d.ts +56 -0
- package/dist/verify/errors.d.ts.map +1 -0
- package/dist/verify/errors.js +58 -0
- package/dist/verify/errors.js.map +1 -0
- package/dist/verify/index.d.ts +119 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +166 -0
- package/dist/verify/index.js.map +1 -0
- package/dist/verify/xpub-safety.d.ts +33 -0
- package/dist/verify/xpub-safety.d.ts.map +1 -0
- package/dist/verify/xpub-safety.js +54 -0
- package/dist/verify/xpub-safety.js.map +1 -0
- package/dist/verify-webhook-signature.d.ts +30 -0
- package/dist/verify-webhook-signature.d.ts.map +1 -0
- package/dist/verify-webhook-signature.js +84 -0
- package/dist/verify-webhook-signature.js.map +1 -0
- package/docs/00-getting-started.md +135 -0
- package/docs/01-authentication.md +114 -0
- package/docs/02-invoices.md +216 -0
- package/docs/03-rates-and-quotes.md +82 -0
- package/docs/04-webhooks.md +126 -0
- package/docs/05-errors.md +199 -0
- package/docs/05-sandbox.md +159 -0
- package/docs/06-idempotency.md +132 -0
- package/docs/examples/express-webhook-receiver.md +97 -0
- package/docs/examples/nextjs-route-handler.md +206 -0
- package/docs/examples/sandbox-vitest-suite.md +263 -0
- package/docs/index.md +66 -0
- package/docs/reference/client.md +392 -0
- package/docs/reference/errors.md +161 -0
- package/docs/reference/types.md +400 -0
- package/package.json +53 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { TxnodError } from '../errors.js';
|
|
2
|
+
import { CODE_TO_CTOR, RETRY_AFTER_CODES, } from './error-ctor-map.js';
|
|
3
|
+
function degraded(status) {
|
|
4
|
+
const raw = {
|
|
5
|
+
type: 'about:blank',
|
|
6
|
+
title: 'Non-compliant error response',
|
|
7
|
+
status,
|
|
8
|
+
error_code: 'internal_error',
|
|
9
|
+
request_id: '',
|
|
10
|
+
};
|
|
11
|
+
return new TxnodError(raw);
|
|
12
|
+
}
|
|
13
|
+
function isRecord(v) {
|
|
14
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
15
|
+
}
|
|
16
|
+
// Duplicated from fetch-with-retry.ts#parseRetryAfterSeconds — do not cross-import; keep in sync.
|
|
17
|
+
// RFC 7231 §7.1.3 allows either delta-seconds or HTTP-date. The cap defends
|
|
18
|
+
// against a hostile/glitching upstream returning a far-future date that would
|
|
19
|
+
// otherwise stall caller-side retry logic for hours.
|
|
20
|
+
const RETRY_AFTER_CAP_SECONDS = 600;
|
|
21
|
+
function parseRetryAfter(response) {
|
|
22
|
+
const header = response.headers.get('Retry-After');
|
|
23
|
+
if (header === null)
|
|
24
|
+
return 0;
|
|
25
|
+
const trimmed = header.trim();
|
|
26
|
+
let raw;
|
|
27
|
+
if (/^\d+$/.test(trimmed)) {
|
|
28
|
+
const n = parseInt(trimmed, 10);
|
|
29
|
+
raw = Number.isFinite(n) && n > 0 ? n : 0;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const ms = Date.parse(header);
|
|
33
|
+
if (!Number.isFinite(ms))
|
|
34
|
+
return 0;
|
|
35
|
+
const deltaSec = Math.ceil((ms - Date.now()) / 1000);
|
|
36
|
+
raw = deltaSec > 0 ? deltaSec : 0;
|
|
37
|
+
}
|
|
38
|
+
return Math.min(raw, RETRY_AFTER_CAP_SECONDS);
|
|
39
|
+
}
|
|
40
|
+
export async function parseProblemDetails(response) {
|
|
41
|
+
const text = await response.text();
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(text);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return degraded(response.status);
|
|
48
|
+
}
|
|
49
|
+
if (!isRecord(parsed))
|
|
50
|
+
return degraded(response.status);
|
|
51
|
+
const { type, title, status, error_code, request_id, errors, wallet_id } = parsed;
|
|
52
|
+
if (type !== 'about:blank' ||
|
|
53
|
+
typeof title !== 'string' ||
|
|
54
|
+
typeof status !== 'number' ||
|
|
55
|
+
typeof error_code !== 'string' ||
|
|
56
|
+
typeof request_id !== 'string') {
|
|
57
|
+
return degraded(response.status);
|
|
58
|
+
}
|
|
59
|
+
const details = {
|
|
60
|
+
type: 'about:blank',
|
|
61
|
+
title,
|
|
62
|
+
status,
|
|
63
|
+
error_code: error_code,
|
|
64
|
+
request_id,
|
|
65
|
+
...(Array.isArray(errors) ? { errors: errors } : {}),
|
|
66
|
+
...(typeof wallet_id === 'string' ? { wallet_id } : {}),
|
|
67
|
+
};
|
|
68
|
+
const Ctor = CODE_TO_CTOR[details.error_code];
|
|
69
|
+
if (Ctor === undefined)
|
|
70
|
+
return degraded(response.status);
|
|
71
|
+
if (RETRY_AFTER_CODES.has(details.error_code)) {
|
|
72
|
+
return new Ctor(details, parseRetryAfter(response));
|
|
73
|
+
}
|
|
74
|
+
return new Ctor(details);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=parse-problem-details.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-problem-details.js","sourceRoot":"","sources":["../../src/internals/parse-problem-details.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACL,YAAY,EACZ,iBAAiB,GAGlB,MAAM,qBAAqB,CAAC;AAE7B,SAAS,QAAQ,CAAC,MAAc;IAC9B,MAAM,GAAG,GAAmB;QAC1B,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,8BAA8B;QACrC,MAAM;QACN,UAAU,EAAE,gBAAgB;QAC5B,UAAU,EAAE,EAAE;KACf,CAAC;IACF,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,kGAAkG;AAClG,4EAA4E;AAC5E,8EAA8E;AAC9E,qDAAqD;AACrD,MAAM,uBAAuB,GAAG,GAAG,CAAC;AACpC,SAAS,eAAe,CAAC,QAAkB;IACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,GAAW,CAAC;IAChB,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrD,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,uBAAuB,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAkB;IAElB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,GACtE,MAAM,CAAC;IACT,IACE,IAAI,KAAK,aAAa;QACtB,OAAO,KAAK,KAAK,QAAQ;QACzB,OAAO,MAAM,KAAK,QAAQ;QAC1B,OAAO,UAAU,KAAK,QAAQ;QAC9B,OAAO,UAAU,KAAK,QAAQ,EAC9B,CAAC;QACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,OAAO,GAAmB;QAC9B,IAAI,EAAE,aAAa;QACnB,KAAK;QACL,MAAM;QACN,UAAU,EAAE,UAA0C;QACtD,UAAU;QACV,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,GAAG,CAAC,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxD,CAAC;IAEF,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,OAAO,IAAK,IAAuB,CAAC,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,IAAK,IAAkB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ErrorCode, ProblemDetails } from '../_shared/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a stand-in `ProblemDetails` envelope for SDK-thrown errors that
|
|
4
|
+
* never received a server response (webhook signature failures, address
|
|
5
|
+
* verification failures, etc.). Used internally by `TxnodSignatureFormatError`,
|
|
6
|
+
* `TxnodHmacError`, `TxnodTimestampError`, and `AddressVerificationError`
|
|
7
|
+
* so they can extend `TxnodError` while still satisfying the RFC-7807
|
|
8
|
+
* envelope shape. Internal helper — not re-exported from the package barrel;
|
|
9
|
+
* partners should not subclass `TxnodError`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function syntheticDetails(error_code: ErrorCode, status: number, title: string): ProblemDetails;
|
|
12
|
+
//# sourceMappingURL=synthetic-details.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthetic-details.d.ts","sourceRoot":"","sources":["../../src/internals/synthetic-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/D;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,SAAS,EACrB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,cAAc,CAQhB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a stand-in `ProblemDetails` envelope for SDK-thrown errors that
|
|
3
|
+
* never received a server response (webhook signature failures, address
|
|
4
|
+
* verification failures, etc.). Used internally by `TxnodSignatureFormatError`,
|
|
5
|
+
* `TxnodHmacError`, `TxnodTimestampError`, and `AddressVerificationError`
|
|
6
|
+
* so they can extend `TxnodError` while still satisfying the RFC-7807
|
|
7
|
+
* envelope shape. Internal helper — not re-exported from the package barrel;
|
|
8
|
+
* partners should not subclass `TxnodError`.
|
|
9
|
+
*/
|
|
10
|
+
export function syntheticDetails(error_code, status, title) {
|
|
11
|
+
return {
|
|
12
|
+
type: 'about:blank',
|
|
13
|
+
title,
|
|
14
|
+
status,
|
|
15
|
+
error_code,
|
|
16
|
+
request_id: '',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=synthetic-details.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthetic-details.js","sourceRoot":"","sources":["../../src/internals/synthetic-details.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,UAAqB,EACrB,MAAc,EACd,KAAa;IAEb,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,KAAK;QACL,MAAM;QACN,UAAU;QACV,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BNB Smart Chain verification — shares BIP-44 coin_type=60' with Ethereum
|
|
3
|
+
* (architecture addendum §4.4). Cross-checked byte-for-byte against server-side
|
|
4
|
+
* derivation in apps/web/lib/derivation/evm.ts.
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4, AD-7.
|
|
9
|
+
*/
|
|
10
|
+
export interface VerifyBscInput {
|
|
11
|
+
xpub: string;
|
|
12
|
+
derivation_path: string;
|
|
13
|
+
expected_address: string;
|
|
14
|
+
}
|
|
15
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
16
|
+
export declare function verifyBsc(input: VerifyBscInput): void;
|
|
17
|
+
//# sourceMappingURL=bsc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsc.d.ts","sourceRoot":"","sources":["../../../src/verify/chains/bsc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAErD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BNB Smart Chain verification — shares BIP-44 coin_type=60' with Ethereum
|
|
3
|
+
* (architecture addendum §4.4). Cross-checked byte-for-byte against server-side
|
|
4
|
+
* derivation in apps/web/lib/derivation/evm.ts.
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4, AD-7.
|
|
9
|
+
*/
|
|
10
|
+
import { verifyEvm } from './evm.js';
|
|
11
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
12
|
+
export function verifyBsc(input) {
|
|
13
|
+
verifyEvm({ ...input, chain: 'bsc' });
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=bsc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bsc.js","sourceRoot":"","sources":["../../../src/verify/chains/bsc.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAQrC,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BTC native-SegWit (BIP-84) verification.
|
|
3
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
4
|
+
* apps/web/lib/derivation/btc.ts (Story 25.3 AC 9 fixture vectors).
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, AD-7.
|
|
9
|
+
* - Discovery §C.6 (Paul Miller / @noble / @scure family rationale),
|
|
10
|
+
* §E.1 (path 3 — audited deps + CI guard),
|
|
11
|
+
* sub-idea #2.1 (BTC SegWit-only default — Taproot deferred).
|
|
12
|
+
* - BIP-84 (https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki).
|
|
13
|
+
* - BIP-173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
|
|
14
|
+
*/
|
|
15
|
+
export interface VerifyBtcInput {
|
|
16
|
+
xpub: string;
|
|
17
|
+
derivation_path: string;
|
|
18
|
+
expected_address: string;
|
|
19
|
+
}
|
|
20
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
21
|
+
export declare function verifyBtc(input: VerifyBtcInput): void;
|
|
22
|
+
//# sourceMappingURL=btc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btc.d.ts","sourceRoot":"","sources":["../../../src/verify/chains/btc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAkCrD"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BTC native-SegWit (BIP-84) verification.
|
|
3
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
4
|
+
* apps/web/lib/derivation/btc.ts (Story 25.3 AC 9 fixture vectors).
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, AD-7.
|
|
9
|
+
* - Discovery §C.6 (Paul Miller / @noble / @scure family rationale),
|
|
10
|
+
* §E.1 (path 3 — audited deps + CI guard),
|
|
11
|
+
* sub-idea #2.1 (BTC SegWit-only default — Taproot deferred).
|
|
12
|
+
* - BIP-84 (https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki).
|
|
13
|
+
* - BIP-173 (https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
|
|
14
|
+
*/
|
|
15
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
16
|
+
import { ripemd160 } from '@noble/hashes/legacy.js';
|
|
17
|
+
import { bech32 } from '@scure/base';
|
|
18
|
+
import { deriveSecp256k1ChildPubkey } from './secp256k1-bip32.js';
|
|
19
|
+
import { AddressVerificationError } from '../errors.js';
|
|
20
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
21
|
+
export function verifyBtc(input) {
|
|
22
|
+
const sentinel = '<unsupported BTC address format — only bc1/tb1 native segwit (BIP-84) supported>';
|
|
23
|
+
let hrp;
|
|
24
|
+
if (input.expected_address.startsWith('bc1q'))
|
|
25
|
+
hrp = 'bc';
|
|
26
|
+
else if (input.expected_address.startsWith('tb1q'))
|
|
27
|
+
hrp = 'tb';
|
|
28
|
+
else {
|
|
29
|
+
throw new AddressVerificationError({
|
|
30
|
+
chain: 'btc',
|
|
31
|
+
derivation_path: input.derivation_path,
|
|
32
|
+
expected_address: input.expected_address,
|
|
33
|
+
derived_address: sentinel,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// `deriveSecp256k1ChildPubkey` strips/re-prepends the BIP-32 version
|
|
37
|
+
// bytes internally (single source of truth — see secp256k1-bip32.ts).
|
|
38
|
+
// Any of xpub / tpub / zpub / vpub is accepted as input here.
|
|
39
|
+
const pubkey = deriveSecp256k1ChildPubkey({
|
|
40
|
+
xpub: input.xpub,
|
|
41
|
+
derivation_path: input.derivation_path,
|
|
42
|
+
});
|
|
43
|
+
const program = ripemd160(sha256(pubkey));
|
|
44
|
+
const words = [0, ...bech32.toWords(program)];
|
|
45
|
+
const derived = bech32.encode(hrp, words);
|
|
46
|
+
if (derived !== input.expected_address) {
|
|
47
|
+
throw new AddressVerificationError({
|
|
48
|
+
chain: 'btc',
|
|
49
|
+
derivation_path: input.derivation_path,
|
|
50
|
+
expected_address: input.expected_address,
|
|
51
|
+
derived_address: derived,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=btc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"btc.js","sourceRoot":"","sources":["../../../src/verify/chains/btc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAQxD,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,QAAQ,GACZ,kFAAkF,CAAC;IACrF,IAAI,GAAgB,CAAC;IACrB,IAAI,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,GAAG,GAAG,IAAI,CAAC;SACrD,IAAI,KAAK,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,GAAG,GAAG,IAAI,CAAC;SAC1D,CAAC;QACJ,MAAM,IAAI,wBAAwB,CAAC;YACjC,KAAK,EAAE,KAAK;YACZ,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,eAAe,EAAE,QAAQ;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,qEAAqE;IACrE,sEAAsE;IACtE,8DAA8D;IAC9D,MAAM,MAAM,GAAG,0BAA0B,CAAC;QACxC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE1C,IAAI,OAAO,KAAK,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,wBAAwB,CAAC;YACjC,KAAK,EAAE,KAAK;YACZ,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,eAAe,EAAE,OAAO;SACzB,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cardano CIP-1852 verification — full base_address reconstruction defending
|
|
3
|
+
* against the NFR-S11 stake-substitution attack class.
|
|
4
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
5
|
+
* apps/web/lib/derivation/cardano.ts.
|
|
6
|
+
*
|
|
7
|
+
* Sources:
|
|
8
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
9
|
+
* - PRD NFR-S11: full base-address reconstruction (no stake-only compares).
|
|
10
|
+
* - Architecture addendum §4.1, §4.3.
|
|
11
|
+
* - Discovery §E.2 (stake-substitution attack analysis),
|
|
12
|
+
* §C.3 (~200 LOC hand-rolled CIP-1852 budget).
|
|
13
|
+
* - CIP-1852 (https://cips.cardano.org/cip/CIP-1852).
|
|
14
|
+
* - CIP-19 (https://cips.cardano.org/cip/CIP-19).
|
|
15
|
+
* - BIP32-Ed25519 paper, Khovratovich & Law:
|
|
16
|
+
* https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf
|
|
17
|
+
* - Reference impl: LedgerHQ/orakolo/HDEd25519.py.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Input shape for `verifyCardano`. Network is inferred from the bech32 HRP of
|
|
21
|
+
* `expected_address` (`addr1…` mainnet, `addr_test1…` testnet).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { verifyCardano, type VerifyCardanoInput } from '@txnod/sdk';
|
|
26
|
+
*
|
|
27
|
+
* const input: VerifyCardanoInput = {
|
|
28
|
+
* xpub: 'acct_xvk1amspej3axrnc6p7cf0xaer365l2770744w5mhzu3l8seackc96pszurk0e6mlmd9dg9zkzsvw9sx7h5llkmu604r8eqhz7nw92fmn7qtfjwwy',
|
|
29
|
+
* derivation_path: "m/1852'/1815'/0'/0/0",
|
|
30
|
+
* expected_address: 'addr1q8sv3r5ve3dftjlv34jma0xx9kd84dzrxudsjkte5vsdd5fht2sfxl6wpe6c9m6jzpey8tzavkkyjgvjc6dluvar65js8mfsuy',
|
|
31
|
+
* };
|
|
32
|
+
* verifyCardano(input);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export interface VerifyCardanoInput {
|
|
36
|
+
xpub: string;
|
|
37
|
+
derivation_path: string;
|
|
38
|
+
expected_address: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Locally verify that a Cardano `addr1…` / `addr_test1…` base address derives
|
|
42
|
+
* from the operator's CIP-5 `acct_xvk1…` account-extended verification key at
|
|
43
|
+
* the given CIP-1852 payment path. Reconstructs the FULL base address — both
|
|
44
|
+
* `payment_key_hash` (path `0/index`) AND `stake_key_hash` (path `2/0`) — and
|
|
45
|
+
* compares the full bech32 string. This closes NFR-S11: an attacker who
|
|
46
|
+
* controls a payment keypair cannot have an `evil_payment_hash || legit_stake_hash`
|
|
47
|
+
* address pass verification, because the SDK rederives both halves from the
|
|
48
|
+
* operator's account xvk and rejects on mismatch.
|
|
49
|
+
*
|
|
50
|
+
* Throws `AddressVerificationError` on mismatch (or unsupported HRP).
|
|
51
|
+
* Throws `TxnodInvalidXpubFormatError` on malformed xpub or path.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { verifyCardano, AddressVerificationError } from '@txnod/sdk';
|
|
56
|
+
*
|
|
57
|
+
* try {
|
|
58
|
+
* verifyCardano({
|
|
59
|
+
* xpub: 'acct_xvk1amspej3axrnc6p7cf0xaer365l2770744w5mhzu3l8seackc96pszurk0e6mlmd9dg9zkzsvw9sx7h5llkmu604r8eqhz7nw92fmn7qtfjwwy',
|
|
60
|
+
* derivation_path: "m/1852'/1815'/0'/0/0",
|
|
61
|
+
* expected_address: 'addr1q8sv3r5ve3dftjlv34jma0xx9kd84dzrxudsjkte5vsdd5fht2sfxl6wpe6c9m6jzpey8tzavkkyjgvjc6dluvar65js8mfsuy',
|
|
62
|
+
* });
|
|
63
|
+
* } catch (err) {
|
|
64
|
+
* if (err instanceof AddressVerificationError) {
|
|
65
|
+
* console.error('ada verify failed', err.expected_address, err.derived_address);
|
|
66
|
+
* } else {
|
|
67
|
+
* throw err;
|
|
68
|
+
* }
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function verifyCardano(input: VerifyCardanoInput): void;
|
|
73
|
+
//# sourceMappingURL=cardano.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cardano.d.ts","sourceRoot":"","sources":["../../../src/verify/chains/cardano.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AA+GD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CA8C7D"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cardano CIP-1852 verification — full base_address reconstruction defending
|
|
3
|
+
* against the NFR-S11 stake-substitution attack class.
|
|
4
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
5
|
+
* apps/web/lib/derivation/cardano.ts.
|
|
6
|
+
*
|
|
7
|
+
* Sources:
|
|
8
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
9
|
+
* - PRD NFR-S11: full base-address reconstruction (no stake-only compares).
|
|
10
|
+
* - Architecture addendum §4.1, §4.3.
|
|
11
|
+
* - Discovery §E.2 (stake-substitution attack analysis),
|
|
12
|
+
* §C.3 (~200 LOC hand-rolled CIP-1852 budget).
|
|
13
|
+
* - CIP-1852 (https://cips.cardano.org/cip/CIP-1852).
|
|
14
|
+
* - CIP-19 (https://cips.cardano.org/cip/CIP-19).
|
|
15
|
+
* - BIP32-Ed25519 paper, Khovratovich & Law:
|
|
16
|
+
* https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf
|
|
17
|
+
* - Reference impl: LedgerHQ/orakolo/HDEd25519.py.
|
|
18
|
+
*/
|
|
19
|
+
import * as ed from '@noble/ed25519';
|
|
20
|
+
import { blake2b } from '@noble/hashes/blake2.js';
|
|
21
|
+
import { hmac } from '@noble/hashes/hmac.js';
|
|
22
|
+
import { sha512 } from '@noble/hashes/sha2.js';
|
|
23
|
+
import { bech32 } from '@scure/base';
|
|
24
|
+
import { TxnodInvalidXpubFormatError } from '../../errors.js';
|
|
25
|
+
import { syntheticDetails } from '../../internals/synthetic-details.js';
|
|
26
|
+
import { AddressVerificationError } from '../errors.js';
|
|
27
|
+
function pathError(message) {
|
|
28
|
+
return new TxnodInvalidXpubFormatError(syntheticDetails('invalid_xpub_format', 400, message));
|
|
29
|
+
}
|
|
30
|
+
function parseAccountXvk(xpub) {
|
|
31
|
+
const decoded = bech32.decode(xpub, false);
|
|
32
|
+
if (decoded.prefix !== 'acct_xvk') {
|
|
33
|
+
throw pathError(`xpub must be a CIP-5 'acct_xvk' bech32 string; got prefix '${decoded.prefix}'.`);
|
|
34
|
+
}
|
|
35
|
+
const bytes = bech32.fromWords(decoded.words);
|
|
36
|
+
if (bytes.length !== 64) {
|
|
37
|
+
throw pathError(`acct_xvk must decode to 64 bytes (32-byte pubkey + 32-byte chain-code); got ${bytes.length}.`);
|
|
38
|
+
}
|
|
39
|
+
return { A: bytes.slice(0, 32), c: bytes.slice(32, 64) };
|
|
40
|
+
}
|
|
41
|
+
function parsePaymentPath(path) {
|
|
42
|
+
const segments = path.split('/');
|
|
43
|
+
if (segments.length < 3 || segments[0] !== 'm') {
|
|
44
|
+
throw pathError(`derivation_path '${path}' must begin with 'm' and have at least 2 segments after 'm'.`);
|
|
45
|
+
}
|
|
46
|
+
const role = segments[segments.length - 2] ?? '';
|
|
47
|
+
const index = segments[segments.length - 1] ?? '';
|
|
48
|
+
if (role.endsWith("'") || index.endsWith("'")) {
|
|
49
|
+
throw pathError(`derivation_path '${path}' last two segments must be non-hardened (no apostrophe suffix).`);
|
|
50
|
+
}
|
|
51
|
+
if (!/^\d+$/.test(role) || !/^\d+$/.test(index)) {
|
|
52
|
+
throw pathError(`derivation_path '${path}' last two segments must be unsigned integers.`);
|
|
53
|
+
}
|
|
54
|
+
if (role !== '0') {
|
|
55
|
+
throw pathError(`derivation_path '${path}' role segment must be 0 (CIP-1852 external chain) for payment leaves; got '${role}'.`);
|
|
56
|
+
}
|
|
57
|
+
return { index: Number(index) };
|
|
58
|
+
}
|
|
59
|
+
function le32(i) {
|
|
60
|
+
const b = new Uint8Array(4);
|
|
61
|
+
b[0] = i & 0xff;
|
|
62
|
+
b[1] = (i >>> 8) & 0xff;
|
|
63
|
+
b[2] = (i >>> 16) & 0xff;
|
|
64
|
+
b[3] = (i >>> 24) & 0xff;
|
|
65
|
+
return b;
|
|
66
|
+
}
|
|
67
|
+
function bytesToNumberLE(b) {
|
|
68
|
+
let n = 0n;
|
|
69
|
+
for (let i = b.length - 1; i >= 0; i--) {
|
|
70
|
+
n = (n << 8n) | BigInt(b[i]);
|
|
71
|
+
}
|
|
72
|
+
return n;
|
|
73
|
+
}
|
|
74
|
+
function concat(...parts) {
|
|
75
|
+
let total = 0;
|
|
76
|
+
for (const p of parts)
|
|
77
|
+
total += p.length;
|
|
78
|
+
const out = new Uint8Array(total);
|
|
79
|
+
let off = 0;
|
|
80
|
+
for (const p of parts) {
|
|
81
|
+
out.set(p, off);
|
|
82
|
+
off += p.length;
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function softCKDpub(parent, i) {
|
|
87
|
+
if (!Number.isInteger(i) || i < 0 || i >= 0x80000000) {
|
|
88
|
+
throw pathError(`child index ${i} out of range for non-hardened BIP32-Ed25519 derivation.`);
|
|
89
|
+
}
|
|
90
|
+
const idx = le32(i);
|
|
91
|
+
const Z = hmac(sha512, parent.c, concat(new Uint8Array([0x02]), parent.A, idx));
|
|
92
|
+
const childChain = hmac(sha512, parent.c, concat(new Uint8Array([0x03]), parent.A, idx)).slice(32, 64);
|
|
93
|
+
const ZL = Z.slice(0, 28);
|
|
94
|
+
const k = 8n * bytesToNumberLE(ZL);
|
|
95
|
+
const A_i = k === 0n
|
|
96
|
+
? parent.A
|
|
97
|
+
: ed.Point.fromBytes(parent.A).add(ed.Point.BASE.multiply(k)).toBytes();
|
|
98
|
+
return { A: A_i, c: childChain };
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Locally verify that a Cardano `addr1…` / `addr_test1…` base address derives
|
|
102
|
+
* from the operator's CIP-5 `acct_xvk1…` account-extended verification key at
|
|
103
|
+
* the given CIP-1852 payment path. Reconstructs the FULL base address — both
|
|
104
|
+
* `payment_key_hash` (path `0/index`) AND `stake_key_hash` (path `2/0`) — and
|
|
105
|
+
* compares the full bech32 string. This closes NFR-S11: an attacker who
|
|
106
|
+
* controls a payment keypair cannot have an `evil_payment_hash || legit_stake_hash`
|
|
107
|
+
* address pass verification, because the SDK rederives both halves from the
|
|
108
|
+
* operator's account xvk and rejects on mismatch.
|
|
109
|
+
*
|
|
110
|
+
* Throws `AddressVerificationError` on mismatch (or unsupported HRP).
|
|
111
|
+
* Throws `TxnodInvalidXpubFormatError` on malformed xpub or path.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* import { verifyCardano, AddressVerificationError } from '@txnod/sdk';
|
|
116
|
+
*
|
|
117
|
+
* try {
|
|
118
|
+
* verifyCardano({
|
|
119
|
+
* xpub: 'acct_xvk1amspej3axrnc6p7cf0xaer365l2770744w5mhzu3l8seackc96pszurk0e6mlmd9dg9zkzsvw9sx7h5llkmu604r8eqhz7nw92fmn7qtfjwwy',
|
|
120
|
+
* derivation_path: "m/1852'/1815'/0'/0/0",
|
|
121
|
+
* expected_address: 'addr1q8sv3r5ve3dftjlv34jma0xx9kd84dzrxudsjkte5vsdd5fht2sfxl6wpe6c9m6jzpey8tzavkkyjgvjc6dluvar65js8mfsuy',
|
|
122
|
+
* });
|
|
123
|
+
* } catch (err) {
|
|
124
|
+
* if (err instanceof AddressVerificationError) {
|
|
125
|
+
* console.error('ada verify failed', err.expected_address, err.derived_address);
|
|
126
|
+
* } else {
|
|
127
|
+
* throw err;
|
|
128
|
+
* }
|
|
129
|
+
* }
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export function verifyCardano(input) {
|
|
133
|
+
const sentinel = '<unsupported Cardano address format — only addr1/addr_test1 base addresses (CIP-19 Type 0) supported>';
|
|
134
|
+
let hrp;
|
|
135
|
+
let networkId;
|
|
136
|
+
if (input.expected_address.startsWith('addr_test1')) {
|
|
137
|
+
hrp = 'addr_test';
|
|
138
|
+
networkId = 0;
|
|
139
|
+
}
|
|
140
|
+
else if (input.expected_address.startsWith('addr1')) {
|
|
141
|
+
hrp = 'addr';
|
|
142
|
+
networkId = 1;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
throw new AddressVerificationError({
|
|
146
|
+
chain: 'ada',
|
|
147
|
+
derivation_path: input.derivation_path,
|
|
148
|
+
expected_address: input.expected_address,
|
|
149
|
+
derived_address: sentinel,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const acct = parseAccountXvk(input.xpub);
|
|
153
|
+
const { index } = parsePaymentPath(input.derivation_path);
|
|
154
|
+
const paymentRole = softCKDpub(acct, 0);
|
|
155
|
+
const paymentLeaf = softCKDpub(paymentRole, index);
|
|
156
|
+
const stakeRole = softCKDpub(acct, 2);
|
|
157
|
+
const stakeLeaf = softCKDpub(stakeRole, 0);
|
|
158
|
+
const paymentKeyHash = blake2b(paymentLeaf.A, { dkLen: 28 });
|
|
159
|
+
const stakeKeyHash = blake2b(stakeLeaf.A, { dkLen: 28 });
|
|
160
|
+
const headerByte = (0x0 << 4) | networkId;
|
|
161
|
+
const raw = new Uint8Array(57);
|
|
162
|
+
raw[0] = headerByte;
|
|
163
|
+
raw.set(paymentKeyHash, 1);
|
|
164
|
+
raw.set(stakeKeyHash, 29);
|
|
165
|
+
const derived = bech32.encode(hrp, bech32.toWords(raw), false);
|
|
166
|
+
if (derived !== input.expected_address) {
|
|
167
|
+
throw new AddressVerificationError({
|
|
168
|
+
chain: 'ada',
|
|
169
|
+
derivation_path: input.derivation_path,
|
|
170
|
+
expected_address: input.expected_address,
|
|
171
|
+
derived_address: derived,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=cardano.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cardano.js","sourceRoot":"","sources":["../../../src/verify/chains/cardano.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVM (ETH / Polygon PoS / BSC) verification — BIP-44 coin_type=60'.
|
|
3
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
4
|
+
* apps/web/lib/derivation/evm.ts (Story 25.3 AC 9 fixture vectors).
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4 (EVM triplet shares coin_type=60'), AD-7.
|
|
9
|
+
* - Discovery §C.6, §E.1.
|
|
10
|
+
* - EIP-55 (https://eips.ethereum.org/EIPS/eip-55).
|
|
11
|
+
* - SLIP-0044 coin_type=60 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md).
|
|
12
|
+
*/
|
|
13
|
+
export interface VerifyEvmInput {
|
|
14
|
+
xpub: string;
|
|
15
|
+
derivation_path: string;
|
|
16
|
+
expected_address: string;
|
|
17
|
+
chain: 'eth' | 'polygon' | 'bsc';
|
|
18
|
+
}
|
|
19
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
20
|
+
export declare function verifyEvm(input: VerifyEvmInput): void;
|
|
21
|
+
//# sourceMappingURL=evm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm.d.ts","sourceRoot":"","sources":["../../../src/verify/chains/evm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAmBH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;CAClC;AAED,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAiBrD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVM (ETH / Polygon PoS / BSC) verification — BIP-44 coin_type=60'.
|
|
3
|
+
* Cross-checked byte-for-byte against server-side derivation in
|
|
4
|
+
* apps/web/lib/derivation/evm.ts (Story 25.3 AC 9 fixture vectors).
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96: SDK locally verifies createInvoice address derives from xpub.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4 (EVM triplet shares coin_type=60'), AD-7.
|
|
9
|
+
* - Discovery §C.6, §E.1.
|
|
10
|
+
* - EIP-55 (https://eips.ethereum.org/EIPS/eip-55).
|
|
11
|
+
* - SLIP-0044 coin_type=60 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md).
|
|
12
|
+
*/
|
|
13
|
+
import { secp256k1 } from '@noble/curves/secp256k1.js';
|
|
14
|
+
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
15
|
+
import { deriveSecp256k1ChildPubkey } from './secp256k1-bip32.js';
|
|
16
|
+
import { AddressVerificationError } from '../errors.js';
|
|
17
|
+
function eip55Encode(bytes20) {
|
|
18
|
+
const lowerHex = Array.from(bytes20, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
19
|
+
const hashed = keccak_256(new TextEncoder().encode(lowerHex));
|
|
20
|
+
const hashedHex = Array.from(hashed, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
21
|
+
let out = '0x';
|
|
22
|
+
for (let i = 0; i < 40; i++) {
|
|
23
|
+
const ch = lowerHex.charAt(i);
|
|
24
|
+
out += parseInt(hashedHex.charAt(i), 16) >= 8 ? ch.toUpperCase() : ch;
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
29
|
+
export function verifyEvm(input) {
|
|
30
|
+
const pubkey = deriveSecp256k1ChildPubkey({
|
|
31
|
+
xpub: input.xpub,
|
|
32
|
+
derivation_path: input.derivation_path,
|
|
33
|
+
});
|
|
34
|
+
const uncompressed = secp256k1.Point.fromBytes(pubkey).toBytes(false);
|
|
35
|
+
const addressBytes = keccak_256(uncompressed.slice(1)).slice(-20);
|
|
36
|
+
const derived = eip55Encode(addressBytes);
|
|
37
|
+
if (derived !== input.expected_address) {
|
|
38
|
+
throw new AddressVerificationError({
|
|
39
|
+
chain: input.chain,
|
|
40
|
+
derivation_path: input.derivation_path,
|
|
41
|
+
expected_address: input.expected_address,
|
|
42
|
+
derived_address: derived,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=evm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm.js","sourceRoot":"","sources":["../../../src/verify/chains/evm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAExD,SAAS,WAAW,CAAC,OAAmB;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AASD,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,KAAqB;IAC7C,MAAM,MAAM,GAAG,0BAA0B,CAAC;QACxC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtE,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;IAE1C,IAAI,OAAO,KAAK,KAAK,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,IAAI,wBAAwB,CAAC;YACjC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,eAAe,EAAE,KAAK,CAAC,eAAe;YACtC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,eAAe,EAAE,OAAO;SACzB,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polygon PoS verification — shares BIP-44 coin_type=60' with Ethereum
|
|
3
|
+
* (architecture addendum §4.4). Cross-checked byte-for-byte against server-side
|
|
4
|
+
* derivation in apps/web/lib/derivation/evm.ts.
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4, AD-7.
|
|
9
|
+
*/
|
|
10
|
+
export interface VerifyPolygonInput {
|
|
11
|
+
xpub: string;
|
|
12
|
+
derivation_path: string;
|
|
13
|
+
expected_address: string;
|
|
14
|
+
}
|
|
15
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
16
|
+
export declare function verifyPolygon(input: VerifyPolygonInput): void;
|
|
17
|
+
//# sourceMappingURL=polygon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon.d.ts","sourceRoot":"","sources":["../../../src/verify/chains/polygon.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAE7D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polygon PoS verification — shares BIP-44 coin_type=60' with Ethereum
|
|
3
|
+
* (architecture addendum §4.4). Cross-checked byte-for-byte against server-side
|
|
4
|
+
* derivation in apps/web/lib/derivation/evm.ts.
|
|
5
|
+
*
|
|
6
|
+
* Sources:
|
|
7
|
+
* - PRD FR96.
|
|
8
|
+
* - Architecture addendum §4.1, §4.3, §4.4, AD-7.
|
|
9
|
+
*/
|
|
10
|
+
import { verifyEvm } from './evm.js';
|
|
11
|
+
/** Throws AddressVerificationError on mismatch; returns void on success. */
|
|
12
|
+
export function verifyPolygon(input) {
|
|
13
|
+
verifyEvm({ ...input, chain: 'polygon' });
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=polygon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polygon.js","sourceRoot":"","sources":["../../../src/verify/chains/polygon.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAQrC,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,SAAS,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;AAC5C,CAAC"}
|