forked from MetaMask/smart-accounts-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathx402Client.ts
More file actions
116 lines (98 loc) · 3.27 KB
/
Copy pathx402Client.ts
File metadata and controls
116 lines (98 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { type Hex, getAddress, isHex } from './ethereum';
export type x402PaymentRequirements = {
scheme: string;
network: string;
asset: string;
amount: string;
payTo: string;
maxTimeoutSeconds: number;
extra?: Record<string, unknown>;
};
export type x402PaymentPayloadResult = {
x402Version: number;
payload: Record<string, unknown>;
extensions?: Record<string, unknown>;
};
export type x402DelegationPaymentPayload = {
delegationManager: Hex;
permissionContext: Hex;
delegator: Hex;
};
export type x402DelegationProvider = (
paymentRequirements: x402PaymentRequirements,
) => Promise<x402DelegationPaymentPayload>;
export type x402SchemeNetworkClientLike = {
readonly scheme: string;
createPaymentPayload: (
x402Version: number,
paymentRequirements: x402PaymentRequirements,
context?: Record<string, unknown>,
) => Promise<x402PaymentPayloadResult>;
};
export type x402Erc7710ClientConfig = {
delegationProvider: x402DelegationProvider;
fallbackClient?: x402SchemeNetworkClientLike;
};
/**
* Normalize and validate a delegation payload before publishing it.
*
* @param payload - Delegation payload returned by the configured provider.
* @returns The normalized payload with checksum addresses.
*/
function normalizeDelegationPayload(
payload: x402DelegationPaymentPayload,
): x402DelegationPaymentPayload {
if (!isHex(payload.permissionContext) || payload.permissionContext === '0x') {
throw new Error(
'Invalid delegation payload: permissionContext must be non-empty hex data',
);
}
return {
delegationManager: getAddress(payload.delegationManager),
permissionContext: payload.permissionContext,
delegator: getAddress(payload.delegator),
};
}
/**
* x402 `SchemeNetworkClient`-compatible implementation for ERC-7710 payments.
*
* This class uses structural typing and intentionally does not import x402 types,
* so it can be consumed without adding a direct dependency on x402 packages.
*/
export class x402Erc7710Client {
readonly scheme = 'exact';
readonly #delegationProvider: x402DelegationProvider;
readonly #fallbackClient?: x402SchemeNetworkClientLike;
constructor(config: x402Erc7710ClientConfig) {
this.#delegationProvider = config.delegationProvider;
this.#fallbackClient = config.fallbackClient;
}
async createPaymentPayload(
x402Version: number,
paymentRequirements: x402PaymentRequirements,
context?: Record<string, unknown>,
): Promise<x402PaymentPayloadResult> {
const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod;
if (assetTransferMethod !== 'erc7710') {
if (this.#fallbackClient) {
return this.#fallbackClient.createPaymentPayload(
x402Version,
paymentRequirements,
context,
);
}
const invalidAssetTransferMethod =
typeof assetTransferMethod === 'string'
? `"${assetTransferMethod}"`
: JSON.stringify(assetTransferMethod);
throw new Error(
`x402Erc7710Client can only process assetTransferMethod "erc7710". Received: ${invalidAssetTransferMethod}`,
);
}
const delegation = await this.#delegationProvider(paymentRequirements);
return {
x402Version,
payload: normalizeDelegationPayload(delegation),
};
}
}