@pay-skill/sdk 0.1.1 → 0.1.3
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 +154 -154
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +2 -2
- package/dist/auth.js.map +1 -1
- package/dist/client.d.ts +8 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +106 -54
- package/dist/client.js.map +1 -1
- package/dist/eip3009.d.ts +24 -0
- package/dist/eip3009.d.ts.map +1 -0
- package/dist/eip3009.js +56 -0
- package/dist/eip3009.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +35 -26
- package/dist/models.d.ts.map +1 -1
- package/dist/signer.d.ts +1 -1
- package/dist/signer.d.ts.map +1 -1
- package/dist/signer.js +1 -2
- package/dist/signer.js.map +1 -1
- package/dist/wallet.d.ts.map +1 -1
- package/dist/wallet.js +6 -3
- package/dist/wallet.js.map +1 -1
- package/jsr.json +12 -0
- package/package.json +48 -44
- package/src/auth.ts +200 -200
- package/src/client.ts +644 -644
- package/src/eip3009.ts +79 -79
- package/src/index.ts +51 -51
- package/src/models.ts +77 -77
- package/src/ows-signer.ts +223 -223
- package/src/signer.ts +147 -147
- package/src/wallet.ts +445 -445
- package/tests/test_auth_rejection.ts +154 -154
- package/tests/test_crypto.ts +251 -251
- package/tests/test_e2e.ts +158 -158
- package/tests/test_ows_integration.ts +92 -92
- package/tests/test_ows_signer.ts +365 -365
- package/tests/test_validation.ts +66 -66
package/src/eip3009.ts
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EIP-3009 TransferWithAuthorization signing for x402 direct settlement.
|
|
3
|
-
*
|
|
4
|
-
* Unlike EIP-2612 permits (which need a nonce from the USDC contract),
|
|
5
|
-
* EIP-3009 uses a random nonce chosen by the signer. Fully local — no
|
|
6
|
-
* server round-trip needed.
|
|
7
|
-
*
|
|
8
|
-
* Domain: { name: "USD Coin", version: "2", chainId, verifyingContract: usdcAddress }
|
|
9
|
-
* Type: TransferWithAuthorization(address from, address to, uint256 value,
|
|
10
|
-
* uint256 validAfter, uint256 validBefore, bytes32 nonce)
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { type Hex, type Address } from "viem";
|
|
14
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
15
|
-
import { randomBytes } from "node:crypto";
|
|
16
|
-
|
|
17
|
-
export interface TransferAuthorization {
|
|
18
|
-
from: string;
|
|
19
|
-
to: string;
|
|
20
|
-
amount: number;
|
|
21
|
-
nonce: string;
|
|
22
|
-
v: number;
|
|
23
|
-
r: string;
|
|
24
|
-
s: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const TRANSFER_AUTH_TYPES = {
|
|
28
|
-
TransferWithAuthorization: [
|
|
29
|
-
{ name: "from", type: "address" },
|
|
30
|
-
{ name: "to", type: "address" },
|
|
31
|
-
{ name: "value", type: "uint256" },
|
|
32
|
-
{ name: "validAfter", type: "uint256" },
|
|
33
|
-
{ name: "validBefore", type: "uint256" },
|
|
34
|
-
{ name: "nonce", type: "bytes32" },
|
|
35
|
-
],
|
|
36
|
-
} as const;
|
|
37
|
-
|
|
38
|
-
export async function signTransferAuthorization(
|
|
39
|
-
privateKey: Hex,
|
|
40
|
-
to: Address,
|
|
41
|
-
amount: number,
|
|
42
|
-
chainId: number,
|
|
43
|
-
usdcAddress: Address,
|
|
44
|
-
): Promise<TransferAuthorization> {
|
|
45
|
-
const account = privateKeyToAccount(privateKey);
|
|
46
|
-
const nonce = ("0x" + randomBytes(32).toString("hex")) as Hex;
|
|
47
|
-
|
|
48
|
-
const signature = await account.signTypedData({
|
|
49
|
-
domain: {
|
|
50
|
-
name: "USD Coin",
|
|
51
|
-
version: "2",
|
|
52
|
-
chainId,
|
|
53
|
-
verifyingContract: usdcAddress,
|
|
54
|
-
},
|
|
55
|
-
types: TRANSFER_AUTH_TYPES,
|
|
56
|
-
primaryType: "TransferWithAuthorization",
|
|
57
|
-
message: {
|
|
58
|
-
from: account.address,
|
|
59
|
-
to,
|
|
60
|
-
value: BigInt(amount),
|
|
61
|
-
validAfter: 0n,
|
|
62
|
-
validBefore: 0n,
|
|
63
|
-
nonce,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const sigHex = signature.slice(2);
|
|
68
|
-
const r = `0x${sigHex.slice(0, 64)}`;
|
|
69
|
-
const s = `0x${sigHex.slice(64, 128)}`;
|
|
70
|
-
const v = parseInt(sigHex.slice(128, 130), 16);
|
|
71
|
-
|
|
72
|
-
return { from: account.address, to, amount, nonce, v, r, s };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function combinedSignature(auth: TransferAuthorization): string {
|
|
76
|
-
const r = auth.r.startsWith("0x") ? auth.r.slice(2) : auth.r;
|
|
77
|
-
const s = auth.s.startsWith("0x") ? auth.s.slice(2) : auth.s;
|
|
78
|
-
return `0x${r}${s}${auth.v.toString(16).padStart(2, "0")}`;
|
|
79
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* EIP-3009 TransferWithAuthorization signing for x402 direct settlement.
|
|
3
|
+
*
|
|
4
|
+
* Unlike EIP-2612 permits (which need a nonce from the USDC contract),
|
|
5
|
+
* EIP-3009 uses a random nonce chosen by the signer. Fully local — no
|
|
6
|
+
* server round-trip needed.
|
|
7
|
+
*
|
|
8
|
+
* Domain: { name: "USD Coin", version: "2", chainId, verifyingContract: usdcAddress }
|
|
9
|
+
* Type: TransferWithAuthorization(address from, address to, uint256 value,
|
|
10
|
+
* uint256 validAfter, uint256 validBefore, bytes32 nonce)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { type Hex, type Address } from "viem";
|
|
14
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
15
|
+
import { randomBytes } from "node:crypto";
|
|
16
|
+
|
|
17
|
+
export interface TransferAuthorization {
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
amount: number;
|
|
21
|
+
nonce: string;
|
|
22
|
+
v: number;
|
|
23
|
+
r: string;
|
|
24
|
+
s: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const TRANSFER_AUTH_TYPES = {
|
|
28
|
+
TransferWithAuthorization: [
|
|
29
|
+
{ name: "from", type: "address" },
|
|
30
|
+
{ name: "to", type: "address" },
|
|
31
|
+
{ name: "value", type: "uint256" },
|
|
32
|
+
{ name: "validAfter", type: "uint256" },
|
|
33
|
+
{ name: "validBefore", type: "uint256" },
|
|
34
|
+
{ name: "nonce", type: "bytes32" },
|
|
35
|
+
],
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
export async function signTransferAuthorization(
|
|
39
|
+
privateKey: Hex,
|
|
40
|
+
to: Address,
|
|
41
|
+
amount: number,
|
|
42
|
+
chainId: number,
|
|
43
|
+
usdcAddress: Address,
|
|
44
|
+
): Promise<TransferAuthorization> {
|
|
45
|
+
const account = privateKeyToAccount(privateKey);
|
|
46
|
+
const nonce = ("0x" + randomBytes(32).toString("hex")) as Hex;
|
|
47
|
+
|
|
48
|
+
const signature = await account.signTypedData({
|
|
49
|
+
domain: {
|
|
50
|
+
name: "USD Coin",
|
|
51
|
+
version: "2",
|
|
52
|
+
chainId,
|
|
53
|
+
verifyingContract: usdcAddress,
|
|
54
|
+
},
|
|
55
|
+
types: TRANSFER_AUTH_TYPES,
|
|
56
|
+
primaryType: "TransferWithAuthorization",
|
|
57
|
+
message: {
|
|
58
|
+
from: account.address,
|
|
59
|
+
to,
|
|
60
|
+
value: BigInt(amount),
|
|
61
|
+
validAfter: 0n,
|
|
62
|
+
validBefore: 0n,
|
|
63
|
+
nonce,
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const sigHex = signature.slice(2);
|
|
68
|
+
const r = `0x${sigHex.slice(0, 64)}`;
|
|
69
|
+
const s = `0x${sigHex.slice(64, 128)}`;
|
|
70
|
+
const v = parseInt(sigHex.slice(128, 130), 16);
|
|
71
|
+
|
|
72
|
+
return { from: account.address, to, amount, nonce, v, r, s };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function combinedSignature(auth: TransferAuthorization): string {
|
|
76
|
+
const r = auth.r.startsWith("0x") ? auth.r.slice(2) : auth.r;
|
|
77
|
+
const s = auth.s.startsWith("0x") ? auth.s.slice(2) : auth.s;
|
|
78
|
+
return `0x${r}${s}${auth.v.toString(16).padStart(2, "0")}`;
|
|
79
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
export { PayClient, DEFAULT_API_URL } from "./client.js";
|
|
2
|
-
export type { PayClientOptions } from "./client.js";
|
|
3
|
-
|
|
4
|
-
export {
|
|
5
|
-
PayError,
|
|
6
|
-
PayValidationError,
|
|
7
|
-
PayNetworkError,
|
|
8
|
-
PayServerError,
|
|
9
|
-
PayInsufficientFundsError,
|
|
10
|
-
} from "./errors.js";
|
|
11
|
-
|
|
12
|
-
export type {
|
|
13
|
-
DirectPaymentResult,
|
|
14
|
-
DiscoverOptions,
|
|
15
|
-
DiscoverService,
|
|
16
|
-
Tab,
|
|
17
|
-
TabStatus,
|
|
18
|
-
StatusResponse,
|
|
19
|
-
WebhookRegistration,
|
|
20
|
-
} from "./models.js";
|
|
21
|
-
|
|
22
|
-
export type { Signer } from "./signer.js";
|
|
23
|
-
export {
|
|
24
|
-
CliSigner,
|
|
25
|
-
RawKeySigner,
|
|
26
|
-
CallbackSigner,
|
|
27
|
-
createSigner,
|
|
28
|
-
} from "./signer.js";
|
|
29
|
-
|
|
30
|
-
export { OwsSigner } from "./ows-signer.js";
|
|
31
|
-
export type { OwsSignerOptions } from "./ows-signer.js";
|
|
32
|
-
|
|
33
|
-
export { Wallet, PrivateKeySigner } from "./wallet.js";
|
|
34
|
-
export type {
|
|
35
|
-
WalletOptions,
|
|
36
|
-
FundLinkOptions,
|
|
37
|
-
PermitResult,
|
|
38
|
-
} from "./wallet.js";
|
|
39
|
-
|
|
40
|
-
export {
|
|
41
|
-
buildAuthHeaders,
|
|
42
|
-
buildAuthHeadersWithSigner,
|
|
43
|
-
computeEip712Hash,
|
|
44
|
-
} from "./auth.js";
|
|
45
|
-
export type { AuthConfig, AuthHeaders } from "./auth.js";
|
|
46
|
-
|
|
47
|
-
export {
|
|
48
|
-
signTransferAuthorization,
|
|
49
|
-
combinedSignature,
|
|
50
|
-
} from "./eip3009.js";
|
|
51
|
-
export type { TransferAuthorization } from "./eip3009.js";
|
|
1
|
+
export { PayClient, DEFAULT_API_URL } from "./client.js";
|
|
2
|
+
export type { PayClientOptions } from "./client.js";
|
|
3
|
+
|
|
4
|
+
export {
|
|
5
|
+
PayError,
|
|
6
|
+
PayValidationError,
|
|
7
|
+
PayNetworkError,
|
|
8
|
+
PayServerError,
|
|
9
|
+
PayInsufficientFundsError,
|
|
10
|
+
} from "./errors.js";
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
DirectPaymentResult,
|
|
14
|
+
DiscoverOptions,
|
|
15
|
+
DiscoverService,
|
|
16
|
+
Tab,
|
|
17
|
+
TabStatus,
|
|
18
|
+
StatusResponse,
|
|
19
|
+
WebhookRegistration,
|
|
20
|
+
} from "./models.js";
|
|
21
|
+
|
|
22
|
+
export type { Signer } from "./signer.js";
|
|
23
|
+
export {
|
|
24
|
+
CliSigner,
|
|
25
|
+
RawKeySigner,
|
|
26
|
+
CallbackSigner,
|
|
27
|
+
createSigner,
|
|
28
|
+
} from "./signer.js";
|
|
29
|
+
|
|
30
|
+
export { OwsSigner } from "./ows-signer.js";
|
|
31
|
+
export type { OwsSignerOptions } from "./ows-signer.js";
|
|
32
|
+
|
|
33
|
+
export { Wallet, PrivateKeySigner } from "./wallet.js";
|
|
34
|
+
export type {
|
|
35
|
+
WalletOptions,
|
|
36
|
+
FundLinkOptions,
|
|
37
|
+
PermitResult,
|
|
38
|
+
} from "./wallet.js";
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
buildAuthHeaders,
|
|
42
|
+
buildAuthHeadersWithSigner,
|
|
43
|
+
computeEip712Hash,
|
|
44
|
+
} from "./auth.js";
|
|
45
|
+
export type { AuthConfig, AuthHeaders } from "./auth.js";
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
signTransferAuthorization,
|
|
49
|
+
combinedSignature,
|
|
50
|
+
} from "./eip3009.js";
|
|
51
|
+
export type { TransferAuthorization } from "./eip3009.js";
|
package/src/models.ts
CHANGED
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
/** Tab lifecycle states. */
|
|
2
|
-
export type TabStatus = "open" | "closed";
|
|
3
|
-
|
|
4
|
-
/** Result of a direct payment. */
|
|
5
|
-
export interface DirectPaymentResult {
|
|
6
|
-
txHash: string;
|
|
7
|
-
status: string;
|
|
8
|
-
/** Amount in USDC micro-units (6 decimals). */
|
|
9
|
-
amount: number;
|
|
10
|
-
/** Fee deducted in USDC micro-units. */
|
|
11
|
-
fee: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/** Tab state. */
|
|
15
|
-
export interface Tab {
|
|
16
|
-
tabId: string;
|
|
17
|
-
provider: string;
|
|
18
|
-
/** Total locked amount in USDC micro-units. */
|
|
19
|
-
amount: number;
|
|
20
|
-
/** Remaining balance in USDC micro-units. */
|
|
21
|
-
balanceRemaining: number;
|
|
22
|
-
/** Total charged so far in USDC micro-units. */
|
|
23
|
-
totalCharged: number;
|
|
24
|
-
/** Number of charges made. */
|
|
25
|
-
chargeCount: number;
|
|
26
|
-
/** Max per-charge limit in USDC micro-units. */
|
|
27
|
-
maxChargePerCall: number;
|
|
28
|
-
/** Total withdrawn so far in USDC micro-units. */
|
|
29
|
-
totalWithdrawn: number;
|
|
30
|
-
status: TabStatus;
|
|
31
|
-
/** Number of charges buffered awaiting batch settlement. */
|
|
32
|
-
pendingChargeCount: number;
|
|
33
|
-
/** Total amount of pending charges in USDC micro-units. */
|
|
34
|
-
pendingChargeTotal: number;
|
|
35
|
-
/** balance_remaining minus pending charges — the true available balance. */
|
|
36
|
-
effectiveBalance: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Wallet status. */
|
|
40
|
-
export interface StatusResponse {
|
|
41
|
-
address: string;
|
|
42
|
-
/** USDC balance in micro-units. */
|
|
43
|
-
balance: number;
|
|
44
|
-
openTabs: Tab[];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Discoverable service from the facilitator catalog. */
|
|
48
|
-
export interface DiscoverService {
|
|
49
|
-
name: string;
|
|
50
|
-
description: string;
|
|
51
|
-
/** Public base URL for pay request (e.g. "https://weather.example.com"). */
|
|
52
|
-
baseUrl: string;
|
|
53
|
-
category: string;
|
|
54
|
-
keywords: string[];
|
|
55
|
-
routes: { path: string; method?: string; price?: string; settlement?: string; free?: boolean }[];
|
|
56
|
-
/** URL to API documentation (OpenAPI spec, docs page, etc). */
|
|
57
|
-
docsUrl?: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/** Options for discover search. */
|
|
61
|
-
export interface DiscoverOptions {
|
|
62
|
-
/** Search query (matches keywords and description). */
|
|
63
|
-
query?: string;
|
|
64
|
-
/** Sort order: "volume" (default), "newest", "price_asc", "price_desc". */
|
|
65
|
-
sort?: string;
|
|
66
|
-
/** Filter by category. */
|
|
67
|
-
category?: string;
|
|
68
|
-
/** Filter by settlement mode: "direct" or "tab". */
|
|
69
|
-
settlement?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Registered webhook. */
|
|
73
|
-
export interface WebhookRegistration {
|
|
74
|
-
webhookId: string;
|
|
75
|
-
url: string;
|
|
76
|
-
events: string[];
|
|
77
|
-
}
|
|
1
|
+
/** Tab lifecycle states. */
|
|
2
|
+
export type TabStatus = "open" | "closed";
|
|
3
|
+
|
|
4
|
+
/** Result of a direct payment. */
|
|
5
|
+
export interface DirectPaymentResult {
|
|
6
|
+
txHash: string;
|
|
7
|
+
status: string;
|
|
8
|
+
/** Amount in USDC micro-units (6 decimals). */
|
|
9
|
+
amount: number;
|
|
10
|
+
/** Fee deducted in USDC micro-units. */
|
|
11
|
+
fee: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Tab state. */
|
|
15
|
+
export interface Tab {
|
|
16
|
+
tabId: string;
|
|
17
|
+
provider: string;
|
|
18
|
+
/** Total locked amount in USDC micro-units. */
|
|
19
|
+
amount: number;
|
|
20
|
+
/** Remaining balance in USDC micro-units. */
|
|
21
|
+
balanceRemaining: number;
|
|
22
|
+
/** Total charged so far in USDC micro-units. */
|
|
23
|
+
totalCharged: number;
|
|
24
|
+
/** Number of charges made. */
|
|
25
|
+
chargeCount: number;
|
|
26
|
+
/** Max per-charge limit in USDC micro-units. */
|
|
27
|
+
maxChargePerCall: number;
|
|
28
|
+
/** Total withdrawn so far in USDC micro-units. */
|
|
29
|
+
totalWithdrawn: number;
|
|
30
|
+
status: TabStatus;
|
|
31
|
+
/** Number of charges buffered awaiting batch settlement. */
|
|
32
|
+
pendingChargeCount: number;
|
|
33
|
+
/** Total amount of pending charges in USDC micro-units. */
|
|
34
|
+
pendingChargeTotal: number;
|
|
35
|
+
/** balance_remaining minus pending charges — the true available balance. */
|
|
36
|
+
effectiveBalance: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Wallet status. */
|
|
40
|
+
export interface StatusResponse {
|
|
41
|
+
address: string;
|
|
42
|
+
/** USDC balance in micro-units. */
|
|
43
|
+
balance: number;
|
|
44
|
+
openTabs: Tab[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Discoverable service from the facilitator catalog. */
|
|
48
|
+
export interface DiscoverService {
|
|
49
|
+
name: string;
|
|
50
|
+
description: string;
|
|
51
|
+
/** Public base URL for pay request (e.g. "https://weather.example.com"). */
|
|
52
|
+
baseUrl: string;
|
|
53
|
+
category: string;
|
|
54
|
+
keywords: string[];
|
|
55
|
+
routes: { path: string; method?: string; price?: string; settlement?: string; free?: boolean }[];
|
|
56
|
+
/** URL to API documentation (OpenAPI spec, docs page, etc). */
|
|
57
|
+
docsUrl?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Options for discover search. */
|
|
61
|
+
export interface DiscoverOptions {
|
|
62
|
+
/** Search query (matches keywords and description). */
|
|
63
|
+
query?: string;
|
|
64
|
+
/** Sort order: "volume" (default), "newest", "price_asc", "price_desc". */
|
|
65
|
+
sort?: string;
|
|
66
|
+
/** Filter by category. */
|
|
67
|
+
category?: string;
|
|
68
|
+
/** Filter by settlement mode: "direct" or "tab". */
|
|
69
|
+
settlement?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Registered webhook. */
|
|
73
|
+
export interface WebhookRegistration {
|
|
74
|
+
webhookId: string;
|
|
75
|
+
url: string;
|
|
76
|
+
events: string[];
|
|
77
|
+
}
|