@obbyx/obyte 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +15 -2
- package/dist/channel/definition.d.ts +38 -0
- package/dist/channel/definition.d.ts.map +1 -0
- package/dist/channel/definition.js +86 -0
- package/dist/channel/definition.js.map +1 -0
- package/dist/config/index.d.ts +31 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +33 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/amounts.d.ts +35 -0
- package/dist/core/amounts.d.ts.map +1 -0
- package/dist/core/amounts.js +94 -0
- package/dist/core/amounts.js.map +1 -0
- package/dist/core/errors.d.ts +16 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +18 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/networks.d.ts +34 -0
- package/dist/core/networks.d.ts.map +1 -0
- package/dist/core/networks.js +50 -0
- package/dist/core/networks.js.map +1 -0
- package/dist/core/result.d.ts +17 -0
- package/dist/core/result.d.ts.map +1 -0
- package/dist/core/result.js +13 -0
- package/dist/core/result.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logger/index.d.ts +76 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +161 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/signing/signed-message.d.ts +47 -0
- package/dist/signing/signed-message.d.ts.map +1 -0
- package/dist/signing/signed-message.js +102 -0
- package/dist/signing/signed-message.js.map +1 -0
- package/dist/unit/exact-unit.d.ts +94 -0
- package/dist/unit/exact-unit.d.ts.map +1 -0
- package/dist/unit/exact-unit.js +334 -0
- package/dist/unit/exact-unit.js.map +1 -0
- package/dist/wallet/index.d.ts +29 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +106 -0
- package/dist/wallet/index.js.map +1 -0
- package/package.json +64 -3
- package/src/channel/definition.ts +114 -0
- package/src/config/index.ts +40 -0
- package/src/core/amounts.ts +116 -0
- package/src/core/errors.ts +22 -0
- package/src/core/networks.ts +81 -0
- package/src/core/result.ts +23 -0
- package/src/index.ts +58 -0
- package/src/logger/index.ts +234 -0
- package/src/signing/signed-message.ts +147 -0
- package/src/types/obyte-internal.d.ts +19 -0
- package/src/unit/exact-unit.ts +388 -0
- package/src/wallet/index.ts +130 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type DestinationStream, type Level, type Logger } from 'pino';
|
|
2
|
+
/**
|
|
3
|
+
* Unified logger for all obbyx packages and apps (plan §7).
|
|
4
|
+
*
|
|
5
|
+
* - Structured JSON (pino), human-readable output in dev via pino-pretty.
|
|
6
|
+
* - Correlation fields (requestId, traceId, binding, proofId, ...) are taken
|
|
7
|
+
* from an AsyncLocalStorage context, so every log line written while a
|
|
8
|
+
* payment is processed carries them automatically — in the seller middleware,
|
|
9
|
+
* the facilitator and the watcher alike.
|
|
10
|
+
* - Sensitive values (signatures, payment packages, signed units, API keys,
|
|
11
|
+
* challenges, private keys) are never written; they are replaced by a short
|
|
12
|
+
* SHA-256 fingerprint so they can still be correlated across logs.
|
|
13
|
+
* - Libraries never call `console`; they receive a Logger via DI and create
|
|
14
|
+
* per-module children with {@link moduleLogger}.
|
|
15
|
+
*/
|
|
16
|
+
export type { Logger, Level } from 'pino';
|
|
17
|
+
export declare const LOG_LEVELS: readonly Level[];
|
|
18
|
+
/** Correlation fields propagated through a payment flow. */
|
|
19
|
+
export interface LogContext {
|
|
20
|
+
requestId?: string;
|
|
21
|
+
traceId?: string;
|
|
22
|
+
binding?: string;
|
|
23
|
+
proofId?: string;
|
|
24
|
+
network?: string;
|
|
25
|
+
scheme?: string;
|
|
26
|
+
x402Version?: number;
|
|
27
|
+
sellerId?: string;
|
|
28
|
+
aa?: string;
|
|
29
|
+
seq?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Runs `fn` with additional correlation fields. Nested calls merge with (and
|
|
33
|
+
* may override) the outer context.
|
|
34
|
+
*/
|
|
35
|
+
export declare function withLogContext<T>(fields: LogContext, fn: () => T): T;
|
|
36
|
+
export declare function getLogContext(): Readonly<LogContext>;
|
|
37
|
+
/**
|
|
38
|
+
* Short, stable fingerprint of a sensitive value: `sha256:<12 hex>`.
|
|
39
|
+
* Use it to log *that* a value was seen without revealing it.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fingerprint(value: unknown): string;
|
|
42
|
+
/**
|
|
43
|
+
* Field names whose values are bearer-sensitive or secret. They are redacted at
|
|
44
|
+
* the top level and up to three levels deep. Naming convention: code that logs
|
|
45
|
+
* such data must use one of these field names (enforced by tests and review).
|
|
46
|
+
*/
|
|
47
|
+
export declare const SENSITIVE_FIELDS: readonly string[];
|
|
48
|
+
export interface CreateLoggerOptions {
|
|
49
|
+
/** Base level. Default: `info`. */
|
|
50
|
+
level?: Level;
|
|
51
|
+
/** Per-module overrides, e.g. `{ 'x402.exact': 'debug', hub: 'trace' }`. */
|
|
52
|
+
moduleLevels?: Readonly<Record<string, Level>>;
|
|
53
|
+
/** Service name written into every line (`service` field). */
|
|
54
|
+
service?: string;
|
|
55
|
+
/** Pretty-print for local development. */
|
|
56
|
+
pretty?: boolean;
|
|
57
|
+
/** Custom destination (tests, files). Ignored when `pretty` is set. */
|
|
58
|
+
destination?: DestinationStream;
|
|
59
|
+
}
|
|
60
|
+
export declare function createLogger(options?: CreateLoggerOptions): Logger;
|
|
61
|
+
/**
|
|
62
|
+
* Child logger for a module (`x402.exact`, `hub`, `watcher.sync`, ...).
|
|
63
|
+
* Applies the most specific per-module level: `x402.exact.verify` inherits a
|
|
64
|
+
* level configured for `x402.exact` or `x402`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function moduleLogger(root: Logger, module: string, bindings?: Record<string, unknown>): Logger;
|
|
67
|
+
export declare function resolveModuleLevel(module: string, levels: Readonly<Record<string, Level>>): Level | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Parses `LOG_LEVELS="x402.exact=debug,hub=trace"`. Invalid entries throw so
|
|
70
|
+
* misconfiguration is visible at startup instead of silently ignored.
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseModuleLevels(spec: string | undefined): Record<string, Level>;
|
|
73
|
+
export declare function isLevel(value: string): value is Level;
|
|
74
|
+
/** Builds a logger from standard env vars: LOG_LEVEL, LOG_LEVELS, LOG_PRETTY. */
|
|
75
|
+
export declare function createLoggerFromEnv(service: string, env?: Readonly<Record<string, string | undefined>>): Logger;
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,iBAAiB,EAAE,KAAK,KAAK,EAAE,KAAK,MAAM,EAAsB,MAAM,MAAM,CAAC;AAEjG;;;;;;;;;;;;;GAaG;AACH,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAE1C,eAAO,MAAM,UAAU,EAAE,SAAS,KAAK,EAAyD,CAAC;AAEjG,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAGpE;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAAC,UAAU,CAAC,CAEpD;AAQD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGlD;AAeD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAmB7C,CAAC;AAqBF,MAAM,WAAW,mBAAmB;IAClC,mCAAmC;IACnC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,4EAA4E;IAC5E,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAID,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAqBtE;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACrC,MAAM,CAMR;AAMD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,GACtC,KAAK,GAAG,SAAS,CAOnB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAWjF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,KAAK,CAErD;AAED,iFAAiF;AACjF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAe,GAC9D,MAAM,CASR"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { pino } from 'pino';
|
|
4
|
+
export const LOG_LEVELS = ['fatal', 'error', 'warn', 'info', 'debug', 'trace'];
|
|
5
|
+
const contextStorage = new AsyncLocalStorage();
|
|
6
|
+
/**
|
|
7
|
+
* Runs `fn` with additional correlation fields. Nested calls merge with (and
|
|
8
|
+
* may override) the outer context.
|
|
9
|
+
*/
|
|
10
|
+
export function withLogContext(fields, fn) {
|
|
11
|
+
const parent = contextStorage.getStore();
|
|
12
|
+
return contextStorage.run(Object.freeze({ ...parent, ...stripUndefined(fields) }), fn);
|
|
13
|
+
}
|
|
14
|
+
export function getLogContext() {
|
|
15
|
+
return contextStorage.getStore() ?? {};
|
|
16
|
+
}
|
|
17
|
+
function stripUndefined(fields) {
|
|
18
|
+
return Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Short, stable fingerprint of a sensitive value: `sha256:<12 hex>`.
|
|
22
|
+
* Use it to log *that* a value was seen without revealing it.
|
|
23
|
+
*/
|
|
24
|
+
export function fingerprint(value) {
|
|
25
|
+
const text = typeof value === 'string' ? value : stableStringify(value);
|
|
26
|
+
return `sha256:${createHash('sha256').update(text).digest('hex').slice(0, 12)}`;
|
|
27
|
+
}
|
|
28
|
+
function stableStringify(value) {
|
|
29
|
+
if (value === undefined)
|
|
30
|
+
return 'undefined';
|
|
31
|
+
return JSON.stringify(value, (_key, v) => {
|
|
32
|
+
if (typeof v === 'bigint')
|
|
33
|
+
return v.toString();
|
|
34
|
+
if (v && typeof v === 'object' && !Array.isArray(v)) {
|
|
35
|
+
return Object.fromEntries(Object.entries(v).sort(([a], [b]) => a.localeCompare(b)));
|
|
36
|
+
}
|
|
37
|
+
return v;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Field names whose values are bearer-sensitive or secret. They are redacted at
|
|
42
|
+
* the top level and up to three levels deep. Naming convention: code that logs
|
|
43
|
+
* such data must use one of these field names (enforced by tests and review).
|
|
44
|
+
*/
|
|
45
|
+
export const SENSITIVE_FIELDS = [
|
|
46
|
+
'authentifiers',
|
|
47
|
+
'signedPackage',
|
|
48
|
+
'signed_package',
|
|
49
|
+
'sentByPeer',
|
|
50
|
+
'paymentPayload',
|
|
51
|
+
'paymentSignature',
|
|
52
|
+
'xPayment',
|
|
53
|
+
'joint',
|
|
54
|
+
'signedUnit',
|
|
55
|
+
'apiKey',
|
|
56
|
+
'authorization',
|
|
57
|
+
'cookie',
|
|
58
|
+
'challengeSignature',
|
|
59
|
+
'privateKey',
|
|
60
|
+
'mnemonic',
|
|
61
|
+
'seed',
|
|
62
|
+
'password',
|
|
63
|
+
'secret',
|
|
64
|
+
];
|
|
65
|
+
const SENSITIVE_HEADERS = [
|
|
66
|
+
'payment-signature',
|
|
67
|
+
'x-payment',
|
|
68
|
+
'authorization',
|
|
69
|
+
'cookie',
|
|
70
|
+
'x-api-key',
|
|
71
|
+
];
|
|
72
|
+
function redactPaths() {
|
|
73
|
+
const paths = [];
|
|
74
|
+
for (const field of SENSITIVE_FIELDS) {
|
|
75
|
+
paths.push(field, `*.${field}`, `*.*.${field}`, `*.*.*.${field}`);
|
|
76
|
+
}
|
|
77
|
+
for (const header of SENSITIVE_HEADERS) {
|
|
78
|
+
paths.push(`headers["${header}"]`, `*.headers["${header}"]`);
|
|
79
|
+
}
|
|
80
|
+
return paths;
|
|
81
|
+
}
|
|
82
|
+
const moduleLevelsByLogger = new WeakMap();
|
|
83
|
+
export function createLogger(options = {}) {
|
|
84
|
+
const pinoOptions = {
|
|
85
|
+
level: options.level ?? 'info',
|
|
86
|
+
base: options.service === undefined ? {} : { service: options.service },
|
|
87
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
88
|
+
messageKey: 'msg',
|
|
89
|
+
formatters: { level: (label) => ({ level: label }) },
|
|
90
|
+
redact: { paths: redactPaths(), censor: (value) => redacted(value) },
|
|
91
|
+
serializers: { err: pino.stdSerializers.err },
|
|
92
|
+
mixin: () => ({ ...getLogContext() }),
|
|
93
|
+
};
|
|
94
|
+
const logger = options.pretty === true
|
|
95
|
+
? pino({ ...pinoOptions, transport: { target: 'pino-pretty', options: { colorize: true } } })
|
|
96
|
+
: options.destination === undefined
|
|
97
|
+
? pino(pinoOptions)
|
|
98
|
+
: pino(pinoOptions, options.destination);
|
|
99
|
+
moduleLevelsByLogger.set(logger, options.moduleLevels ?? {});
|
|
100
|
+
return logger;
|
|
101
|
+
}
|
|
102
|
+
function redacted(value) {
|
|
103
|
+
return value === undefined || value === null ? '[redacted]' : `[redacted ${fingerprint(value)}]`;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Child logger for a module (`x402.exact`, `hub`, `watcher.sync`, ...).
|
|
107
|
+
* Applies the most specific per-module level: `x402.exact.verify` inherits a
|
|
108
|
+
* level configured for `x402.exact` or `x402`.
|
|
109
|
+
*/
|
|
110
|
+
export function moduleLogger(root, module, bindings = {}) {
|
|
111
|
+
const levels = findModuleLevels(root);
|
|
112
|
+
const level = resolveModuleLevel(module, levels);
|
|
113
|
+
const child = root.child({ module, ...bindings }, level === undefined ? {} : { level });
|
|
114
|
+
moduleLevelsByLogger.set(child, levels);
|
|
115
|
+
return child;
|
|
116
|
+
}
|
|
117
|
+
function findModuleLevels(logger) {
|
|
118
|
+
return moduleLevelsByLogger.get(logger) ?? {};
|
|
119
|
+
}
|
|
120
|
+
export function resolveModuleLevel(module, levels) {
|
|
121
|
+
const parts = module.split('.');
|
|
122
|
+
for (let i = parts.length; i > 0; i--) {
|
|
123
|
+
const level = levels[parts.slice(0, i).join('.')];
|
|
124
|
+
if (level !== undefined)
|
|
125
|
+
return level;
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parses `LOG_LEVELS="x402.exact=debug,hub=trace"`. Invalid entries throw so
|
|
131
|
+
* misconfiguration is visible at startup instead of silently ignored.
|
|
132
|
+
*/
|
|
133
|
+
export function parseModuleLevels(spec) {
|
|
134
|
+
const result = {};
|
|
135
|
+
if (spec === undefined || spec.trim() === '')
|
|
136
|
+
return result;
|
|
137
|
+
for (const entry of spec.split(',')) {
|
|
138
|
+
const [module, level] = entry.split('=').map((s) => s.trim());
|
|
139
|
+
if (!module || !level || !isLevel(level)) {
|
|
140
|
+
throw new Error(`Invalid LOG_LEVELS entry "${entry}" (expected module=level)`);
|
|
141
|
+
}
|
|
142
|
+
result[module] = level;
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
export function isLevel(value) {
|
|
147
|
+
return LOG_LEVELS.includes(value);
|
|
148
|
+
}
|
|
149
|
+
/** Builds a logger from standard env vars: LOG_LEVEL, LOG_LEVELS, LOG_PRETTY. */
|
|
150
|
+
export function createLoggerFromEnv(service, env = process.env) {
|
|
151
|
+
const level = env['LOG_LEVEL'] ?? 'info';
|
|
152
|
+
if (!isLevel(level))
|
|
153
|
+
throw new Error(`Invalid LOG_LEVEL "${level}"`);
|
|
154
|
+
return createLogger({
|
|
155
|
+
service,
|
|
156
|
+
level,
|
|
157
|
+
moduleLevels: parseModuleLevels(env['LOG_LEVELS']),
|
|
158
|
+
pretty: env['LOG_PRETTY'] === '1' || env['LOG_PRETTY'] === 'true',
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/logger/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ObyteNetwork } from '../core/networks.js';
|
|
2
|
+
import { type Verdict } from '../core/result.js';
|
|
3
|
+
/**
|
|
4
|
+
* Obyte signed messages ("signed packages") as used by AA payment channels.
|
|
5
|
+
*
|
|
6
|
+
* Supported profile (same as aa-channels-lib's light verifier, plus network
|
|
7
|
+
* binding): exactly one author, an embedded `['sig', {pubkey}]` definition
|
|
8
|
+
* whose chash equals the author address, signature under path `r`, and a
|
|
9
|
+
* `version` that belongs to the expected network (testnet versions end in
|
|
10
|
+
* `t`) — so a package can never be accepted on the other network (I4).
|
|
11
|
+
*
|
|
12
|
+
* Packages are signed with obyte.js directly:
|
|
13
|
+
* `obyte.utils.signMessage(message, { privateKey, testnet })`.
|
|
14
|
+
*/
|
|
15
|
+
export type SigDefinition = readonly ['sig', {
|
|
16
|
+
readonly pubkey: string;
|
|
17
|
+
}];
|
|
18
|
+
export interface SignedPackage<M = unknown> {
|
|
19
|
+
version: string;
|
|
20
|
+
signed_message: M;
|
|
21
|
+
authors: [
|
|
22
|
+
{
|
|
23
|
+
address: string;
|
|
24
|
+
definition: SigDefinition;
|
|
25
|
+
authentifiers: {
|
|
26
|
+
r: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
export interface VerifiedPackage<M = unknown> {
|
|
32
|
+
readonly signer: string;
|
|
33
|
+
readonly pubkey: string;
|
|
34
|
+
readonly message: M;
|
|
35
|
+
}
|
|
36
|
+
export declare const SIGNED_PACKAGE_VERSIONS: {
|
|
37
|
+
readonly livenet: readonly ["1.0", "2.0", "3.0", "4.0"];
|
|
38
|
+
readonly testnet: readonly ["1.0t", "2.0t", "3.0t", "4.0t"];
|
|
39
|
+
};
|
|
40
|
+
export declare function verifySignedPackage<M = unknown>(pkg: unknown, options: {
|
|
41
|
+
network: ObyteNetwork;
|
|
42
|
+
expectedSigner?: string;
|
|
43
|
+
}): Verdict<VerifiedPackage<M>>;
|
|
44
|
+
export declare function isSigDefinition(value: unknown): value is SigDefinition;
|
|
45
|
+
/** secp256k1 verification that never throws on malformed input. */
|
|
46
|
+
export declare function verifySignature(hash: Uint8Array, signature: unknown, pubkey: string): boolean;
|
|
47
|
+
//# sourceMappingURL=signed-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-message.d.ts","sourceRoot":"","sources":["../../src/signing/signed-message.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,OAAO,EAA8C,MAAM,mBAAmB,CAAC;AAE7F;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1E,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE;QACP;YACE,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,EAAE,aAAa,CAAC;YAC1B,aAAa,EAAE;gBAAE,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC;SAC9B;KACF,CAAC;CACH;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;CACrB;AAED,eAAO,MAAM,uBAAuB;;;CAG1B,CAAC;AAWX,wBAAgB,mBAAmB,CAAC,CAAC,GAAG,OAAO,EAC7C,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAkE7B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAStE;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAO7F"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Ambient types for obyte.js internals; a reference (not tsconfig "include") so that
|
|
2
|
+
// workspace packages compiling these sources via the @obbyx/source condition see them.
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
|
4
|
+
/// <reference path="../types/obyte-internal.d.ts" />
|
|
5
|
+
import obyte from 'obyte';
|
|
6
|
+
import { getSignedPackageHashToSign, verify } from 'obyte/lib/internal.js';
|
|
7
|
+
import { isAddress } from '../channel/definition.js';
|
|
8
|
+
import { accept, hasOnlyKeys, isPlainObject, reject } from '../core/result.js';
|
|
9
|
+
export const SIGNED_PACKAGE_VERSIONS = {
|
|
10
|
+
livenet: ['1.0', '2.0', '3.0', '4.0'],
|
|
11
|
+
testnet: ['1.0t', '2.0t', '3.0t', '4.0t'],
|
|
12
|
+
};
|
|
13
|
+
const PACKAGE_KEYS = new Set([
|
|
14
|
+
'signed_message',
|
|
15
|
+
'authors',
|
|
16
|
+
'last_ball_unit',
|
|
17
|
+
'timestamp',
|
|
18
|
+
'version',
|
|
19
|
+
]);
|
|
20
|
+
const AUTHOR_KEYS = new Set(['address', 'definition', 'authentifiers']);
|
|
21
|
+
export function verifySignedPackage(pkg, options) {
|
|
22
|
+
if (!isPlainObject(pkg))
|
|
23
|
+
return reject('invalid_signed_package', 'Package must be an object');
|
|
24
|
+
if (!hasOnlyKeys(pkg, PACKAGE_KEYS)) {
|
|
25
|
+
return reject('invalid_signed_package', 'Package has unexpected fields');
|
|
26
|
+
}
|
|
27
|
+
if (!('signed_message' in pkg)) {
|
|
28
|
+
return reject('invalid_signed_package', 'Package has no signed_message');
|
|
29
|
+
}
|
|
30
|
+
const versions = SIGNED_PACKAGE_VERSIONS[options.network.name];
|
|
31
|
+
if (typeof pkg['version'] !== 'string' || !versions.includes(pkg['version'])) {
|
|
32
|
+
return reject('invalid_signed_package_network', `Package version is not valid for ${options.network.caip2}`);
|
|
33
|
+
}
|
|
34
|
+
const authors = pkg['authors'];
|
|
35
|
+
if (!Array.isArray(authors) || authors.length !== 1) {
|
|
36
|
+
return reject('invalid_signed_package', 'Package must have exactly one author');
|
|
37
|
+
}
|
|
38
|
+
const author = authors[0];
|
|
39
|
+
if (!isPlainObject(author) || !hasOnlyKeys(author, AUTHOR_KEYS)) {
|
|
40
|
+
return reject('invalid_signed_package', 'Malformed author');
|
|
41
|
+
}
|
|
42
|
+
const address = author['address'];
|
|
43
|
+
if (!isAddress(address))
|
|
44
|
+
return reject('invalid_signed_package', 'Invalid author address');
|
|
45
|
+
if (options.expectedSigner !== undefined && address !== options.expectedSigner) {
|
|
46
|
+
return reject('invalid_signed_package_signer', 'Package is signed by an unexpected address');
|
|
47
|
+
}
|
|
48
|
+
const definition = author['definition'];
|
|
49
|
+
if (!isSigDefinition(definition)) {
|
|
50
|
+
return reject('invalid_signed_package_definition', "Only ['sig', {pubkey}] definitions are supported");
|
|
51
|
+
}
|
|
52
|
+
let chash;
|
|
53
|
+
try {
|
|
54
|
+
chash = obyte.utils.getChash160([...definition]);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return reject('invalid_signed_package_definition', 'Definition cannot be hashed');
|
|
58
|
+
}
|
|
59
|
+
if (chash !== address) {
|
|
60
|
+
return reject('invalid_signed_package_definition', 'Definition does not match author address');
|
|
61
|
+
}
|
|
62
|
+
const authentifiers = author['authentifiers'];
|
|
63
|
+
if (!isPlainObject(authentifiers) || Object.keys(authentifiers).length !== 1) {
|
|
64
|
+
return reject('invalid_signed_package_signature', 'Expected a single authentifier "r"');
|
|
65
|
+
}
|
|
66
|
+
let hash;
|
|
67
|
+
try {
|
|
68
|
+
hash = getSignedPackageHashToSign(pkg);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return reject('invalid_signed_package', 'Package cannot be hashed');
|
|
72
|
+
}
|
|
73
|
+
if (!verifySignature(hash, authentifiers['r'], definition[1].pubkey)) {
|
|
74
|
+
return reject('invalid_signed_package_signature', 'Signature is invalid');
|
|
75
|
+
}
|
|
76
|
+
return accept({
|
|
77
|
+
signer: address,
|
|
78
|
+
pubkey: definition[1].pubkey,
|
|
79
|
+
message: pkg['signed_message'],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function isSigDefinition(value) {
|
|
83
|
+
if (!Array.isArray(value) || value.length !== 2 || value[0] !== 'sig')
|
|
84
|
+
return false;
|
|
85
|
+
const params = value[1];
|
|
86
|
+
return (isPlainObject(params) &&
|
|
87
|
+
Object.keys(params).length === 1 &&
|
|
88
|
+
typeof params['pubkey'] === 'string' &&
|
|
89
|
+
params['pubkey'].length === 44);
|
|
90
|
+
}
|
|
91
|
+
/** secp256k1 verification that never throws on malformed input. */
|
|
92
|
+
export function verifySignature(hash, signature, pubkey) {
|
|
93
|
+
if (typeof signature !== 'string')
|
|
94
|
+
return false;
|
|
95
|
+
try {
|
|
96
|
+
return verify(hash, signature, pubkey);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=signed-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signed-message.js","sourceRoot":"","sources":["../../src/signing/signed-message.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ObyteNetwork } from '../core/networks.js';
|
|
2
|
+
import { type Verdict } from '../core/result.js';
|
|
3
|
+
import { type SigDefinition } from '../signing/signed-message.js';
|
|
4
|
+
/**
|
|
5
|
+
* Local (ledger-independent) validation of a client-signed unit for the x402
|
|
6
|
+
* `exact` scheme — the supported profile of ADR-0002.
|
|
7
|
+
*
|
|
8
|
+
* Checks done here need no hub: structure, network, unit hash, payload hashes,
|
|
9
|
+
* author definition and signature, commissions, message set, outputs and the
|
|
10
|
+
* signed binding. Ledger checks (inputs unspent, last ball recency, author
|
|
11
|
+
* definition when not embedded) are performed by the facilitator with a
|
|
12
|
+
* LedgerPort using {@link ExactUnitFacts}.
|
|
13
|
+
*
|
|
14
|
+
* Anything outside the profile is rejected; the profile is deliberately narrow.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EXACT_REASONS: {
|
|
17
|
+
readonly unsupported: "invalid_exact_obyte_unsupported_unit";
|
|
18
|
+
readonly tooLarge: "invalid_exact_obyte_unit_too_large";
|
|
19
|
+
readonly network: "invalid_exact_obyte_network";
|
|
20
|
+
readonly unitHash: "invalid_exact_obyte_unit_hash";
|
|
21
|
+
readonly payloadHash: "invalid_exact_obyte_payload_hash";
|
|
22
|
+
readonly definition: "invalid_exact_obyte_definition";
|
|
23
|
+
readonly definitionRequired: "invalid_exact_obyte_definition_required";
|
|
24
|
+
readonly signature: "invalid_exact_obyte_signature";
|
|
25
|
+
readonly commissions: "invalid_exact_obyte_commissions";
|
|
26
|
+
readonly recipient: "invalid_exact_obyte_recipient_mismatch";
|
|
27
|
+
readonly amount: "invalid_exact_obyte_amount_mismatch";
|
|
28
|
+
readonly asset: "invalid_exact_obyte_asset_mismatch";
|
|
29
|
+
readonly binding: "invalid_exact_obyte_binding_mismatch";
|
|
30
|
+
readonly payer: "invalid_exact_obyte_payer";
|
|
31
|
+
};
|
|
32
|
+
/** Only current unit versions are accepted. */
|
|
33
|
+
export declare const EXACT_UNIT_VERSIONS: {
|
|
34
|
+
readonly livenet: "4.0";
|
|
35
|
+
readonly testnet: "4.0t";
|
|
36
|
+
};
|
|
37
|
+
export declare const DEFAULT_MAX_UNIT_BYTES: number;
|
|
38
|
+
export interface ExactExpectation {
|
|
39
|
+
readonly network: ObyteNetwork;
|
|
40
|
+
readonly payTo: string;
|
|
41
|
+
/** `'base'` or asset id; must be allowlisted by the caller beforehand. */
|
|
42
|
+
readonly asset: string;
|
|
43
|
+
readonly amount: bigint;
|
|
44
|
+
readonly binding: string;
|
|
45
|
+
readonly quoteId: string;
|
|
46
|
+
/** Facilitator's own addresses: they must never be the payer. */
|
|
47
|
+
readonly facilitatorAddresses?: readonly string[];
|
|
48
|
+
readonly maxUnitBytes?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface InputRef {
|
|
51
|
+
readonly asset: string;
|
|
52
|
+
readonly unit: string;
|
|
53
|
+
readonly messageIndex: number;
|
|
54
|
+
readonly outputIndex: number;
|
|
55
|
+
}
|
|
56
|
+
export interface ExactUnitFacts {
|
|
57
|
+
readonly unitHash: string;
|
|
58
|
+
readonly payer: string;
|
|
59
|
+
readonly inputs: readonly InputRef[];
|
|
60
|
+
readonly lastBallUnit: string;
|
|
61
|
+
readonly parentUnits: readonly string[];
|
|
62
|
+
readonly timestamp: number;
|
|
63
|
+
/** Sum of outputs per asset ('base' for bytes), used to check inputs balance. */
|
|
64
|
+
readonly outputTotals: Readonly<Record<string, bigint>>;
|
|
65
|
+
readonly commissions: {
|
|
66
|
+
readonly headers: number;
|
|
67
|
+
readonly payload: number;
|
|
68
|
+
};
|
|
69
|
+
/** True when the author definition was not embedded and came from the caller. */
|
|
70
|
+
readonly definitionFromLedger: boolean;
|
|
71
|
+
}
|
|
72
|
+
export declare function validateExactUnit(unit: unknown, expect: ExactExpectation, options?: {
|
|
73
|
+
authorDefinition?: SigDefinition;
|
|
74
|
+
}): Verdict<ExactUnitFacts>;
|
|
75
|
+
/**
|
|
76
|
+
* Commissions ocore expects for an already SIGNED single-author unit (v4,
|
|
77
|
+
* sizes counted with keys). obyte.js `getHeadersSize` is meant for the
|
|
78
|
+
* unsigned unit during compose (authentifiers hold a path placeholder) and
|
|
79
|
+
* adds SIGNATURE_SIZE itself; on a signed unit the real signature is already
|
|
80
|
+
* counted, so it is subtracted. Verified against testnet unit DxPSVW8p…
|
|
81
|
+
* (headers 452, payload 432).
|
|
82
|
+
*/
|
|
83
|
+
export declare function expectedCommissions(unit: object): {
|
|
84
|
+
headers: number;
|
|
85
|
+
payload: number;
|
|
86
|
+
};
|
|
87
|
+
export declare function compareOutputs(a: {
|
|
88
|
+
address: string;
|
|
89
|
+
amount: number;
|
|
90
|
+
}, b: {
|
|
91
|
+
address: string;
|
|
92
|
+
amount: number;
|
|
93
|
+
}): number;
|
|
94
|
+
//# sourceMappingURL=exact-unit.d.ts.map
|
|
@@ -0,0 +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"}
|