@x402r/extensions 0.0.0
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/package.json +37 -0
- package/refund.d.ts +253 -0
- package/refund.js +2 -0
- package/refund.mjs +2 -0
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@x402r/extensions",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "x402 extensions - parent package for x402 extensions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./index.js",
|
|
7
|
+
"types": "./index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./refund": {
|
|
10
|
+
"types": "./refund.d.ts",
|
|
11
|
+
"import": "./refund.mjs",
|
|
12
|
+
"require": "./refund.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"refund.mjs",
|
|
18
|
+
"refund.js",
|
|
19
|
+
"refund.d.ts"
|
|
20
|
+
],
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"author": "Coinbase Inc.",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/BackTrackCo/x402r-extensions.git"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@x402r/refund": "^0.0.0"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@x402/core": "^2.0.0",
|
|
35
|
+
"@x402/evm": "^2.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/refund.d.ts
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { PaymentOption, RoutesConfig } from '@x402/core/http';
|
|
2
|
+
import { PaymentPayload, PaymentRequirements, SettleResponse } from '@x402/core/types';
|
|
3
|
+
import { FacilitatorEvmSigner } from '@x402/evm';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type definitions for the Refund Helper Extension
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Extension identifier constant for the refund extension
|
|
11
|
+
*/
|
|
12
|
+
declare const REFUND_EXTENSION_KEY = "refund";
|
|
13
|
+
/**
|
|
14
|
+
* Constant for the refund marker key (internal marker)
|
|
15
|
+
* Used to identify refundable payment options
|
|
16
|
+
* The merchantPayout is read directly from the option's payTo field when processing
|
|
17
|
+
*/
|
|
18
|
+
declare const REFUND_MARKER_KEY = "_x402_refund";
|
|
19
|
+
/**
|
|
20
|
+
* Refund extension info structure
|
|
21
|
+
*
|
|
22
|
+
* merchantPayouts: Map of proxy address -> merchantPayout
|
|
23
|
+
* This allows multiple refundable options with different merchantPayouts
|
|
24
|
+
*/
|
|
25
|
+
interface RefundExtensionInfo {
|
|
26
|
+
factoryAddress: string;
|
|
27
|
+
merchantPayouts: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Refund extension structure (matches extension pattern with info and schema)
|
|
31
|
+
*/
|
|
32
|
+
interface RefundExtension {
|
|
33
|
+
info: RefundExtensionInfo;
|
|
34
|
+
schema: {
|
|
35
|
+
$schema: "https://json-schema.org/draft/2020-12/schema";
|
|
36
|
+
type: "object";
|
|
37
|
+
properties: {
|
|
38
|
+
factoryAddress: {
|
|
39
|
+
type: "string";
|
|
40
|
+
pattern: "^0x[a-fA-F0-9]{40}$";
|
|
41
|
+
description: "The X402DepositRelayFactory contract address";
|
|
42
|
+
};
|
|
43
|
+
merchantPayouts: {
|
|
44
|
+
type: "object";
|
|
45
|
+
additionalProperties: {
|
|
46
|
+
type: "string";
|
|
47
|
+
pattern: "^0x[a-fA-F0-9]{40}$";
|
|
48
|
+
};
|
|
49
|
+
description: "Map of proxy address to merchant payout address";
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
required: ["factoryAddress", "merchantPayouts"];
|
|
53
|
+
additionalProperties: false;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Type guard to check if a payment option is refundable
|
|
58
|
+
* A refundable option has a marker stored in extra
|
|
59
|
+
*
|
|
60
|
+
* @param option - The payment option to check
|
|
61
|
+
* @returns True if the option is refundable
|
|
62
|
+
*/
|
|
63
|
+
declare function isRefundableOption(option: PaymentOption): boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Server-side helpers for the Refund Helper Extension
|
|
67
|
+
*
|
|
68
|
+
* These helpers allow merchants to mark payment options as refundable
|
|
69
|
+
* and process route configurations to route payments to X402DepositRelayProxy contracts.
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Declares a refund extension with factory address and merchantPayouts map
|
|
74
|
+
*
|
|
75
|
+
* @param factoryAddress - The X402DepositRelayFactory contract address
|
|
76
|
+
* @param merchantPayouts - Map of proxy address to merchant payout address
|
|
77
|
+
* @returns Refund extension object with info and schema
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const extension = declareRefundExtension("0xFactory123...", {
|
|
82
|
+
* "0xProxy1...": "0xMerchant1...",
|
|
83
|
+
* "0xProxy2...": "0xMerchant2...",
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
declare function declareRefundExtension(factoryAddress: string, merchantPayouts: Record<string, string>): Record<string, RefundExtension>;
|
|
88
|
+
/**
|
|
89
|
+
* Marks a payment option as refundable.
|
|
90
|
+
*
|
|
91
|
+
* This function marks the option as refundable so it can be processed by `withRefund()`.
|
|
92
|
+
* The merchantPayout is read directly from the option's `payTo` field when processing.
|
|
93
|
+
*
|
|
94
|
+
* @param option - The payment option to mark as refundable
|
|
95
|
+
* @returns A new PaymentOption marked as refundable (does not mutate original)
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const refundableOption = refundable({
|
|
100
|
+
* scheme: "exact",
|
|
101
|
+
* payTo: "0xmerchant123...",
|
|
102
|
+
* price: "$0.01",
|
|
103
|
+
* network: "eip155:84532",
|
|
104
|
+
* });
|
|
105
|
+
* // refundableOption.extra._x402_refund = true
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
declare function refundable(option: PaymentOption): PaymentOption;
|
|
109
|
+
/**
|
|
110
|
+
* Processes route configuration to handle refundable payment options.
|
|
111
|
+
*
|
|
112
|
+
* This function finds all payment options marked with `refundable()` and:
|
|
113
|
+
* 1. Computes the proxy address using CREATE3 (no bytecode needed!)
|
|
114
|
+
* 2. Sets `payTo` to the proxy address
|
|
115
|
+
* 3. Adds the refund extension with factory address
|
|
116
|
+
*
|
|
117
|
+
* @param routes - Route configuration (single RouteConfig or Record<string, RouteConfig>)
|
|
118
|
+
* @param factoryAddress - The X402DepositRelayFactory contract address (required)
|
|
119
|
+
* @param createxAddress - The CreateX contract address (optional, will use standard address for network if not provided)
|
|
120
|
+
* @returns A new RoutesConfig with refundable options routed to proxy (deep cloned, does not mutate original)
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const routes = {
|
|
125
|
+
* "/api": {
|
|
126
|
+
* accepts: refundable({
|
|
127
|
+
* scheme: "exact",
|
|
128
|
+
* payTo: "0xmerchant123...",
|
|
129
|
+
* price: "$0.01",
|
|
130
|
+
* network: "eip155:84532",
|
|
131
|
+
* }),
|
|
132
|
+
* },
|
|
133
|
+
* };
|
|
134
|
+
*
|
|
135
|
+
* // Version is optional - defaults to config file value
|
|
136
|
+
* // CreateX address is optional - uses standard address for the network
|
|
137
|
+
* const processedRoutes = withRefund(routes, "0xFactory123...");
|
|
138
|
+
* // processedRoutes["/api"].accepts.payTo = computed proxy address
|
|
139
|
+
* // processedRoutes["/api"].extensions.refund = { info: { factoryAddress: "0xFactory123..." }, schema: {...} }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
declare function withRefund(routes: RoutesConfig, factoryAddress: string, createxAddress?: string): RoutesConfig;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Helper to compute CREATE3 address for RelayProxy
|
|
146
|
+
*
|
|
147
|
+
* Uses the CREATE3 formula via CreateX (matching Solidity implementation):
|
|
148
|
+
*
|
|
149
|
+
* Where:
|
|
150
|
+
* - salt = keccak256(abi.encodePacked(factoryAddress, merchantPayout))
|
|
151
|
+
* - guardedSalt = keccak256(abi.encode(salt)) // CreateX guards the salt
|
|
152
|
+
* - createxDeployer = the CreateX contract address
|
|
153
|
+
*
|
|
154
|
+
* CREATE3 is much simpler than CREATE2 - no bytecode needed!
|
|
155
|
+
* The address depends only on the deployer (CreateX) and salt.
|
|
156
|
+
*
|
|
157
|
+
* IMPORTANT: The CreateX address must match the one used by the factory contract.
|
|
158
|
+
* The factory stores its CreateX address and can be queried via factory.getCreateX().
|
|
159
|
+
* This function computes addresses locally without any on-chain calls.
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* Computes the CREATE3 address for a merchant's relay proxy
|
|
163
|
+
*
|
|
164
|
+
* This matches the Solidity implementation in DepositRelayFactory.getRelayAddress():
|
|
165
|
+
* 1. salt = keccak256(abi.encodePacked(merchantPayout))
|
|
166
|
+
* 2. guardedSalt = keccak256(abi.encode(salt)) // CreateX guards the salt
|
|
167
|
+
* 3. return CREATEX.computeCreate3Address(guardedSalt)
|
|
168
|
+
*
|
|
169
|
+
* Uses the @whoislewys/predict-deterministic-address library which correctly
|
|
170
|
+
* implements the CREATE3 formula used by CreateX (based on Solady's CREATE3).
|
|
171
|
+
* This ensures the computed address matches the factory's on-chain computation
|
|
172
|
+
* without requiring any on-chain calls.
|
|
173
|
+
*
|
|
174
|
+
* @param createxAddress - The CreateX contract address
|
|
175
|
+
* @param factoryAddress - The DepositRelayFactory contract address
|
|
176
|
+
* @param merchantPayout - The merchant's payout address
|
|
177
|
+
* @returns The deterministic proxy address
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* // No bytecode needed! Computes locally without on-chain calls.
|
|
182
|
+
* const relayAddress = computeRelayAddress(
|
|
183
|
+
* "0xCreateX123...",
|
|
184
|
+
* "0xMerchant123...",
|
|
185
|
+
* 0n // version
|
|
186
|
+
* );
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
declare function computeRelayAddress(createxAddress: string, factoryAddress: string, merchantPayout: string): string;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Facilitator-side helpers for the Refund Helper Extension
|
|
193
|
+
*
|
|
194
|
+
* These helpers allow facilitator operators to validate refund info
|
|
195
|
+
* and handle refund settlements via X402DepositRelayProxy contracts.
|
|
196
|
+
*/
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Extracts refund extension info from payment payload or requirements
|
|
200
|
+
*
|
|
201
|
+
* @param paymentPayload - The payment payload (may contain extensions)
|
|
202
|
+
* @param _ - The payment requirements (currently unused, kept for API compatibility)
|
|
203
|
+
* @returns Refund extension info if valid, null otherwise
|
|
204
|
+
*/
|
|
205
|
+
declare function extractRefundInfo(paymentPayload: PaymentPayload, _: PaymentRequirements): {
|
|
206
|
+
factoryAddress: string;
|
|
207
|
+
merchantPayouts: Record<string, string>;
|
|
208
|
+
} | null;
|
|
209
|
+
/**
|
|
210
|
+
* Helper for facilitator operators to handle refund settlements via X402DepositRelayProxy.
|
|
211
|
+
*
|
|
212
|
+
* This function:
|
|
213
|
+
* 1. Extracts refund extension info (factory address)
|
|
214
|
+
* 2. Validates factory exists
|
|
215
|
+
* 3. Reads merchantPayout and escrow directly from proxy storage
|
|
216
|
+
* 4. Checks if merchant is registered
|
|
217
|
+
* 5. Deploys relay on-demand if needed (via factory)
|
|
218
|
+
* 6. Calls proxy.executeDeposit() to deposit funds into escrow
|
|
219
|
+
*
|
|
220
|
+
* Returns null if refund is not applicable (delegates to normal flow).
|
|
221
|
+
* Throws error on execution failure or if merchant not registered (facilitator should handle in hook).
|
|
222
|
+
*
|
|
223
|
+
* @param paymentPayload - The payment payload containing authorization and signature
|
|
224
|
+
* @param paymentRequirements - The payment requirements containing refund extension
|
|
225
|
+
* @param signer - The EVM signer for contract interactions
|
|
226
|
+
* @returns SettleResponse on success, null if not applicable
|
|
227
|
+
* @throws Error on execution failure or if merchant not registered
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* facilitator.onBeforeSettle(async (context) => {
|
|
232
|
+
* try {
|
|
233
|
+
* const result = await settleWithRefundHelper(
|
|
234
|
+
* context.paymentPayload,
|
|
235
|
+
* context.paymentRequirements,
|
|
236
|
+
* signer,
|
|
237
|
+
* );
|
|
238
|
+
*
|
|
239
|
+
* if (result) {
|
|
240
|
+
* return { abort: true, reason: 'handled_by_refund_helper' };
|
|
241
|
+
* }
|
|
242
|
+
* } catch (error) {
|
|
243
|
+
* // Log error but don't abort - let normal settlement proceed
|
|
244
|
+
* console.error('Refund helper settlement failed:', error);
|
|
245
|
+
* }
|
|
246
|
+
*
|
|
247
|
+
* return null; // Proceed with normal settlement
|
|
248
|
+
* });
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
declare function settleWithRefundHelper(paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, signer: FacilitatorEvmSigner): Promise<SettleResponse | null>;
|
|
252
|
+
|
|
253
|
+
export { REFUND_EXTENSION_KEY, REFUND_MARKER_KEY, type RefundExtension, type RefundExtensionInfo, computeRelayAddress, declareRefundExtension, extractRefundInfo, isRefundableOption, refundable, settleWithRefundHelper, withRefund };
|
package/refund.js
ADDED
package/refund.mjs
ADDED