forked from MetaMask/smart-accounts-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathx402Server.ts
More file actions
108 lines (92 loc) · 3.01 KB
/
Copy pathx402Server.ts
File metadata and controls
108 lines (92 loc) · 3.01 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
import { type Address, getAddress } from './ethereum';
import type { x402PaymentRequirements } from './x402Client';
export type x402Erc7710ServerConfig = {
allowAssetTransferMethodOverride?: boolean;
};
/**
* Validate and normalize optional facilitator address metadata.
*
* @param publishedAddresses - Optional facilitator address list from `supportedKind.extra`.
* @returns A normalized checksum address list, or `undefined` when no list is provided.
*/
function validateFacilitatorAddresses(
publishedAddresses: unknown,
): Address[] | undefined {
if (publishedAddresses === undefined) {
return undefined;
}
if (!Array.isArray(publishedAddresses)) {
throw new Error(
'Invalid facilitatorAddresses specified: expected an array of addresses',
);
}
if (publishedAddresses.length === 0) {
throw new Error(
'Invalid facilitatorAddresses specified: expected at least one address',
);
}
const normalizedAddresses: Address[] = [];
const validationErrors: string[] = [];
publishedAddresses.forEach((address, index) => {
if (typeof address !== 'string') {
validationErrors.push(`facilitatorAddresses[${index}] must be a string`);
return;
}
try {
normalizedAddresses.push(getAddress(address));
} catch {
validationErrors.push(
`facilitatorAddresses[${index}] is not a valid address: "${address}"`,
);
}
});
if (validationErrors.length > 0) {
throw new Error(
`Invalid facilitatorAddresses specified: ${validationErrors.join('; ')}`,
);
}
return normalizedAddresses;
}
/**
* x402 `SchemeNetworkServer`-compatible implementation for publishing
* `assetTransferMethod: "erc7710"` in payment requirements.
*
* 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 x402Erc7710Server {
readonly scheme = 'exact';
readonly #allowAssetTransferMethodOverride: boolean;
constructor(config?: x402Erc7710ServerConfig) {
this.#allowAssetTransferMethodOverride =
config?.allowAssetTransferMethodOverride ?? false;
}
async enhancePaymentRequirements(
paymentRequirements: x402PaymentRequirements,
supportedKind: {
extra?: Record<string, unknown>;
},
): Promise<x402PaymentRequirements> {
const existingMethod = paymentRequirements.extra?.assetTransferMethod;
if (
typeof existingMethod === 'string' &&
existingMethod !== 'erc7710' &&
!this.#allowAssetTransferMethodOverride
) {
throw new Error(
`Cannot overwrite existing assetTransferMethod "${existingMethod}" with "erc7710"`,
);
}
const facilitatorAddresses = validateFacilitatorAddresses(
supportedKind.extra?.facilitatorAddresses,
);
return {
...paymentRequirements,
extra: {
...(paymentRequirements.extra ?? {}),
...(facilitatorAddresses ? { facilitatorAddresses } : {}),
assetTransferMethod: 'erc7710',
},
};
}
}