@4mica/sdk 1.0.1 → 1.0.2
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/dist/contract.js +26 -10
- package/package.json +4 -2
- package/dist/abi/core4mica.json +0 -1605
- package/dist/abi/erc20.json +0 -187
- package/dist/client.d.ts +0 -56
- package/dist/client.js +0 -258
- package/dist/src/abi/core4mica.json +0 -1605
- package/dist/src/abi/erc20.json +0 -187
- package/dist/src/bls.d.ts +0 -5
- package/dist/src/bls.js +0 -45
- package/dist/src/client.d.ts +0 -55
- package/dist/src/client.js +0 -214
- package/dist/src/config.d.ts +0 -21
- package/dist/src/config.js +0 -76
- package/dist/src/contract.d.ts +0 -33
- package/dist/src/contract.js +0 -121
- package/dist/src/errors.d.ts +0 -17
- package/dist/src/errors.js +0 -31
- package/dist/src/guarantee.d.ts +0 -3
- package/dist/src/guarantee.js +0 -66
- package/dist/src/index.d.ts +0 -11
- package/dist/src/index.js +0 -27
- package/dist/src/models.d.ts +0 -119
- package/dist/src/models.js +0 -132
- package/dist/src/rpc.d.ts +0 -30
- package/dist/src/rpc.js +0 -122
- package/dist/src/signing.d.ts +0 -16
- package/dist/src/signing.js +0 -102
- package/dist/src/utils.d.ts +0 -8
- package/dist/src/utils.js +0 -78
- package/dist/src/x402.d.ts +0 -77
- package/dist/src/x402.js +0 -214
- package/dist/tests/config.test.d.ts +0 -1
- package/dist/tests/config.test.js +0 -26
- package/dist/tests/guarantee.test.d.ts +0 -1
- package/dist/tests/guarantee.test.js +0 -26
- package/dist/tests/rpc.test.d.ts +0 -1
- package/dist/tests/rpc.test.js +0 -44
- package/dist/tests/signing.test.d.ts +0 -1
- package/dist/tests/signing.test.js +0 -25
- package/dist/tests/utils.test.d.ts +0 -1
- package/dist/tests/utils.test.js +0 -25
- package/dist/tests/x402.test.d.ts +0 -1
- package/dist/tests/x402.test.js +0 -65
- package/dist/x402.d.ts +0 -78
- package/dist/x402.js +0 -231
package/dist/tests/rpc.test.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const rpc_1 = require("../src/rpc");
|
|
5
|
-
const errors_1 = require("../src/errors");
|
|
6
|
-
(0, vitest_1.describe)('RpcProxy', () => {
|
|
7
|
-
(0, vitest_1.it)('round trips public params', async () => {
|
|
8
|
-
const params = {
|
|
9
|
-
publicKey: [1, 2, 3],
|
|
10
|
-
contractAddress: '0x1234567890abcdef1234567890abcdef12345678',
|
|
11
|
-
ethereumHttpRpcUrl: 'http://localhost:8545',
|
|
12
|
-
eip712Name: '4mica',
|
|
13
|
-
eip712Version: '1',
|
|
14
|
-
chainId: 1337,
|
|
15
|
-
};
|
|
16
|
-
const fetchMock = vitest_1.vi.fn(async (input) => {
|
|
17
|
-
const url = input.toString();
|
|
18
|
-
(0, vitest_1.expect)(url.endsWith('/core/public-params')).toBe(true);
|
|
19
|
-
return new Response(JSON.stringify(params), { status: 200 });
|
|
20
|
-
});
|
|
21
|
-
const proxy = new rpc_1.RpcProxy('http://example.com', undefined, fetchMock);
|
|
22
|
-
const got = await proxy.getPublicParams();
|
|
23
|
-
(0, vitest_1.expect)(got.chainId).toBe(1337);
|
|
24
|
-
(0, vitest_1.expect)(got.contractAddress).toBe(params.contractAddress);
|
|
25
|
-
(0, vitest_1.expect)(got.ethereumHttpRpcUrl).toBe(params.ethereumHttpRpcUrl);
|
|
26
|
-
});
|
|
27
|
-
(0, vitest_1.it)('surfaces api errors', async () => {
|
|
28
|
-
const fetchMock = vitest_1.vi.fn(async (input) => {
|
|
29
|
-
(0, vitest_1.expect)(input.toString()).toContain('settlementStatus=unknown');
|
|
30
|
-
return new Response(JSON.stringify({ error: 'invalid settlement status: unknown' }), {
|
|
31
|
-
status: 400,
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
const proxy = new rpc_1.RpcProxy('http://example.com', undefined, fetchMock);
|
|
35
|
-
await (0, vitest_1.expect)(proxy.listRecipientTabs('0xdeadbeef', ['unknown'])).rejects.toThrow(errors_1.RpcError);
|
|
36
|
-
});
|
|
37
|
-
(0, vitest_1.it)('returns decode error on invalid json', async () => {
|
|
38
|
-
const fetchMock = vitest_1.vi.fn(async () => {
|
|
39
|
-
return new Response('not-json', { status: 200 });
|
|
40
|
-
});
|
|
41
|
-
const proxy = new rpc_1.RpcProxy('http://example.com', undefined, fetchMock);
|
|
42
|
-
await (0, vitest_1.expect)(proxy.getPublicParams()).rejects.toThrow(errors_1.RpcError);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const models_1 = require("../src/models");
|
|
5
|
-
const signing_1 = require("../src/signing");
|
|
6
|
-
const errors_1 = require("../src/errors");
|
|
7
|
-
function buildParams() {
|
|
8
|
-
return new signing_1.CorePublicParameters(new Uint8Array(), '0x0000000000000000000000000000000000000000', 'https://example.com', '4Mica', '1', 1);
|
|
9
|
-
}
|
|
10
|
-
(0, vitest_1.describe)('PaymentSigner', () => {
|
|
11
|
-
(0, vitest_1.it)('rejects address mismatch', async () => {
|
|
12
|
-
const signer = new signing_1.PaymentSigner('11'.repeat(32));
|
|
13
|
-
const claims = models_1.PaymentGuaranteeRequestClaims.new('0x0000000000000000000000000000000000000011', '0x0000000000000000000000000000000000000002', 1, 5, 1234, null);
|
|
14
|
-
await (0, vitest_1.expect)(signer.signRequest(buildParams(), claims, models_1.SigningScheme.EIP712)).rejects.toThrow(errors_1.SigningError);
|
|
15
|
-
});
|
|
16
|
-
(0, vitest_1.it)('produces eip712 signature', async () => {
|
|
17
|
-
const privateKey = '0x59c6995e998f97a5a0044976f7be35d5ad91c0cfa55b5cfb20b07a1c60f4c5bc';
|
|
18
|
-
const signer = new signing_1.PaymentSigner(privateKey);
|
|
19
|
-
const accountAddress = (await signer['wallet'].getAddress()).toLowerCase();
|
|
20
|
-
const claims = models_1.PaymentGuaranteeRequestClaims.new(accountAddress, '0x0000000000000000000000000000000000000002', 42, 123, 999, null);
|
|
21
|
-
const sig = await signer.signRequest(buildParams(), claims, models_1.SigningScheme.EIP712);
|
|
22
|
-
(0, vitest_1.expect)(sig.scheme).toBe(models_1.SigningScheme.EIP712);
|
|
23
|
-
(0, vitest_1.expect)(sig.signature.length).toBe(132);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/utils.test.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const utils_1 = require("../src/utils");
|
|
5
|
-
(0, vitest_1.describe)('utils', () => {
|
|
6
|
-
(0, vitest_1.it)('validateUrl rejects bad input', () => {
|
|
7
|
-
(0, vitest_1.expect)(() => (0, utils_1.validateUrl)('not-a-url')).toThrow(utils_1.ValidationError);
|
|
8
|
-
});
|
|
9
|
-
(0, vitest_1.it)('normalizePrivateKey strips prefix and lowercases', () => {
|
|
10
|
-
const key = (0, utils_1.normalizePrivateKey)('0xABCDEF' + '0'.repeat(58));
|
|
11
|
-
(0, vitest_1.expect)(key).toBe('0xabcdef' + '0'.repeat(58));
|
|
12
|
-
});
|
|
13
|
-
(0, vitest_1.it)('parseU256 accepts hex strings and serializes back', () => {
|
|
14
|
-
const value = (0, utils_1.parseU256)('0x10');
|
|
15
|
-
(0, vitest_1.expect)(value).toBe(16n);
|
|
16
|
-
(0, vitest_1.expect)((0, utils_1.serializeU256)(value)).toBe('0x10');
|
|
17
|
-
});
|
|
18
|
-
(0, vitest_1.it)('normalizeAddress round trips checksum', () => {
|
|
19
|
-
const addr = '0x0000000000000000000000000000000000000001';
|
|
20
|
-
(0, vitest_1.expect)((0, utils_1.normalizeAddress)(addr)).toBe('0x0000000000000000000000000000000000000001');
|
|
21
|
-
});
|
|
22
|
-
(0, vitest_1.it)('parseU256 rejects negatives', () => {
|
|
23
|
-
(0, vitest_1.expect)(() => (0, utils_1.parseU256)(-1)).toThrow(utils_1.ValidationError);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/tests/x402.test.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const vitest_1 = require("vitest");
|
|
4
|
-
const models_1 = require("../src/models");
|
|
5
|
-
const x402_1 = require("../src/x402");
|
|
6
|
-
const errors_1 = require("../src/errors");
|
|
7
|
-
class StubSigner {
|
|
8
|
-
async signPayment() {
|
|
9
|
-
return { signature: 'deadbeef', scheme: models_1.SigningScheme.EIP712 };
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
class StubX402Flow extends x402_1.X402Flow {
|
|
13
|
-
async requestTab() {
|
|
14
|
-
return new x402_1.TabResponse('2', '0x0000000000000000000000000000000000000001');
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
(0, vitest_1.describe)('X402Flow', () => {
|
|
18
|
-
(0, vitest_1.it)('rejects invalid scheme', async () => {
|
|
19
|
-
const flow = new StubX402Flow(new StubSigner());
|
|
20
|
-
const requirements = new x402_1.PaymentRequirements('http+pay', 'testnet', '1', '0x0000000000000000000000000000000000000003', '0x0000000000000000000000000000000000000000', { tabEndpoint: 'https://example.com' });
|
|
21
|
-
await (0, vitest_1.expect)(flow.signPayment(requirements, '0x0000000000000000000000000000000000000001')).rejects.toThrow(errors_1.X402Error);
|
|
22
|
-
});
|
|
23
|
-
(0, vitest_1.it)('builds header and payload', async () => {
|
|
24
|
-
const flow = new StubX402Flow(new StubSigner());
|
|
25
|
-
const requirements = new x402_1.PaymentRequirements('4mica+pay', 'testnet', '5', '0x0000000000000000000000000000000000000003', '0x0000000000000000000000000000000000000000', { tabEndpoint: 'https://example.com' });
|
|
26
|
-
const userAddress = '0x0000000000000000000000000000000000000001';
|
|
27
|
-
const signed = await flow.signPayment(requirements, userAddress);
|
|
28
|
-
const decoded = Buffer.from(signed.header, 'base64').toString('utf8');
|
|
29
|
-
const envelope = JSON.parse(decoded);
|
|
30
|
-
(0, vitest_1.expect)(envelope.x402Version).toBe(1);
|
|
31
|
-
(0, vitest_1.expect)(envelope.scheme).toBe('4mica+pay');
|
|
32
|
-
(0, vitest_1.expect)(envelope.payload.claims.tab_id).toBe('0x2');
|
|
33
|
-
(0, vitest_1.expect)(signed.claims.tabId).toBe(2n);
|
|
34
|
-
(0, vitest_1.expect)(signed.claims.amount).toBe(5n);
|
|
35
|
-
});
|
|
36
|
-
(0, vitest_1.it)('settles payment through facilitator', async () => {
|
|
37
|
-
const userAddress = '0x0000000000000000000000000000000000000009';
|
|
38
|
-
const tabEndpoint = 'http://facilitator.test/tab';
|
|
39
|
-
const facilitatorUrl = 'http://facilitator.test';
|
|
40
|
-
const requirements = new x402_1.PaymentRequirements('4mica+pay', 'testnet', '5', '0x00000000000000000000000000000000000000ff', '0x0000000000000000000000000000000000000000', { tabEndpoint });
|
|
41
|
-
const fetch = async (url, init) => {
|
|
42
|
-
const u = new URL(url);
|
|
43
|
-
if (u.pathname === '/tab') {
|
|
44
|
-
const body = JSON.parse(init?.body);
|
|
45
|
-
(0, vitest_1.expect)(body.userAddress).toBe(userAddress);
|
|
46
|
-
return new Response(JSON.stringify({ tabId: '0x1234', userAddress }), { status: 200 });
|
|
47
|
-
}
|
|
48
|
-
if (u.pathname === '/settle') {
|
|
49
|
-
const payload = JSON.parse(init?.body);
|
|
50
|
-
(0, vitest_1.expect)(payload.paymentRequirements.payTo).toBe(requirements.payTo);
|
|
51
|
-
return new Response(JSON.stringify({ settled: true, networkId: requirements.network }), {
|
|
52
|
-
status: 200,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
return new Response('not found', { status: 404 });
|
|
56
|
-
};
|
|
57
|
-
const flow = new x402_1.X402Flow(new StubSigner(), fetch);
|
|
58
|
-
const payment = await flow.signPayment(requirements, userAddress);
|
|
59
|
-
(0, vitest_1.expect)(payment.claims.tabId).toBe(0x1234n);
|
|
60
|
-
const settled = await flow.settlePayment(payment, requirements, facilitatorUrl);
|
|
61
|
-
(0, vitest_1.expect)(settled.settlement.settled).toBe(true);
|
|
62
|
-
(0, vitest_1.expect)(settled.settlement.networkId).toBe(requirements.network);
|
|
63
|
-
(0, vitest_1.expect)(settled.payment.claims.recipientAddress).toBe(requirements.payTo);
|
|
64
|
-
});
|
|
65
|
-
});
|
package/dist/x402.d.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { PaymentGuaranteeRequestClaims, PaymentSignature, SigningScheme } from './models';
|
|
2
|
-
import type { FetchFn } from './rpc';
|
|
3
|
-
export interface PaymentRequirementsInit {
|
|
4
|
-
scheme: string;
|
|
5
|
-
network: string;
|
|
6
|
-
maxAmountRequired: string;
|
|
7
|
-
payTo: string;
|
|
8
|
-
asset: string;
|
|
9
|
-
extra?: Record<string, unknown>;
|
|
10
|
-
resource?: string;
|
|
11
|
-
description?: string;
|
|
12
|
-
mimeType?: string;
|
|
13
|
-
outputSchema?: unknown;
|
|
14
|
-
maxTimeoutSeconds?: number;
|
|
15
|
-
}
|
|
16
|
-
export declare class PaymentRequirements {
|
|
17
|
-
scheme: string;
|
|
18
|
-
network: string;
|
|
19
|
-
maxAmountRequired: string;
|
|
20
|
-
payTo: string;
|
|
21
|
-
asset: string;
|
|
22
|
-
extra: Record<string, unknown>;
|
|
23
|
-
resource?: string | undefined;
|
|
24
|
-
description?: string | undefined;
|
|
25
|
-
mimeType?: string | undefined;
|
|
26
|
-
outputSchema?: unknown | undefined;
|
|
27
|
-
maxTimeoutSeconds?: number | undefined;
|
|
28
|
-
constructor(scheme: string, network: string, maxAmountRequired: string, payTo: string, asset: string, extra: Record<string, unknown>, resource?: string | undefined, description?: string | undefined, mimeType?: string | undefined, outputSchema?: unknown | undefined, maxTimeoutSeconds?: number | undefined);
|
|
29
|
-
static fromRaw(raw: Record<string, unknown>): PaymentRequirements;
|
|
30
|
-
toPayload(): Record<string, unknown>;
|
|
31
|
-
}
|
|
32
|
-
export declare class PaymentRequirementsExtra {
|
|
33
|
-
tabEndpoint?: string | null | undefined;
|
|
34
|
-
constructor(tabEndpoint?: string | null | undefined);
|
|
35
|
-
static fromRaw(raw: Record<string, unknown> | undefined): PaymentRequirementsExtra;
|
|
36
|
-
}
|
|
37
|
-
export declare class TabResponse {
|
|
38
|
-
tabId: string;
|
|
39
|
-
userAddress: string;
|
|
40
|
-
nextReqId?: string | null | undefined;
|
|
41
|
-
constructor(tabId: string, userAddress: string, nextReqId?: string | null | undefined);
|
|
42
|
-
}
|
|
43
|
-
export declare class X402PaymentEnvelope {
|
|
44
|
-
x402Version: number;
|
|
45
|
-
scheme: string;
|
|
46
|
-
network: string;
|
|
47
|
-
payload: Record<string, unknown>;
|
|
48
|
-
constructor(x402Version: number, scheme: string, network: string, payload: Record<string, unknown>);
|
|
49
|
-
toPayload(): Record<string, unknown>;
|
|
50
|
-
}
|
|
51
|
-
export declare class X402SignedPayment {
|
|
52
|
-
header: string;
|
|
53
|
-
claims: PaymentGuaranteeRequestClaims;
|
|
54
|
-
signature: PaymentSignature;
|
|
55
|
-
constructor(header: string, claims: PaymentGuaranteeRequestClaims, signature: PaymentSignature);
|
|
56
|
-
}
|
|
57
|
-
export declare class X402SettledPayment {
|
|
58
|
-
payment: X402SignedPayment;
|
|
59
|
-
settlement: unknown;
|
|
60
|
-
constructor(payment: X402SignedPayment, settlement: unknown);
|
|
61
|
-
}
|
|
62
|
-
export interface FlowSigner {
|
|
63
|
-
signPayment(claims: PaymentGuaranteeRequestClaims, scheme: SigningScheme): Promise<PaymentSignature>;
|
|
64
|
-
}
|
|
65
|
-
export declare class X402Flow {
|
|
66
|
-
private signer;
|
|
67
|
-
private fetchFn;
|
|
68
|
-
constructor(signer: FlowSigner, fetchFn?: FetchFn);
|
|
69
|
-
static fromClient(client: {
|
|
70
|
-
user: FlowSigner;
|
|
71
|
-
}): X402Flow;
|
|
72
|
-
signPayment(paymentRequirements: PaymentRequirements, userAddress: string, existingTabId?: bigint | number, existingReqId?: bigint | number): Promise<X402SignedPayment>;
|
|
73
|
-
settlePayment(payment: X402SignedPayment, paymentRequirements: PaymentRequirements, facilitatorUrl: string): Promise<X402SettledPayment>;
|
|
74
|
-
protected requestTab(paymentRequirements: PaymentRequirements, userAddress: string): Promise<TabResponse>;
|
|
75
|
-
protected buildClaims(requirements: PaymentRequirements, tab: TabResponse, userAddress: string): PaymentGuaranteeRequestClaims;
|
|
76
|
-
private static validateScheme;
|
|
77
|
-
private static buildEnvelope;
|
|
78
|
-
}
|
package/dist/x402.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.X402Flow = exports.X402SettledPayment = exports.X402SignedPayment = exports.X402PaymentEnvelope = exports.TabResponse = exports.PaymentRequirementsExtra = exports.PaymentRequirements = void 0;
|
|
4
|
-
const models_1 = require("./models");
|
|
5
|
-
const utils_1 = require("./utils");
|
|
6
|
-
const errors_1 = require("./errors");
|
|
7
|
-
const isRecord = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
8
|
-
class PaymentRequirements {
|
|
9
|
-
constructor(scheme, network, maxAmountRequired, payTo, asset, extra, resource, description, mimeType, outputSchema, maxTimeoutSeconds) {
|
|
10
|
-
this.scheme = scheme;
|
|
11
|
-
this.network = network;
|
|
12
|
-
this.maxAmountRequired = maxAmountRequired;
|
|
13
|
-
this.payTo = payTo;
|
|
14
|
-
this.asset = asset;
|
|
15
|
-
this.extra = extra;
|
|
16
|
-
this.resource = resource;
|
|
17
|
-
this.description = description;
|
|
18
|
-
this.mimeType = mimeType;
|
|
19
|
-
this.outputSchema = outputSchema;
|
|
20
|
-
this.maxTimeoutSeconds = maxTimeoutSeconds;
|
|
21
|
-
}
|
|
22
|
-
static fromRaw(raw) {
|
|
23
|
-
const pick = (keys, defaultValue) => {
|
|
24
|
-
for (const key of keys) {
|
|
25
|
-
const value = raw[key];
|
|
26
|
-
if (value !== undefined && value !== null)
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
return defaultValue;
|
|
30
|
-
};
|
|
31
|
-
const amount = pick(['maxAmountRequired', 'max_amount_required']);
|
|
32
|
-
const payTo = pick(['payTo', 'pay_to']);
|
|
33
|
-
const asset = pick(['asset', 'assetAddress', 'asset_address']);
|
|
34
|
-
const scheme = pick(['scheme']);
|
|
35
|
-
const network = pick(['network']);
|
|
36
|
-
if (!amount || !payTo || !asset || !scheme || !network) {
|
|
37
|
-
const missing = [
|
|
38
|
-
['scheme', scheme],
|
|
39
|
-
['network', network],
|
|
40
|
-
['maxAmountRequired', amount],
|
|
41
|
-
['payTo', payTo],
|
|
42
|
-
['asset', asset],
|
|
43
|
-
]
|
|
44
|
-
.filter(([, value]) => !value)
|
|
45
|
-
.map(([key]) => key)
|
|
46
|
-
.join(', ');
|
|
47
|
-
throw new errors_1.X402Error(`payment requirements missing fields: ${missing}`);
|
|
48
|
-
}
|
|
49
|
-
return new PaymentRequirements(String(scheme), String(network), String(amount), String(payTo), String(asset), pick(['extra'], {}) ?? {}, pick(['resource']), pick(['description']), pick(['mimeType', 'mime_type']), pick(['outputSchema', 'output_schema']), pick(['maxTimeoutSeconds', 'max_timeout_seconds']));
|
|
50
|
-
}
|
|
51
|
-
toPayload() {
|
|
52
|
-
const extraPayload = { ...(this.extra ?? {}) };
|
|
53
|
-
if ('tab_endpoint' in extraPayload && !('tabEndpoint' in extraPayload)) {
|
|
54
|
-
extraPayload['tabEndpoint'] = extraPayload['tab_endpoint'];
|
|
55
|
-
delete extraPayload['tab_endpoint'];
|
|
56
|
-
}
|
|
57
|
-
const payload = {
|
|
58
|
-
scheme: this.scheme,
|
|
59
|
-
network: this.network,
|
|
60
|
-
maxAmountRequired: this.maxAmountRequired,
|
|
61
|
-
payTo: this.payTo,
|
|
62
|
-
asset: this.asset,
|
|
63
|
-
extra: extraPayload,
|
|
64
|
-
};
|
|
65
|
-
if (this.resource !== undefined)
|
|
66
|
-
payload.resource = this.resource;
|
|
67
|
-
if (this.description !== undefined)
|
|
68
|
-
payload.description = this.description;
|
|
69
|
-
if (this.mimeType !== undefined)
|
|
70
|
-
payload.mimeType = this.mimeType;
|
|
71
|
-
if (this.outputSchema !== undefined)
|
|
72
|
-
payload.outputSchema = this.outputSchema;
|
|
73
|
-
if (this.maxTimeoutSeconds !== undefined)
|
|
74
|
-
payload.maxTimeoutSeconds = this.maxTimeoutSeconds;
|
|
75
|
-
return payload;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
exports.PaymentRequirements = PaymentRequirements;
|
|
79
|
-
class PaymentRequirementsExtra {
|
|
80
|
-
constructor(tabEndpoint) {
|
|
81
|
-
this.tabEndpoint = tabEndpoint;
|
|
82
|
-
}
|
|
83
|
-
static fromRaw(raw) {
|
|
84
|
-
const tabEndpointRaw = (isRecord(raw) ? raw.tabEndpoint : undefined) ??
|
|
85
|
-
(isRecord(raw) ? raw.tab_endpoint : undefined);
|
|
86
|
-
const tabEndpoint = typeof tabEndpointRaw === 'string'
|
|
87
|
-
? tabEndpointRaw
|
|
88
|
-
: tabEndpointRaw === null
|
|
89
|
-
? null
|
|
90
|
-
: undefined;
|
|
91
|
-
return new PaymentRequirementsExtra(tabEndpoint);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
exports.PaymentRequirementsExtra = PaymentRequirementsExtra;
|
|
95
|
-
class TabResponse {
|
|
96
|
-
constructor(tabId, userAddress, nextReqId) {
|
|
97
|
-
this.tabId = tabId;
|
|
98
|
-
this.userAddress = userAddress;
|
|
99
|
-
this.nextReqId = nextReqId;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
exports.TabResponse = TabResponse;
|
|
103
|
-
class X402PaymentEnvelope {
|
|
104
|
-
constructor(x402Version, scheme, network, payload) {
|
|
105
|
-
this.x402Version = x402Version;
|
|
106
|
-
this.scheme = scheme;
|
|
107
|
-
this.network = network;
|
|
108
|
-
this.payload = payload;
|
|
109
|
-
}
|
|
110
|
-
toPayload() {
|
|
111
|
-
return {
|
|
112
|
-
x402Version: this.x402Version,
|
|
113
|
-
scheme: this.scheme,
|
|
114
|
-
network: this.network,
|
|
115
|
-
payload: this.payload,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
exports.X402PaymentEnvelope = X402PaymentEnvelope;
|
|
120
|
-
class X402SignedPayment {
|
|
121
|
-
constructor(header, claims, signature) {
|
|
122
|
-
this.header = header;
|
|
123
|
-
this.claims = claims;
|
|
124
|
-
this.signature = signature;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
exports.X402SignedPayment = X402SignedPayment;
|
|
128
|
-
class X402SettledPayment {
|
|
129
|
-
constructor(payment, settlement) {
|
|
130
|
-
this.payment = payment;
|
|
131
|
-
this.settlement = settlement;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
exports.X402SettledPayment = X402SettledPayment;
|
|
135
|
-
class X402Flow {
|
|
136
|
-
constructor(signer, fetchFn = fetch) {
|
|
137
|
-
this.signer = signer;
|
|
138
|
-
this.fetchFn = fetchFn;
|
|
139
|
-
}
|
|
140
|
-
static fromClient(client) {
|
|
141
|
-
return new X402Flow(client.user);
|
|
142
|
-
}
|
|
143
|
-
async signPayment(paymentRequirements, userAddress, existingTabId, existingReqId) {
|
|
144
|
-
X402Flow.validateScheme(paymentRequirements.scheme);
|
|
145
|
-
let tab;
|
|
146
|
-
if (existingTabId !== undefined && existingTabId !== null) {
|
|
147
|
-
tab = new TabResponse(String(existingTabId), userAddress, existingReqId !== undefined && existingReqId !== null ? String(existingReqId) : undefined);
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
tab = await this.requestTab(paymentRequirements, userAddress);
|
|
151
|
-
}
|
|
152
|
-
const claims = this.buildClaims(paymentRequirements, tab, userAddress);
|
|
153
|
-
const signature = await this.signer.signPayment(claims, models_1.SigningScheme.EIP712);
|
|
154
|
-
const envelope = X402Flow.buildEnvelope(paymentRequirements, claims, signature);
|
|
155
|
-
const payload = envelope.toPayload();
|
|
156
|
-
payload.x402Version ?? (payload.x402Version = envelope.x402Version);
|
|
157
|
-
const header = Buffer.from(JSON.stringify(payload)).toString('base64');
|
|
158
|
-
return new X402SignedPayment(header, claims, signature);
|
|
159
|
-
}
|
|
160
|
-
async settlePayment(payment, paymentRequirements, facilitatorUrl) {
|
|
161
|
-
const url = `${facilitatorUrl.replace(/\/$/, '')}/settle`;
|
|
162
|
-
const response = await this.fetchFn(url, {
|
|
163
|
-
method: 'POST',
|
|
164
|
-
headers: { 'content-type': 'application/json' },
|
|
165
|
-
body: JSON.stringify({
|
|
166
|
-
x402Version: 1,
|
|
167
|
-
paymentHeader: payment.header,
|
|
168
|
-
paymentRequirements: paymentRequirements.toPayload(),
|
|
169
|
-
}),
|
|
170
|
-
});
|
|
171
|
-
const data = await response.text();
|
|
172
|
-
if (!response.ok) {
|
|
173
|
-
throw new errors_1.X402Error(`settlement failed with status ${response.status}: ${data}`);
|
|
174
|
-
}
|
|
175
|
-
const settlement = data ? JSON.parse(data) : {};
|
|
176
|
-
return new X402SettledPayment(payment, settlement);
|
|
177
|
-
}
|
|
178
|
-
async requestTab(paymentRequirements, userAddress) {
|
|
179
|
-
const extra = PaymentRequirementsExtra.fromRaw(paymentRequirements.extra);
|
|
180
|
-
if (!extra.tabEndpoint) {
|
|
181
|
-
throw new errors_1.X402Error('missing tabEndpoint in paymentRequirements.extra');
|
|
182
|
-
}
|
|
183
|
-
const resp = await this.fetchFn(extra.tabEndpoint, {
|
|
184
|
-
method: 'POST',
|
|
185
|
-
headers: { 'content-type': 'application/json' },
|
|
186
|
-
body: JSON.stringify({
|
|
187
|
-
userAddress,
|
|
188
|
-
paymentRequirements: paymentRequirements.toPayload(),
|
|
189
|
-
}),
|
|
190
|
-
});
|
|
191
|
-
if (!resp.ok) {
|
|
192
|
-
const text = await resp.text();
|
|
193
|
-
throw new errors_1.X402Error(`tab resolution failed: ${resp.status} ${text}`);
|
|
194
|
-
}
|
|
195
|
-
const body = await resp.json();
|
|
196
|
-
return new TabResponse(body.tabId ?? body.tab_id, body.userAddress ?? body.user_address, body.nextReqId ?? body.next_req_id ?? body.reqId ?? body.req_id);
|
|
197
|
-
}
|
|
198
|
-
buildClaims(requirements, tab, userAddress) {
|
|
199
|
-
const tabId = (0, utils_1.parseU256)(tab.tabId);
|
|
200
|
-
const reqId = tab.nextReqId !== undefined && tab.nextReqId !== null ? (0, utils_1.parseU256)(tab.nextReqId) : 0n;
|
|
201
|
-
const amount = (0, utils_1.parseU256)(requirements.maxAmountRequired);
|
|
202
|
-
if (tab.userAddress.toLowerCase() !== userAddress.toLowerCase()) {
|
|
203
|
-
throw new errors_1.X402Error(`user mismatch in paymentRequirements: found ${tab.userAddress}, expected ${userAddress}`);
|
|
204
|
-
}
|
|
205
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
206
|
-
return models_1.PaymentGuaranteeRequestClaims.new(userAddress, (0, utils_1.normalizeAddress)(requirements.payTo), tabId, amount, timestamp, requirements.asset, reqId);
|
|
207
|
-
}
|
|
208
|
-
static validateScheme(scheme) {
|
|
209
|
-
if (!scheme.toLowerCase().includes('4mica')) {
|
|
210
|
-
throw new errors_1.X402Error(`invalid scheme: ${scheme}`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
static buildEnvelope(paymentRequirements, claims, signature) {
|
|
214
|
-
const payload = {
|
|
215
|
-
claims: {
|
|
216
|
-
version: 'v1',
|
|
217
|
-
user_address: claims.userAddress,
|
|
218
|
-
recipient_address: claims.recipientAddress,
|
|
219
|
-
tab_id: `0x${claims.tabId.toString(16)}`,
|
|
220
|
-
req_id: `0x${claims.reqId.toString(16)}`,
|
|
221
|
-
amount: `0x${claims.amount.toString(16)}`,
|
|
222
|
-
asset_address: claims.assetAddress,
|
|
223
|
-
timestamp: claims.timestamp,
|
|
224
|
-
},
|
|
225
|
-
signature: signature.signature,
|
|
226
|
-
scheme: signature.scheme,
|
|
227
|
-
};
|
|
228
|
-
return new X402PaymentEnvelope(1, paymentRequirements.scheme, paymentRequirements.network, payload);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
exports.X402Flow = X402Flow;
|