@4mica/sdk 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/auth.js +29 -77
- package/dist/bls.d.ts +1 -0
- package/dist/bls.js +190 -12
- package/dist/chain.d.ts +2 -0
- package/dist/chain.js +26 -0
- package/dist/client/index.d.ts +24 -0
- package/dist/client/index.js +71 -0
- package/dist/client/recipient.d.ts +24 -0
- package/dist/client/recipient.js +132 -0
- package/dist/client/shared.d.ts +11 -0
- package/dist/client/shared.js +17 -0
- package/dist/client/user.d.ts +17 -0
- package/dist/client/user.js +74 -0
- package/dist/client.js +24 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +7 -0
- package/dist/contract.d.ts +12 -8
- package/dist/contract.js +18 -40
- package/dist/debug.d.ts +2 -0
- package/dist/debug.js +5 -0
- package/dist/guarantee.js +26 -4
- package/dist/http.d.ts +11 -0
- package/dist/http.js +57 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/models.d.ts +1 -4
- package/dist/models.js +20 -25
- package/dist/payment.d.ts +19 -0
- package/dist/payment.js +32 -0
- package/dist/rpc.d.ts +5 -5
- package/dist/rpc.js +18 -38
- package/dist/serde.d.ts +5 -0
- package/dist/serde.js +33 -0
- package/dist/signing.js +5 -5
- package/dist/x402/index.d.ts +1 -1
- package/dist/x402/index.js +20 -18
- package/dist/x402/models.d.ts +4 -16
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -38,9 +38,9 @@ The SDK requires a signing key and can use sensible defaults for the rest:
|
|
|
38
38
|
- `authUrl` and `authRefreshMarginSecs` (optional): SIWE auth config. Only used when auth is
|
|
39
39
|
enabled via `enableAuth()` or by setting either value (defaults to `rpcUrl` and 60 seconds).
|
|
40
40
|
|
|
41
|
-
> Note: `ethereumHttpRpcUrl` and `contractAddress` are fetched from the core service
|
|
42
|
-
>
|
|
43
|
-
> different values than the server defaults.
|
|
41
|
+
> Note: `ethereumHttpRpcUrl` and `contractAddress` are fetched from the core service by default.
|
|
42
|
+
> The SDK validates the connected chain ID but does not verify the contract address or code. Only
|
|
43
|
+
> override these if you need to use different values than the server defaults.
|
|
44
44
|
|
|
45
45
|
### 1) Using ConfigBuilder
|
|
46
46
|
|
|
@@ -153,6 +153,7 @@ X-PAYMENT header (and optional `/settle` call) that the facilitator will accept.
|
|
|
153
153
|
|
|
154
154
|
At minimum you need:
|
|
155
155
|
- `scheme` and `network` (scheme must include `4mica`, e.g. `4mica-credit`)
|
|
156
|
+
- `payTo` (recipient address), `asset`, and `maxAmountRequired` (v1) or `amount` (v2)
|
|
156
157
|
- `extra.tabEndpoint` for tab resolution
|
|
157
158
|
|
|
158
159
|
`X402Flow` will refresh the tab by calling `extra.tabEndpoint` before signing.
|
|
@@ -258,6 +259,7 @@ Notes:
|
|
|
258
259
|
- `signPayment` and `signPaymentV2` always use EIP-712 signing and will error if the scheme is not 4mica.
|
|
259
260
|
- `UserClient.signPayment` supports `SigningScheme.EIP712` (default) and `SigningScheme.EIP191`.
|
|
260
261
|
- `settlePayment` only hits `/settle`; resource servers should still call `/verify` first when enforcing access.
|
|
262
|
+
- `RecipientClient.remunerate` requires the optional `@noble/curves` dependency for BLS decoding.
|
|
261
263
|
|
|
262
264
|
### API Methods Summary
|
|
263
265
|
|
|
@@ -303,8 +305,7 @@ Available under `client.rpc` (requires an admin API key):
|
|
|
303
305
|
## Error Handling
|
|
304
306
|
|
|
305
307
|
All SDK errors extend `FourMicaError`. Common error types include `ConfigError`, `RpcError`,
|
|
306
|
-
`
|
|
307
|
-
`AuthError`.
|
|
308
|
+
`SigningError`, `VerificationError`, `X402Error`, and `AuthError`.
|
|
308
309
|
|
|
309
310
|
## License
|
|
310
311
|
|
package/dist/auth.js
CHANGED
|
@@ -2,48 +2,32 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AuthSession = exports.AuthClient = void 0;
|
|
4
4
|
exports.buildSiweMessage = buildSiweMessage;
|
|
5
|
+
const http_1 = require("./http");
|
|
5
6
|
const errors_1 = require("./errors");
|
|
6
7
|
const utils_1 = require("./utils");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
if (typeof value === 'string' && value.trim()) {
|
|
10
|
-
return value;
|
|
11
|
-
}
|
|
12
|
-
throw new errors_1.AuthDecodeError(`invalid auth response: missing ${label}`);
|
|
13
|
-
};
|
|
14
|
-
const readNumber = (value, label) => {
|
|
15
|
-
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
16
|
-
return value;
|
|
17
|
-
}
|
|
18
|
-
if (typeof value === 'string' && value.trim()) {
|
|
19
|
-
const parsed = Number(value);
|
|
20
|
-
if (Number.isFinite(parsed)) {
|
|
21
|
-
return parsed;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
throw new errors_1.AuthDecodeError(`invalid auth response: missing ${label}`);
|
|
25
|
-
};
|
|
8
|
+
const serde_1 = require("./serde");
|
|
9
|
+
const missingField = (label) => new errors_1.AuthDecodeError(`invalid auth response: missing ${label}`);
|
|
26
10
|
const parseTokens = (payload) => {
|
|
27
|
-
const accessToken = readString(payload.access_token ?? payload.accessToken, 'access_token');
|
|
28
|
-
const refreshToken = readString(payload.refresh_token ?? payload.refreshToken, 'refresh_token');
|
|
29
|
-
const expiresIn = readNumber(payload.expires_in ?? payload.expiresIn, 'expires_in');
|
|
11
|
+
const accessToken = (0, serde_1.readString)(payload.access_token ?? payload.accessToken, 'access_token', missingField);
|
|
12
|
+
const refreshToken = (0, serde_1.readString)(payload.refresh_token ?? payload.refreshToken, 'refresh_token', missingField);
|
|
13
|
+
const expiresIn = (0, serde_1.readNumber)(payload.expires_in ?? payload.expiresIn, 'expires_in', missingField);
|
|
30
14
|
return { accessToken, refreshToken, expiresIn };
|
|
31
15
|
};
|
|
32
16
|
const parseSiweTemplate = (payload) => {
|
|
33
|
-
const domain = readString(payload.domain, 'siwe.domain');
|
|
34
|
-
const uri = readString(payload.uri, 'siwe.uri');
|
|
35
|
-
const chainId = readNumber(payload.chain_id ?? payload.chainId, 'siwe.chain_id');
|
|
36
|
-
const statement = readString(payload.statement, 'siwe.statement');
|
|
37
|
-
const expiration = readString(payload.expiration, 'siwe.expiration');
|
|
38
|
-
const issuedAt = readString(payload.issued_at ?? payload.issuedAt, 'siwe.issued_at');
|
|
17
|
+
const domain = (0, serde_1.readString)(payload.domain, 'siwe.domain', missingField);
|
|
18
|
+
const uri = (0, serde_1.readString)(payload.uri, 'siwe.uri', missingField);
|
|
19
|
+
const chainId = (0, serde_1.readNumber)(payload.chain_id ?? payload.chainId, 'siwe.chain_id', missingField);
|
|
20
|
+
const statement = (0, serde_1.readString)(payload.statement, 'siwe.statement', missingField);
|
|
21
|
+
const expiration = (0, serde_1.readString)(payload.expiration, 'siwe.expiration', missingField);
|
|
22
|
+
const issuedAt = (0, serde_1.readString)(payload.issued_at ?? payload.issuedAt, 'siwe.issued_at', missingField);
|
|
39
23
|
return { domain, uri, chainId, statement, expiration, issuedAt };
|
|
40
24
|
};
|
|
41
25
|
const parseNonceResponse = (payload) => {
|
|
42
|
-
if (!isRecord(payload)) {
|
|
26
|
+
if (!(0, serde_1.isRecord)(payload)) {
|
|
43
27
|
throw new errors_1.AuthDecodeError('invalid auth response: nonce payload');
|
|
44
28
|
}
|
|
45
|
-
const nonce = readString(payload.nonce, 'nonce');
|
|
46
|
-
if (!isRecord(payload.siwe)) {
|
|
29
|
+
const nonce = (0, serde_1.readString)(payload.nonce, 'nonce', missingField);
|
|
30
|
+
if (!(0, serde_1.isRecord)(payload.siwe)) {
|
|
47
31
|
throw new errors_1.AuthDecodeError('invalid auth response: missing siwe template');
|
|
48
32
|
}
|
|
49
33
|
return { nonce, siwe: parseSiweTemplate(payload.siwe) };
|
|
@@ -58,7 +42,7 @@ class AuthClient {
|
|
|
58
42
|
constructor(endpoint, fetchFn = fetch) {
|
|
59
43
|
try {
|
|
60
44
|
const validated = (0, utils_1.validateUrl)(endpoint);
|
|
61
|
-
this.baseUrl =
|
|
45
|
+
this.baseUrl = (0, http_1.normalizeBaseUrl)(validated);
|
|
62
46
|
}
|
|
63
47
|
catch (err) {
|
|
64
48
|
if (err instanceof utils_1.ValidationError) {
|
|
@@ -74,14 +58,14 @@ class AuthClient {
|
|
|
74
58
|
}
|
|
75
59
|
async verify(address, message, signature) {
|
|
76
60
|
const payload = await this.post('/auth/verify', { address, message, signature });
|
|
77
|
-
if (!isRecord(payload)) {
|
|
61
|
+
if (!(0, serde_1.isRecord)(payload)) {
|
|
78
62
|
throw new errors_1.AuthDecodeError('invalid auth response: verify payload');
|
|
79
63
|
}
|
|
80
64
|
return parseTokens(payload);
|
|
81
65
|
}
|
|
82
66
|
async refresh(refreshToken) {
|
|
83
67
|
const payload = await this.post('/auth/refresh', { refresh_token: refreshToken });
|
|
84
|
-
if (!isRecord(payload)) {
|
|
68
|
+
if (!(0, serde_1.isRecord)(payload)) {
|
|
85
69
|
throw new errors_1.AuthDecodeError('invalid auth response: refresh payload');
|
|
86
70
|
}
|
|
87
71
|
return parseTokens(payload);
|
|
@@ -97,54 +81,22 @@ class AuthClient {
|
|
|
97
81
|
});
|
|
98
82
|
}
|
|
99
83
|
async request(path, init) {
|
|
100
|
-
let response;
|
|
101
84
|
try {
|
|
102
|
-
|
|
85
|
+
return await (0, http_1.requestJson)(this.fetchFn, `${this.baseUrl}${path}`, init, {
|
|
86
|
+
decodeError: (message) => new errors_1.AuthDecodeError(message),
|
|
87
|
+
httpError: (message, response, body) => new errors_1.AuthApiError(message, {
|
|
88
|
+
status: response.status,
|
|
89
|
+
body,
|
|
90
|
+
}),
|
|
91
|
+
allowEmptyOk: true,
|
|
92
|
+
});
|
|
103
93
|
}
|
|
104
94
|
catch (err) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
let text;
|
|
108
|
-
try {
|
|
109
|
-
text = await response.text();
|
|
110
|
-
}
|
|
111
|
-
catch (err) {
|
|
112
|
-
throw new errors_1.AuthDecodeError(`invalid response from ${response.url}: ${String(err)}`);
|
|
113
|
-
}
|
|
114
|
-
let payload = text;
|
|
115
|
-
if (text) {
|
|
116
|
-
try {
|
|
117
|
-
payload = JSON.parse(text);
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
if (response.ok) {
|
|
121
|
-
throw new errors_1.AuthDecodeError(`invalid JSON response from ${response.url}: ${String(err)}`);
|
|
122
|
-
}
|
|
95
|
+
if (err instanceof errors_1.AuthError) {
|
|
96
|
+
throw err;
|
|
123
97
|
}
|
|
98
|
+
throw new errors_1.AuthTransportError(`auth request failed: ${String(err)}`);
|
|
124
99
|
}
|
|
125
|
-
else {
|
|
126
|
-
payload = null;
|
|
127
|
-
}
|
|
128
|
-
if (response.ok) {
|
|
129
|
-
return payload;
|
|
130
|
-
}
|
|
131
|
-
let message = 'unknown error';
|
|
132
|
-
if (payload && typeof payload === 'object') {
|
|
133
|
-
const record = payload;
|
|
134
|
-
const error = record.error;
|
|
135
|
-
const msg = record.message;
|
|
136
|
-
message =
|
|
137
|
-
(typeof error === 'string' && error) ||
|
|
138
|
-
(typeof msg === 'string' && msg) ||
|
|
139
|
-
JSON.stringify(record, (_k, v) => v);
|
|
140
|
-
}
|
|
141
|
-
else if (typeof payload === 'string' && payload.trim()) {
|
|
142
|
-
message = payload.trim();
|
|
143
|
-
}
|
|
144
|
-
throw new errors_1.AuthApiError(`${response.status}: ${message}`, {
|
|
145
|
-
status: response.status,
|
|
146
|
-
body: payload,
|
|
147
|
-
});
|
|
148
100
|
}
|
|
149
101
|
}
|
|
150
102
|
exports.AuthClient = AuthClient;
|
package/dist/bls.d.ts
CHANGED
package/dist/bls.js
CHANGED
|
@@ -1,8 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.signatureToWords = signatureToWords;
|
|
37
|
+
exports.signatureToWordsAsync = signatureToWordsAsync;
|
|
4
38
|
const viem_1 = require("viem");
|
|
39
|
+
const debug_1 = require("./debug");
|
|
5
40
|
const errors_1 = require("./errors");
|
|
41
|
+
let curvesCache = null;
|
|
42
|
+
let curvesPromise = null;
|
|
6
43
|
function splitFp(value) {
|
|
7
44
|
const be48 = value.toString(16).padStart(96, '0');
|
|
8
45
|
const bytes = (0, viem_1.toBytes)(`0x${be48}`);
|
|
@@ -11,20 +48,114 @@ function splitFp(value) {
|
|
|
11
48
|
const lo = bytes.slice(16);
|
|
12
49
|
return [hi, lo];
|
|
13
50
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
51
|
+
const normalizeBlsImportError = (err) => {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
if (message.includes('ERR_PACKAGE_PATH_NOT_EXPORTED')) {
|
|
54
|
+
return new errors_1.VerificationError('BLS decoding requires @noble/curves; use the .js subpath (bls12-381.js) or update the SDK.');
|
|
55
|
+
}
|
|
56
|
+
if (message.includes('ERR_REQUIRE_ESM') || message.includes('require() of ES Module')) {
|
|
57
|
+
return new errors_1.VerificationError('BLS decoding requires @noble/curves; ESM install detected. Use signatureToWordsAsync or run in CJS.');
|
|
58
|
+
}
|
|
59
|
+
return new errors_1.VerificationError('BLS decoding requires @noble/curves; install it to enable remuneration');
|
|
60
|
+
};
|
|
61
|
+
const loadCurvesSync = () => {
|
|
62
|
+
if (curvesCache)
|
|
63
|
+
return curvesCache;
|
|
20
64
|
try {
|
|
21
65
|
// Lazy require to keep the dependency optional.
|
|
22
66
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
23
|
-
|
|
67
|
+
curvesCache = require('@noble/curves/bls12-381');
|
|
68
|
+
return curvesCache;
|
|
24
69
|
}
|
|
25
70
|
catch {
|
|
26
|
-
|
|
71
|
+
try {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
73
|
+
curvesCache = require('@noble/curves/bls12-381.js');
|
|
74
|
+
return curvesCache;
|
|
75
|
+
}
|
|
76
|
+
catch (err2) {
|
|
77
|
+
throw normalizeBlsImportError(err2);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const loadCurvesAsync = async () => {
|
|
82
|
+
if (curvesCache)
|
|
83
|
+
return curvesCache;
|
|
84
|
+
if (curvesPromise)
|
|
85
|
+
return curvesPromise;
|
|
86
|
+
curvesPromise = (async () => {
|
|
87
|
+
try {
|
|
88
|
+
// Try CJS first.
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
90
|
+
return require('@noble/curves/bls12-381');
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
const mod = (await Promise.resolve().then(() => __importStar(require('@noble/curves/bls12-381.js'))));
|
|
94
|
+
return mod;
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
97
|
+
curvesCache = await curvesPromise;
|
|
98
|
+
return curvesCache;
|
|
99
|
+
};
|
|
100
|
+
const normalizeSignature = (input) => {
|
|
101
|
+
if (debug_1.DEBUG_BLS) {
|
|
102
|
+
const type = input && typeof input === 'object'
|
|
103
|
+
? `object(keys=${Object.keys(input)
|
|
104
|
+
.slice(0, 6)
|
|
105
|
+
.join(',')})`
|
|
106
|
+
: typeof input;
|
|
107
|
+
console.log(` debug bls: normalizeSignature input=${type}`);
|
|
108
|
+
}
|
|
109
|
+
if (typeof input === 'string') {
|
|
110
|
+
const raw = input.startsWith('0x') ? input.slice(2) : input;
|
|
111
|
+
const bytes = (0, viem_1.toBytes)(`0x${raw}`);
|
|
112
|
+
return { hex: raw, bytes };
|
|
113
|
+
}
|
|
114
|
+
if (input instanceof Uint8Array) {
|
|
115
|
+
const hex = Buffer.from(input).toString('hex');
|
|
116
|
+
return { hex, bytes: input };
|
|
117
|
+
}
|
|
118
|
+
if (typeof Buffer !== 'undefined' && Buffer.isBuffer(input)) {
|
|
119
|
+
const hex = input.toString('hex');
|
|
120
|
+
return { hex, bytes: new Uint8Array(input) };
|
|
121
|
+
}
|
|
122
|
+
if (input instanceof ArrayBuffer) {
|
|
123
|
+
const bytes = new Uint8Array(input);
|
|
124
|
+
const hex = Buffer.from(bytes).toString('hex');
|
|
125
|
+
return { hex, bytes };
|
|
126
|
+
}
|
|
127
|
+
if (ArrayBuffer.isView(input)) {
|
|
128
|
+
const bytes = new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
129
|
+
const hex = Buffer.from(bytes).toString('hex');
|
|
130
|
+
return { hex, bytes };
|
|
131
|
+
}
|
|
132
|
+
if (Array.isArray(input)) {
|
|
133
|
+
const bytes = Uint8Array.from(input);
|
|
134
|
+
const hex = Buffer.from(bytes).toString('hex');
|
|
135
|
+
return { hex, bytes };
|
|
27
136
|
}
|
|
137
|
+
if (input && typeof input === 'object') {
|
|
138
|
+
const record = input;
|
|
139
|
+
if (Array.isArray(record.data)) {
|
|
140
|
+
const bytes = Uint8Array.from(record.data);
|
|
141
|
+
const hex = Buffer.from(bytes).toString('hex');
|
|
142
|
+
return { hex, bytes };
|
|
143
|
+
}
|
|
144
|
+
if ('bytes' in record) {
|
|
145
|
+
return normalizeSignature(record.bytes);
|
|
146
|
+
}
|
|
147
|
+
if ('signature' in record) {
|
|
148
|
+
return normalizeSignature(record.signature);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const label = input && typeof input === 'object'
|
|
152
|
+
? `object(keys=${Object.keys(input)
|
|
153
|
+
.slice(0, 6)
|
|
154
|
+
.join(',')})`
|
|
155
|
+
: typeof input;
|
|
156
|
+
throw new errors_1.VerificationError(`expected signature hex string or bytes, got ${label}`);
|
|
157
|
+
};
|
|
158
|
+
const signatureToWordsWith = (curves, signatureHex) => {
|
|
28
159
|
const toBigint = (field) => {
|
|
29
160
|
if (typeof field === 'bigint' || typeof field === 'number' || typeof field === 'string') {
|
|
30
161
|
return BigInt(field);
|
|
@@ -37,12 +168,47 @@ function signatureToWords(signatureHex) {
|
|
|
37
168
|
}
|
|
38
169
|
throw new errors_1.VerificationError('invalid BLS field element');
|
|
39
170
|
};
|
|
171
|
+
const readFp2 = (value) => {
|
|
172
|
+
if (!value || typeof value !== 'object') {
|
|
173
|
+
throw new errors_1.VerificationError('invalid BLS field element');
|
|
174
|
+
}
|
|
175
|
+
const record = value;
|
|
176
|
+
if (Array.isArray(record.c) && record.c.length >= 2) {
|
|
177
|
+
return [record.c[0], record.c[1]];
|
|
178
|
+
}
|
|
179
|
+
if ('c0' in record && 'c1' in record) {
|
|
180
|
+
return [record.c0, record.c1];
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(record.coeffs)) {
|
|
183
|
+
const coeffs = record.coeffs;
|
|
184
|
+
if (coeffs.length >= 2)
|
|
185
|
+
return [coeffs[0], coeffs[1]];
|
|
186
|
+
}
|
|
187
|
+
throw new errors_1.VerificationError('invalid BLS field element');
|
|
188
|
+
};
|
|
40
189
|
try {
|
|
41
|
-
const
|
|
42
|
-
const
|
|
190
|
+
const sig = normalizeSignature(signatureHex);
|
|
191
|
+
const g2 = curves.bls12_381.G2;
|
|
192
|
+
const pointCtor = g2.Point ?? g2.ProjectivePoint;
|
|
193
|
+
if (!pointCtor?.fromHex) {
|
|
194
|
+
throw new errors_1.VerificationError('unsupported @noble/curves BLS export');
|
|
195
|
+
}
|
|
196
|
+
let point;
|
|
197
|
+
try {
|
|
198
|
+
point = pointCtor.fromHex(sig.bytes);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
202
|
+
if (message.includes('hex string expected')) {
|
|
203
|
+
point = pointCtor.fromHex(sig.hex);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
throw err;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
43
209
|
const affine = point.toAffine();
|
|
44
|
-
const [x0, x1] = affine.x
|
|
45
|
-
const [y0, y1] = affine.y
|
|
210
|
+
const [x0, x1] = readFp2(affine.x);
|
|
211
|
+
const [y0, y1] = readFp2(affine.y);
|
|
46
212
|
const coords = [x0, x1, y0, y1].map((fp) => toBigint(fp));
|
|
47
213
|
const words = [];
|
|
48
214
|
coords.forEach((coord) => {
|
|
@@ -55,4 +221,16 @@ function signatureToWords(signatureHex) {
|
|
|
55
221
|
const message = err instanceof Error ? err.message : String(err);
|
|
56
222
|
throw new errors_1.VerificationError(`invalid BLS signature: ${message}`);
|
|
57
223
|
}
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Expand a compressed G2 signature into the tuple expected by the contract.
|
|
227
|
+
* This mirrors the Python helper and requires the optional `@noble/curves` dependency.
|
|
228
|
+
*/
|
|
229
|
+
function signatureToWords(signatureHex) {
|
|
230
|
+
const curves = loadCurvesSync();
|
|
231
|
+
return signatureToWordsWith(curves, signatureHex);
|
|
232
|
+
}
|
|
233
|
+
async function signatureToWordsAsync(signatureHex) {
|
|
234
|
+
const curves = await loadCurvesAsync();
|
|
235
|
+
return signatureToWordsWith(curves, signatureHex);
|
|
58
236
|
}
|
package/dist/chain.d.ts
ADDED
package/dist/chain.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getChain = getChain;
|
|
4
|
+
const chains_1 = require("viem/chains");
|
|
5
|
+
const CHAINS = {
|
|
6
|
+
1: chains_1.mainnet,
|
|
7
|
+
11155111: chains_1.sepolia,
|
|
8
|
+
8453: chains_1.base,
|
|
9
|
+
84532: chains_1.baseSepolia,
|
|
10
|
+
137: chains_1.polygon,
|
|
11
|
+
80002: chains_1.polygonAmoy,
|
|
12
|
+
};
|
|
13
|
+
function getChain(chainId, rpcUrl) {
|
|
14
|
+
const chain = CHAINS[chainId];
|
|
15
|
+
if (chain)
|
|
16
|
+
return chain;
|
|
17
|
+
return {
|
|
18
|
+
id: chainId,
|
|
19
|
+
name: `local-${chainId}`,
|
|
20
|
+
nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },
|
|
21
|
+
rpcUrls: {
|
|
22
|
+
default: { http: [rpcUrl] },
|
|
23
|
+
public: { http: [rpcUrl] },
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AuthTokens } from '../auth';
|
|
2
|
+
import { Config } from '../config';
|
|
3
|
+
import { ContractGateway } from '../contract';
|
|
4
|
+
import { RpcProxy } from '../rpc';
|
|
5
|
+
import { CorePublicParameters, PaymentSigner } from '../signing';
|
|
6
|
+
import { RecipientClient } from './recipient';
|
|
7
|
+
import { UserClient } from './user';
|
|
8
|
+
export declare class Client {
|
|
9
|
+
readonly rpc: RpcProxy;
|
|
10
|
+
readonly params: CorePublicParameters;
|
|
11
|
+
readonly gateway: ContractGateway;
|
|
12
|
+
readonly guaranteeDomain: string;
|
|
13
|
+
readonly user: UserClient;
|
|
14
|
+
readonly recipient: RecipientClient;
|
|
15
|
+
readonly signer: PaymentSigner;
|
|
16
|
+
private authSession?;
|
|
17
|
+
private constructor();
|
|
18
|
+
static new(cfg: Config): Promise<Client>;
|
|
19
|
+
private static buildGateway;
|
|
20
|
+
aclose(): Promise<void>;
|
|
21
|
+
login(): Promise<AuthTokens>;
|
|
22
|
+
}
|
|
23
|
+
export { UserClient } from './user';
|
|
24
|
+
export { RecipientClient } from './recipient';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RecipientClient = exports.UserClient = exports.Client = void 0;
|
|
4
|
+
const auth_1 = require("../auth");
|
|
5
|
+
const contract_1 = require("../contract");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const rpc_1 = require("../rpc");
|
|
8
|
+
const signing_1 = require("../signing");
|
|
9
|
+
const recipient_1 = require("./recipient");
|
|
10
|
+
const user_1 = require("./user");
|
|
11
|
+
class Client {
|
|
12
|
+
rpc;
|
|
13
|
+
params;
|
|
14
|
+
gateway;
|
|
15
|
+
guaranteeDomain;
|
|
16
|
+
user;
|
|
17
|
+
recipient;
|
|
18
|
+
signer;
|
|
19
|
+
authSession;
|
|
20
|
+
constructor(rpc, params, gateway, guaranteeDomain, signer, authSession) {
|
|
21
|
+
this.rpc = rpc;
|
|
22
|
+
this.params = params;
|
|
23
|
+
this.gateway = gateway;
|
|
24
|
+
this.guaranteeDomain = guaranteeDomain;
|
|
25
|
+
this.signer = signer;
|
|
26
|
+
this.authSession = authSession;
|
|
27
|
+
this.user = new user_1.UserClient(this);
|
|
28
|
+
this.recipient = new recipient_1.RecipientClient(this);
|
|
29
|
+
}
|
|
30
|
+
static async new(cfg) {
|
|
31
|
+
const rpc = new rpc_1.RpcProxy(cfg.rpcUrl, cfg.adminApiKey);
|
|
32
|
+
const params = await rpc.getPublicParams();
|
|
33
|
+
const gateway = await Client.buildGateway(cfg, params);
|
|
34
|
+
const guaranteeDomain = await gateway.getGuaranteeDomain();
|
|
35
|
+
const signer = new signing_1.PaymentSigner(cfg.signer);
|
|
36
|
+
const authEnabled = cfg.authUrl !== undefined || cfg.authRefreshMarginSecs !== undefined;
|
|
37
|
+
const authSession = cfg.bearerToken || !authEnabled
|
|
38
|
+
? undefined
|
|
39
|
+
: new auth_1.AuthSession({
|
|
40
|
+
authUrl: cfg.authUrl ?? cfg.rpcUrl,
|
|
41
|
+
signer: cfg.signer,
|
|
42
|
+
refreshMarginSecs: cfg.authRefreshMarginSecs ?? 60,
|
|
43
|
+
});
|
|
44
|
+
if (cfg.bearerToken) {
|
|
45
|
+
rpc.withBearerToken(cfg.bearerToken);
|
|
46
|
+
}
|
|
47
|
+
else if (authSession) {
|
|
48
|
+
rpc.withTokenProvider(() => authSession.accessToken());
|
|
49
|
+
}
|
|
50
|
+
return new Client(rpc, params, gateway, guaranteeDomain, signer, authSession);
|
|
51
|
+
}
|
|
52
|
+
static async buildGateway(cfg, params) {
|
|
53
|
+
const ethRpcUrl = cfg.ethereumHttpRpcUrl ?? params.ethereumHttpRpcUrl;
|
|
54
|
+
const contractAddress = cfg.contractAddress ?? params.contractAddress;
|
|
55
|
+
return contract_1.ContractGateway.create(ethRpcUrl, cfg.signer, contractAddress, params.chainId);
|
|
56
|
+
}
|
|
57
|
+
async aclose() {
|
|
58
|
+
await this.rpc.aclose();
|
|
59
|
+
}
|
|
60
|
+
async login() {
|
|
61
|
+
if (!this.authSession) {
|
|
62
|
+
throw new errors_1.AuthMissingConfigError('auth is not enabled');
|
|
63
|
+
}
|
|
64
|
+
return this.authSession.login();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.Client = Client;
|
|
68
|
+
var user_2 = require("./user");
|
|
69
|
+
Object.defineProperty(exports, "UserClient", { enumerable: true, get: function () { return user_2.UserClient; } });
|
|
70
|
+
var recipient_2 = require("./recipient");
|
|
71
|
+
Object.defineProperty(exports, "RecipientClient", { enumerable: true, get: function () { return recipient_2.RecipientClient; } });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AssetBalanceInfo, BLSCert, CollateralEventInfo, GuaranteeInfo, PaymentGuaranteeClaims, PaymentGuaranteeRequestClaims, PendingRemunerationInfo, RecipientPaymentInfo, SigningScheme, TabInfo, TabPaymentStatus } from '../models';
|
|
2
|
+
import type { TxReceiptWaitOptions } from '../contract';
|
|
3
|
+
import type { Client } from './index';
|
|
4
|
+
export declare class RecipientClient {
|
|
5
|
+
private client;
|
|
6
|
+
constructor(client: Client);
|
|
7
|
+
private get recipientAddress();
|
|
8
|
+
get guaranteeDomain(): string;
|
|
9
|
+
createTab(userAddress: string, recipientAddress: string, erc20Token: string | undefined | null, ttl?: number | null): Promise<bigint>;
|
|
10
|
+
getTabPaymentStatus(tabId: number | bigint): Promise<TabPaymentStatus>;
|
|
11
|
+
issuePaymentGuarantee(claims: PaymentGuaranteeRequestClaims, signature: string, scheme: SigningScheme): Promise<BLSCert>;
|
|
12
|
+
verifyPaymentGuarantee(cert: BLSCert): PaymentGuaranteeClaims;
|
|
13
|
+
remunerate(cert: BLSCert, waitOptions?: TxReceiptWaitOptions): Promise<import("viem").TransactionReceipt>;
|
|
14
|
+
listSettledTabs(): Promise<TabInfo[]>;
|
|
15
|
+
listPendingRemunerations(): Promise<PendingRemunerationInfo[]>;
|
|
16
|
+
getTab(tabId: number | bigint): Promise<TabInfo | null>;
|
|
17
|
+
listRecipientTabs(settlementStatuses?: string[]): Promise<TabInfo[]>;
|
|
18
|
+
getTabGuarantees(tabId: number | bigint): Promise<GuaranteeInfo[]>;
|
|
19
|
+
getLatestGuarantee(tabId: number | bigint): Promise<GuaranteeInfo | null>;
|
|
20
|
+
getGuarantee(tabId: number | bigint, reqId: number | bigint): Promise<GuaranteeInfo | null>;
|
|
21
|
+
listRecipientPayments(): Promise<RecipientPaymentInfo[]>;
|
|
22
|
+
getCollateralEventsForTab(tabId: number | bigint): Promise<CollateralEventInfo[]>;
|
|
23
|
+
getUserAssetBalance(userAddress: string, assetAddress: string): Promise<AssetBalanceInfo | null>;
|
|
24
|
+
}
|