@atxp/client 0.5.1 → 0.6.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/dist/atxpAccount.js +26 -11
- package/dist/atxpAccount.js.map +1 -1
- package/dist/atxpClient.js +4 -17
- package/dist/atxpClient.js.map +1 -1
- package/dist/atxpFetcher.js +96 -4
- package/dist/atxpFetcher.js.map +1 -1
- package/dist/atxpLocalAccount.js +102 -0
- package/dist/atxpLocalAccount.js.map +1 -0
- package/dist/baseAccount.js +13 -5
- package/dist/baseAccount.js.map +1 -1
- package/dist/basePaymentMaker.js.map +1 -1
- package/dist/index.cjs +240 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +77 -74
- package/dist/index.js +241 -40
- package/dist/index.js.map +1 -1
- package/dist/solanaPaymentMaker.js +4 -2
- package/dist/solanaPaymentMaker.js.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Currency, AuthorizationServerUrl, Network, OAuthDb, FetchLike, Logger, OAuthResourceClient, ClientCredentials, PKCEValues, AccessToken
|
|
1
|
+
import { Currency, AuthorizationServerUrl, Network, OAuthDb, FetchLike, Logger, OAuthResourceClient, ClientCredentials, PKCEValues, AccessToken } from '@atxp/common';
|
|
2
2
|
import { ClientOptions, Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
-
import { Implementation
|
|
3
|
+
import { Implementation } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
5
5
|
import * as oauth from 'oauth4webapi';
|
|
6
6
|
import { ValidateTransferError as ValidateTransferError$1 } from '@solana/pay';
|
|
7
7
|
import BigNumber$1 from 'bignumber.js';
|
|
8
|
-
import { WalletClient, PublicActions } from 'viem';
|
|
8
|
+
import { WalletClient, PublicActions, LocalAccount, Address, TypedData, Hex as Hex$1, SignableMessage, TransactionSerializable } from 'viem';
|
|
9
9
|
|
|
10
10
|
type Hex = `0x${string}`;
|
|
11
11
|
type AccountPrefix = Network;
|
|
@@ -54,6 +54,11 @@ type ClientConfig = {
|
|
|
54
54
|
error: Error;
|
|
55
55
|
}) => Promise<void>;
|
|
56
56
|
};
|
|
57
|
+
type RequiredClientConfigFields$1 = 'mcpServer' | 'account';
|
|
58
|
+
type RequiredClientConfig = Pick<ClientConfig, RequiredClientConfigFields$1>;
|
|
59
|
+
type OptionalClientConfig$1 = Omit<ClientConfig, RequiredClientConfigFields$1>;
|
|
60
|
+
type ClientArgs = RequiredClientConfig & Partial<OptionalClientConfig$1>;
|
|
61
|
+
type FetchWrapper = (config: ClientArgs) => FetchLike;
|
|
57
62
|
declare class InsufficientFundsError extends Error {
|
|
58
63
|
readonly currency: Currency;
|
|
59
64
|
readonly required: BigNumber;
|
|
@@ -74,9 +79,7 @@ interface PaymentMaker {
|
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
type RequiredClientConfigFields = 'mcpServer' | 'account';
|
|
77
|
-
type RequiredClientConfig = Pick<ClientConfig, RequiredClientConfigFields>;
|
|
78
82
|
type OptionalClientConfig = Omit<ClientConfig, RequiredClientConfigFields>;
|
|
79
|
-
type ClientArgs = RequiredClientConfig & Partial<OptionalClientConfig>;
|
|
80
83
|
type BuildableClientConfigFields = 'oAuthDb' | 'logger';
|
|
81
84
|
declare const DEFAULT_CLIENT_CONFIG: Required<Omit<OptionalClientConfig, BuildableClientConfigFields>>;
|
|
82
85
|
declare function buildClientConfig(args: ClientArgs): ClientConfig;
|
|
@@ -124,73 +127,14 @@ declare class OAuthClient extends OAuthResourceClient {
|
|
|
124
127
|
protected _doFetch: FetchLike;
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
strict?: boolean;
|
|
136
|
-
allowInsecureRequests?: boolean;
|
|
137
|
-
allowedAuthorizationServers?: AuthorizationServerUrl[];
|
|
138
|
-
approvePayment?: (payment: ProspectivePayment) => Promise<boolean>;
|
|
139
|
-
logger?: Logger;
|
|
140
|
-
onAuthorize?: (args: {
|
|
141
|
-
authorizationServer: AuthorizationServerUrl;
|
|
142
|
-
userId: string;
|
|
143
|
-
}) => Promise<void>;
|
|
144
|
-
onAuthorizeFailure?: (args: {
|
|
145
|
-
authorizationServer: AuthorizationServerUrl;
|
|
146
|
-
userId: string;
|
|
147
|
-
error: Error;
|
|
148
|
-
}) => Promise<void>;
|
|
149
|
-
onPayment?: (args: {
|
|
150
|
-
payment: ProspectivePayment;
|
|
151
|
-
}) => Promise<void>;
|
|
152
|
-
onPaymentFailure?: (args: {
|
|
153
|
-
payment: ProspectivePayment;
|
|
154
|
-
error: Error;
|
|
155
|
-
}) => Promise<void>;
|
|
156
|
-
}
|
|
157
|
-
declare function atxpFetch(config: ATXPFetcherConfig): FetchLike;
|
|
158
|
-
declare class ATXPFetcher {
|
|
159
|
-
protected oauthClient: OAuthClient;
|
|
160
|
-
protected paymentMakers: Map<string, PaymentMaker>;
|
|
161
|
-
protected sideChannelFetch: FetchLike;
|
|
162
|
-
protected db: OAuthDb;
|
|
163
|
-
protected accountId: string;
|
|
164
|
-
protected allowedAuthorizationServers: AuthorizationServerUrl[];
|
|
165
|
-
protected approvePayment: (payment: ProspectivePayment) => Promise<boolean>;
|
|
166
|
-
protected logger: Logger;
|
|
167
|
-
protected onAuthorize: (args: {
|
|
168
|
-
authorizationServer: AuthorizationServerUrl;
|
|
169
|
-
userId: string;
|
|
170
|
-
}) => Promise<void>;
|
|
171
|
-
protected onAuthorizeFailure: (args: {
|
|
172
|
-
authorizationServer: AuthorizationServerUrl;
|
|
173
|
-
userId: string;
|
|
174
|
-
error: Error;
|
|
175
|
-
}) => Promise<void>;
|
|
176
|
-
protected onPayment: (args: {
|
|
177
|
-
payment: ProspectivePayment;
|
|
178
|
-
}) => Promise<void>;
|
|
179
|
-
protected onPaymentFailure: (args: {
|
|
180
|
-
payment: ProspectivePayment;
|
|
181
|
-
error: Error;
|
|
182
|
-
}) => Promise<void>;
|
|
183
|
-
constructor({ accountId, db, paymentMakers, fetchFn, sideChannelFetch, strict, allowInsecureRequests, allowedAuthorizationServers, approvePayment, logger, onAuthorize, onAuthorizeFailure, onPayment, onPaymentFailure }: ATXPFetcherConfig);
|
|
184
|
-
private defaultPaymentFailureHandler;
|
|
185
|
-
protected handlePaymentRequestError: (paymentRequestError: McpError) => Promise<boolean>;
|
|
186
|
-
protected getPaymentRequestData: (paymentRequestUrl: string) => Promise<PaymentRequestData | null>;
|
|
187
|
-
protected isAllowedAuthServer: (url: string | URL) => boolean;
|
|
188
|
-
protected makeAuthRequestWithPaymentMaker: (authorizationUrl: URL, paymentMaker: PaymentMaker) => Promise<string>;
|
|
189
|
-
protected authToService: (error: OAuthAuthenticationRequiredError) => Promise<void>;
|
|
190
|
-
protected exchangeToken: (myToken: AccessToken, newResourceUrl: string) => Promise<AccessToken>;
|
|
191
|
-
protected checkForATXPResponse: (response: Response) => Promise<void>;
|
|
192
|
-
fetch: FetchLike;
|
|
193
|
-
}
|
|
130
|
+
/**
|
|
131
|
+
* Creates an ATXP fetch wrapper that handles OAuth authentication and payments.
|
|
132
|
+
* This follows the wrapper pattern for fetch functions.
|
|
133
|
+
*
|
|
134
|
+
* @param config - The client configuration
|
|
135
|
+
* @returns A wrapped fetch function that handles ATXP protocol
|
|
136
|
+
*/
|
|
137
|
+
declare function atxpFetch(config: ClientConfig): FetchLike;
|
|
194
138
|
|
|
195
139
|
declare const ValidateTransferError: typeof ValidateTransferError$1;
|
|
196
140
|
declare class SolanaPaymentMaker implements PaymentMaker {
|
|
@@ -230,10 +174,14 @@ declare class ATXPAccount implements Account {
|
|
|
230
174
|
paymentMakers: {
|
|
231
175
|
[key: string]: PaymentMaker;
|
|
232
176
|
};
|
|
177
|
+
origin: string;
|
|
178
|
+
token: string;
|
|
179
|
+
fetchFn: FetchLike;
|
|
233
180
|
constructor(connectionString: string, opts?: {
|
|
234
181
|
fetchFn?: FetchLike;
|
|
235
182
|
network?: Network;
|
|
236
183
|
});
|
|
184
|
+
getSigner(): Promise<LocalAccount>;
|
|
237
185
|
}
|
|
238
186
|
|
|
239
187
|
declare const USDC_CONTRACT_ADDRESS_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
@@ -243,8 +191,63 @@ declare class BaseAccount implements Account {
|
|
|
243
191
|
paymentMakers: {
|
|
244
192
|
[key: string]: PaymentMaker;
|
|
245
193
|
};
|
|
194
|
+
private walletClient;
|
|
195
|
+
private account;
|
|
246
196
|
constructor(baseRPCUrl: string, sourceSecretKey: string);
|
|
197
|
+
/**
|
|
198
|
+
* Get a signer that can be used with the x402 library
|
|
199
|
+
* This is only available for EVM-based accounts
|
|
200
|
+
*/
|
|
201
|
+
getSigner(): LocalAccount;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* ATXP implementation of viem's LocalAccount interface.
|
|
206
|
+
* Delegates signing operations to the accounts-x402 API.
|
|
207
|
+
* Includes properties needed by x402 library for wallet client compatibility.
|
|
208
|
+
*/
|
|
209
|
+
declare class ATXPLocalAccount implements LocalAccount {
|
|
210
|
+
readonly address: Address;
|
|
211
|
+
private origin;
|
|
212
|
+
private token;
|
|
213
|
+
private fetchFn;
|
|
214
|
+
readonly type: "local";
|
|
215
|
+
readonly account: LocalAccount;
|
|
216
|
+
readonly chain: {
|
|
217
|
+
id: number;
|
|
218
|
+
};
|
|
219
|
+
readonly transport: object;
|
|
220
|
+
constructor(address: Address, origin: string, token: string, fetchFn?: FetchLike);
|
|
221
|
+
/**
|
|
222
|
+
* Fetch the wallet address from the /address endpoint
|
|
223
|
+
*/
|
|
224
|
+
static create(origin: string, token: string, fetchFn?: FetchLike): Promise<ATXPLocalAccount>;
|
|
225
|
+
/**
|
|
226
|
+
* Sign a typed data structure using EIP-712
|
|
227
|
+
* This is what x402 library will call for EIP-3009 authorization
|
|
228
|
+
*/
|
|
229
|
+
signTypedData<const TTypedData extends TypedData | {
|
|
230
|
+
[key: string]: unknown;
|
|
231
|
+
}>(typedData: TTypedData): Promise<Hex$1>;
|
|
232
|
+
/**
|
|
233
|
+
* Sign a message - required by LocalAccount interface but not used for X402
|
|
234
|
+
*/
|
|
235
|
+
signMessage(_: {
|
|
236
|
+
message: SignableMessage;
|
|
237
|
+
}): Promise<Hex$1>;
|
|
238
|
+
/**
|
|
239
|
+
* Sign a transaction - required by LocalAccount interface but not used for X402
|
|
240
|
+
*/
|
|
241
|
+
signTransaction(_transaction: TransactionSerializable, _args?: unknown): Promise<Hex$1>;
|
|
242
|
+
/**
|
|
243
|
+
* Get public key - required by LocalAccount interface
|
|
244
|
+
*/
|
|
245
|
+
readonly publicKey: Hex$1;
|
|
246
|
+
/**
|
|
247
|
+
* Source - required by LocalAccount interface (set to 'custom')
|
|
248
|
+
*/
|
|
249
|
+
readonly source: "custom";
|
|
247
250
|
}
|
|
248
251
|
|
|
249
|
-
export { ATXPAccount,
|
|
250
|
-
export type {
|
|
252
|
+
export { ATXPAccount, ATXPLocalAccount, BaseAccount, BasePaymentMaker, DEFAULT_CLIENT_CONFIG, InsufficientFundsError, OAuthAuthenticationRequiredError, OAuthClient, PaymentNetworkError, SolanaAccount, SolanaPaymentMaker, USDC_CONTRACT_ADDRESS_BASE, ValidateTransferError, atxpClient, atxpFetch, buildClientConfig, buildStreamableTransport };
|
|
253
|
+
export type { Account, AccountIdString, ClientArgs, ClientConfig, FetchWrapper, Hex, OAuthClientConfig, PaymentMaker, ProspectivePayment };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { crypto as crypto$1, OAuthResourceClient, ConsoleLogger, PAYMENT_REQUIRED_ERROR_CODE, isSSEResponse, parseMcpMessages, parsePaymentRequests, paymentRequiredError, getIsReactNative, createReactNativeSafeFetch,
|
|
1
|
+
import { crypto as crypto$1, OAuthResourceClient, ConsoleLogger, PAYMENT_REQUIRED_ERROR_CODE, isSSEResponse, parseMcpMessages, parsePaymentRequests, paymentRequiredError, DEFAULT_AUTHORIZATION_SERVER, getIsReactNative, createReactNativeSafeFetch, MemoryOAuthDb, generateJWT } from '@atxp/common';
|
|
2
2
|
import BigNumber$1, { BigNumber } from 'bignumber.js';
|
|
3
3
|
import * as oauth from 'oauth4webapi';
|
|
4
4
|
import { PublicKey, ComputeBudgetProgram, sendAndConfirmTransaction, Connection, Keypair } from '@solana/web3.js';
|
|
@@ -297,18 +297,39 @@ class InsufficientFundsError extends Error {
|
|
|
297
297
|
}
|
|
298
298
|
class PaymentNetworkError extends Error {
|
|
299
299
|
constructor(message, originalError) {
|
|
300
|
-
super(`Payment failed due to network error: ${message}
|
|
300
|
+
super(`Payment failed due to network error: ${message}`);
|
|
301
301
|
this.originalError = originalError;
|
|
302
302
|
this.name = 'PaymentNetworkError';
|
|
303
303
|
}
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Creates an ATXP fetch wrapper that handles OAuth authentication and payments.
|
|
308
|
+
* This follows the wrapper pattern for fetch functions.
|
|
309
|
+
*
|
|
310
|
+
* @param config - The client configuration
|
|
311
|
+
* @returns A wrapped fetch function that handles ATXP protocol
|
|
312
|
+
*/
|
|
306
313
|
function atxpFetch(config) {
|
|
307
|
-
const fetcher = new ATXPFetcher(
|
|
314
|
+
const fetcher = new ATXPFetcher({
|
|
315
|
+
accountId: config.account.accountId,
|
|
316
|
+
db: config.oAuthDb,
|
|
317
|
+
paymentMakers: config.account.paymentMakers,
|
|
318
|
+
fetchFn: config.fetchFn,
|
|
319
|
+
sideChannelFetch: config.oAuthChannelFetch,
|
|
320
|
+
allowInsecureRequests: config.allowHttp,
|
|
321
|
+
allowedAuthorizationServers: config.allowedAuthorizationServers,
|
|
322
|
+
approvePayment: config.approvePayment,
|
|
323
|
+
logger: config.logger,
|
|
324
|
+
onAuthorize: config.onAuthorize,
|
|
325
|
+
onAuthorizeFailure: config.onAuthorizeFailure,
|
|
326
|
+
onPayment: config.onPayment,
|
|
327
|
+
onPaymentFailure: config.onPaymentFailure
|
|
328
|
+
});
|
|
308
329
|
return fetcher.fetch;
|
|
309
330
|
}
|
|
310
331
|
class ATXPFetcher {
|
|
311
|
-
constructor(
|
|
332
|
+
constructor(config) {
|
|
312
333
|
this.defaultPaymentFailureHandler = async ({ payment, error }) => {
|
|
313
334
|
if (error instanceof InsufficientFundsError) {
|
|
314
335
|
this.logger.info(`PAYMENT FAILED: Insufficient ${error.currency} funds on ${payment.network}`);
|
|
@@ -325,6 +346,70 @@ class ATXPFetcher {
|
|
|
325
346
|
this.logger.info(`PAYMENT FAILED: ${error.message}`);
|
|
326
347
|
}
|
|
327
348
|
};
|
|
349
|
+
this.handleMultiDestinationPayment = async (paymentRequestData, paymentRequestUrl, paymentRequestId) => {
|
|
350
|
+
if (!paymentRequestData.destinations || paymentRequestData.destinations.length === 0) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
// Try each destination in order
|
|
354
|
+
for (const dest of paymentRequestData.destinations) {
|
|
355
|
+
const paymentMaker = this.paymentMakers.get(dest.network);
|
|
356
|
+
if (!paymentMaker) {
|
|
357
|
+
this.logger.debug(`ATXP: payment network '${dest.network}' not available, trying next destination`);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
// Convert amount to BigNumber since it comes as a string from JSON
|
|
361
|
+
const amount = new BigNumber(dest.amount);
|
|
362
|
+
const prospectivePayment = {
|
|
363
|
+
accountId: this.accountId,
|
|
364
|
+
resourceUrl: paymentRequestData.resource?.toString() ?? '',
|
|
365
|
+
resourceName: paymentRequestData.resourceName ?? '',
|
|
366
|
+
network: dest.network,
|
|
367
|
+
currency: dest.currency,
|
|
368
|
+
amount: amount,
|
|
369
|
+
iss: paymentRequestData.iss ?? '',
|
|
370
|
+
};
|
|
371
|
+
if (!await this.approvePayment(prospectivePayment)) {
|
|
372
|
+
this.logger.info(`ATXP: payment request denied by callback function for destination on ${dest.network}`);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
let paymentId;
|
|
376
|
+
try {
|
|
377
|
+
paymentId = await paymentMaker.makePayment(amount, dest.currency, dest.address, paymentRequestData.iss);
|
|
378
|
+
this.logger.info(`ATXP: made payment of ${amount.toString()} ${dest.currency} on ${dest.network}: ${paymentId}`);
|
|
379
|
+
await this.onPayment({ payment: prospectivePayment });
|
|
380
|
+
// Submit payment to the server
|
|
381
|
+
const jwt = await paymentMaker.generateJWT({ paymentRequestId, codeChallenge: '' });
|
|
382
|
+
const response = await this.sideChannelFetch(paymentRequestUrl.toString(), {
|
|
383
|
+
method: 'PUT',
|
|
384
|
+
headers: {
|
|
385
|
+
'Authorization': `Bearer ${jwt}`,
|
|
386
|
+
'Content-Type': 'application/json'
|
|
387
|
+
},
|
|
388
|
+
body: JSON.stringify({
|
|
389
|
+
transactionId: paymentId,
|
|
390
|
+
network: dest.network,
|
|
391
|
+
currency: dest.currency
|
|
392
|
+
})
|
|
393
|
+
});
|
|
394
|
+
this.logger.debug(`ATXP: payment was ${response.ok ? 'successfully' : 'not successfully'} PUT to ${paymentRequestUrl} : status ${response.status} ${response.statusText}`);
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
const msg = `ATXP: payment to ${paymentRequestUrl} failed: HTTP ${response.status} ${await response.text()}`;
|
|
397
|
+
this.logger.info(msg);
|
|
398
|
+
throw new Error(msg);
|
|
399
|
+
}
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
const typedError = error;
|
|
404
|
+
this.logger.warn(`ATXP: payment failed on ${dest.network}: ${typedError.message}`);
|
|
405
|
+
await this.onPaymentFailure({ payment: prospectivePayment, error: typedError });
|
|
406
|
+
// Try next destination
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
this.logger.info(`ATXP: no suitable payment destination found among ${paymentRequestData.destinations.length} options`);
|
|
411
|
+
return false;
|
|
412
|
+
};
|
|
328
413
|
this.handlePaymentRequestError = async (paymentRequestError) => {
|
|
329
414
|
if (paymentRequestError.code !== PAYMENT_REQUIRED_ERROR_CODE) {
|
|
330
415
|
throw new Error(`ATXP: expected payment required error (code ${PAYMENT_REQUIRED_ERROR_CODE}); got code ${paymentRequestError.code}`);
|
|
@@ -345,6 +430,11 @@ class ATXPFetcher {
|
|
|
345
430
|
if (!paymentRequestData) {
|
|
346
431
|
throw new Error(`ATXP: payment request ${paymentRequestId} not found on server ${paymentRequestUrl}`);
|
|
347
432
|
}
|
|
433
|
+
// Handle multi-destination format
|
|
434
|
+
if (paymentRequestData.destinations && paymentRequestData.destinations.length > 0) {
|
|
435
|
+
return this.handleMultiDestinationPayment(paymentRequestData, paymentRequestUrl, paymentRequestId);
|
|
436
|
+
}
|
|
437
|
+
// Handle legacy single destination format
|
|
348
438
|
const requestedNetwork = paymentRequestData.network;
|
|
349
439
|
if (!requestedNetwork) {
|
|
350
440
|
throw new Error(`Payment network not provided`);
|
|
@@ -421,7 +511,8 @@ class ATXPFetcher {
|
|
|
421
511
|
},
|
|
422
512
|
body: JSON.stringify({
|
|
423
513
|
transactionId: paymentId,
|
|
424
|
-
network: requestedNetwork
|
|
514
|
+
network: requestedNetwork,
|
|
515
|
+
currency: currency
|
|
425
516
|
})
|
|
426
517
|
});
|
|
427
518
|
this.logger.debug(`ATXP: payment was ${response.ok ? 'successfully' : 'not successfully'} PUT to ${paymentRequestUrl} : status ${response.status} ${response.statusText}`);
|
|
@@ -640,6 +731,7 @@ class ATXPFetcher {
|
|
|
640
731
|
throw error;
|
|
641
732
|
}
|
|
642
733
|
};
|
|
734
|
+
const { accountId, db, paymentMakers, fetchFn = fetch, sideChannelFetch = fetchFn, strict = true, allowInsecureRequests = process.env.NODE_ENV === 'development', allowedAuthorizationServers = [DEFAULT_AUTHORIZATION_SERVER], approvePayment = async () => true, logger = new ConsoleLogger(), onAuthorize = async () => { }, onAuthorizeFailure = async () => { }, onPayment = async () => { }, onPaymentFailure = async () => { } } = config;
|
|
643
735
|
// Use React Native safe fetch if in React Native environment
|
|
644
736
|
const safeFetchFn = getIsReactNative() ? createReactNativeSafeFetch(fetchFn) : fetchFn;
|
|
645
737
|
const safeSideChannelFetch = getIsReactNative() ? createReactNativeSafeFetch(sideChannelFetch) : sideChannelFetch;
|
|
@@ -15798,22 +15890,9 @@ function buildClientConfig(args) {
|
|
|
15798
15890
|
}
|
|
15799
15891
|
function buildStreamableTransport(args) {
|
|
15800
15892
|
const config = buildClientConfig(args);
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
paymentMakers: args.account.paymentMakers,
|
|
15805
|
-
fetchFn: config.fetchFn,
|
|
15806
|
-
sideChannelFetch: config.oAuthChannelFetch,
|
|
15807
|
-
allowInsecureRequests: config.allowHttp,
|
|
15808
|
-
allowedAuthorizationServers: config.allowedAuthorizationServers,
|
|
15809
|
-
approvePayment: config.approvePayment,
|
|
15810
|
-
logger: config.logger,
|
|
15811
|
-
onAuthorize: config.onAuthorize,
|
|
15812
|
-
onAuthorizeFailure: config.onAuthorizeFailure,
|
|
15813
|
-
onPayment: config.onPayment,
|
|
15814
|
-
onPaymentFailure: config.onPaymentFailure
|
|
15815
|
-
});
|
|
15816
|
-
const transport = new StreamableHTTPClientTransport(new URL(args.mcpServer), { fetch: fetcher.fetch });
|
|
15893
|
+
// Apply the ATXP wrapper to the fetch function
|
|
15894
|
+
const wrappedFetch = atxpFetch(config);
|
|
15895
|
+
const transport = new StreamableHTTPClientTransport(new URL(args.mcpServer), { fetch: wrappedFetch });
|
|
15817
15896
|
return transport;
|
|
15818
15897
|
}
|
|
15819
15898
|
async function atxpClient(args) {
|
|
@@ -15830,7 +15909,7 @@ const ValidateTransferError = ValidateTransferError$1;
|
|
|
15830
15909
|
class SolanaPaymentMaker {
|
|
15831
15910
|
constructor(solanaEndpoint, sourceSecretKey, logger) {
|
|
15832
15911
|
this.generateJWT = async ({ paymentRequestId, codeChallenge }) => {
|
|
15833
|
-
// Solana/Web3.js secretKey is 64 bytes:
|
|
15912
|
+
// Solana/Web3.js secretKey is 64 bytes:
|
|
15834
15913
|
// first 32 bytes are the private scalar, last 32 are the public key.
|
|
15835
15914
|
// JWK expects only the 32-byte private scalar for 'd'
|
|
15836
15915
|
const jwk = {
|
|
@@ -15860,8 +15939,10 @@ class SolanaPaymentMaker {
|
|
|
15860
15939
|
this.logger.warn(`Insufficient ${currency} balance for payment. Required: ${amount}, Available: ${balance}`);
|
|
15861
15940
|
throw new InsufficientFundsError(currency, amount, balance, 'solana');
|
|
15862
15941
|
}
|
|
15942
|
+
// Increase compute units to handle both memo and token transfer
|
|
15943
|
+
// Memo uses ~6000 CUs, token transfer needs ~6500 CUs
|
|
15863
15944
|
const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
|
|
15864
|
-
units:
|
|
15945
|
+
units: 50000,
|
|
15865
15946
|
});
|
|
15866
15947
|
const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({
|
|
15867
15948
|
microLamports: 20000,
|
|
@@ -16055,6 +16136,106 @@ class SolanaAccount {
|
|
|
16055
16136
|
}
|
|
16056
16137
|
}
|
|
16057
16138
|
|
|
16139
|
+
function toBasicAuth$1(token) {
|
|
16140
|
+
// Basic auth is base64("username:password"), password is blank
|
|
16141
|
+
const b64 = Buffer.from(`${token}:`).toString('base64');
|
|
16142
|
+
return `Basic ${b64}`;
|
|
16143
|
+
}
|
|
16144
|
+
/**
|
|
16145
|
+
* ATXP implementation of viem's LocalAccount interface.
|
|
16146
|
+
* Delegates signing operations to the accounts-x402 API.
|
|
16147
|
+
* Includes properties needed by x402 library for wallet client compatibility.
|
|
16148
|
+
*/
|
|
16149
|
+
class ATXPLocalAccount {
|
|
16150
|
+
constructor(address, origin, token, fetchFn = fetch) {
|
|
16151
|
+
this.address = address;
|
|
16152
|
+
this.origin = origin;
|
|
16153
|
+
this.token = token;
|
|
16154
|
+
this.fetchFn = fetchFn;
|
|
16155
|
+
this.type = 'local';
|
|
16156
|
+
/**
|
|
16157
|
+
* Get public key - required by LocalAccount interface
|
|
16158
|
+
*/
|
|
16159
|
+
this.publicKey = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
16160
|
+
/**
|
|
16161
|
+
* Source - required by LocalAccount interface (set to 'custom')
|
|
16162
|
+
*/
|
|
16163
|
+
this.source = 'custom';
|
|
16164
|
+
// x402 library expects these properties for wallet client compatibility
|
|
16165
|
+
this.account = this; // Self-reference for x402's isSignerWallet check
|
|
16166
|
+
this.chain = { id: 8453 }; // Base mainnet - could make this configurable
|
|
16167
|
+
this.transport = {}; // Empty transport object for x402 compatibility
|
|
16168
|
+
}
|
|
16169
|
+
/**
|
|
16170
|
+
* Fetch the wallet address from the /address endpoint
|
|
16171
|
+
*/
|
|
16172
|
+
static async create(origin, token, fetchFn = fetch) {
|
|
16173
|
+
// The /address endpoint uses Basic auth like other authenticated endpoints
|
|
16174
|
+
// For X402, we need the Ethereum/Base address with USDC currency
|
|
16175
|
+
const url = new URL(`${origin}/address`);
|
|
16176
|
+
url.searchParams.set('network', 'base'); // X402 operates on Base
|
|
16177
|
+
url.searchParams.set('currency', 'USDC'); // Always USDC for X402
|
|
16178
|
+
const response = await fetchFn(url.toString(), {
|
|
16179
|
+
method: 'GET',
|
|
16180
|
+
headers: {
|
|
16181
|
+
'Authorization': toBasicAuth$1(token)
|
|
16182
|
+
}
|
|
16183
|
+
});
|
|
16184
|
+
if (!response.ok) {
|
|
16185
|
+
const errorText = await response.text();
|
|
16186
|
+
throw new Error(`Failed to fetch destination address: ${response.status} ${response.statusText} ${errorText}`);
|
|
16187
|
+
}
|
|
16188
|
+
const data = await response.json();
|
|
16189
|
+
const address = data.address;
|
|
16190
|
+
if (!address) {
|
|
16191
|
+
throw new Error('Address endpoint did not return an address');
|
|
16192
|
+
}
|
|
16193
|
+
// Check that the account is an Ethereum/Base account (required for X402/EVM operations)
|
|
16194
|
+
const network = data.network;
|
|
16195
|
+
if (!network) {
|
|
16196
|
+
throw new Error('Address endpoint did not return a network');
|
|
16197
|
+
}
|
|
16198
|
+
if (network !== 'ethereum' && network !== 'base') {
|
|
16199
|
+
throw new Error(`ATXPLocalAccount requires an Ethereum/Base account, but got ${network} account`);
|
|
16200
|
+
}
|
|
16201
|
+
return new ATXPLocalAccount(address, origin, token, fetchFn);
|
|
16202
|
+
}
|
|
16203
|
+
/**
|
|
16204
|
+
* Sign a typed data structure using EIP-712
|
|
16205
|
+
* This is what x402 library will call for EIP-3009 authorization
|
|
16206
|
+
*/
|
|
16207
|
+
async signTypedData(typedData) {
|
|
16208
|
+
const response = await this.fetchFn(`${this.origin}/sign-typed-data`, {
|
|
16209
|
+
method: 'POST',
|
|
16210
|
+
headers: {
|
|
16211
|
+
'Authorization': toBasicAuth$1(this.token),
|
|
16212
|
+
'Content-Type': 'application/json',
|
|
16213
|
+
},
|
|
16214
|
+
body: JSON.stringify({
|
|
16215
|
+
typedData
|
|
16216
|
+
})
|
|
16217
|
+
});
|
|
16218
|
+
if (!response.ok) {
|
|
16219
|
+
const errorText = await response.text();
|
|
16220
|
+
throw new Error(`Failed to sign typed data: ${response.status} ${response.statusText} ${errorText}`);
|
|
16221
|
+
}
|
|
16222
|
+
const result = await response.json();
|
|
16223
|
+
return result.signature;
|
|
16224
|
+
}
|
|
16225
|
+
/**
|
|
16226
|
+
* Sign a message - required by LocalAccount interface but not used for X402
|
|
16227
|
+
*/
|
|
16228
|
+
async signMessage(_) {
|
|
16229
|
+
throw new Error('Message signing not implemented for ATXP local account');
|
|
16230
|
+
}
|
|
16231
|
+
/**
|
|
16232
|
+
* Sign a transaction - required by LocalAccount interface but not used for X402
|
|
16233
|
+
*/
|
|
16234
|
+
async signTransaction(_transaction, _args) {
|
|
16235
|
+
throw new Error('Transaction signing not implemented for ATXP local account');
|
|
16236
|
+
}
|
|
16237
|
+
}
|
|
16238
|
+
|
|
16058
16239
|
function toBasicAuth(token) {
|
|
16059
16240
|
// Basic auth is base64("username:password"), password is blank
|
|
16060
16241
|
const b64 = Buffer.from(`${token}:`).toString('base64');
|
|
@@ -16064,10 +16245,11 @@ function parseConnectionString(connectionString) {
|
|
|
16064
16245
|
const url = new URL(connectionString);
|
|
16065
16246
|
const origin = url.origin;
|
|
16066
16247
|
const token = url.searchParams.get('connection_token') || '';
|
|
16248
|
+
const accountId = url.searchParams.get('account_id');
|
|
16067
16249
|
if (!token) {
|
|
16068
16250
|
throw new Error('ATXPAccount: connection string missing connection token');
|
|
16069
16251
|
}
|
|
16070
|
-
return { origin, token };
|
|
16252
|
+
return { origin, token, accountId };
|
|
16071
16253
|
}
|
|
16072
16254
|
class ATXPHttpPaymentMaker {
|
|
16073
16255
|
constructor(origin, token, fetchFn = fetch) {
|
|
@@ -16076,19 +16258,19 @@ class ATXPHttpPaymentMaker {
|
|
|
16076
16258
|
this.fetchFn = fetchFn;
|
|
16077
16259
|
}
|
|
16078
16260
|
async makePayment(amount, currency, receiver, memo) {
|
|
16079
|
-
|
|
16080
|
-
amount: amount.toString(),
|
|
16081
|
-
currency,
|
|
16082
|
-
receiver,
|
|
16083
|
-
memo,
|
|
16084
|
-
};
|
|
16261
|
+
// Make a regular payment via the /pay endpoint
|
|
16085
16262
|
const response = await this.fetchFn(`${this.origin}/pay`, {
|
|
16086
16263
|
method: 'POST',
|
|
16087
16264
|
headers: {
|
|
16088
16265
|
'Authorization': toBasicAuth(this.token),
|
|
16089
16266
|
'Content-Type': 'application/json',
|
|
16090
16267
|
},
|
|
16091
|
-
body: JSON.stringify(
|
|
16268
|
+
body: JSON.stringify({
|
|
16269
|
+
amount: amount.toString(),
|
|
16270
|
+
currency,
|
|
16271
|
+
receiver,
|
|
16272
|
+
memo,
|
|
16273
|
+
}),
|
|
16092
16274
|
});
|
|
16093
16275
|
if (!response.ok) {
|
|
16094
16276
|
const text = await response.text();
|
|
@@ -16125,15 +16307,26 @@ class ATXPHttpPaymentMaker {
|
|
|
16125
16307
|
}
|
|
16126
16308
|
class ATXPAccount {
|
|
16127
16309
|
constructor(connectionString, opts) {
|
|
16128
|
-
const { origin, token } = parseConnectionString(connectionString);
|
|
16310
|
+
const { origin, token, accountId } = parseConnectionString(connectionString);
|
|
16129
16311
|
const fetchFn = opts?.fetchFn ?? fetch;
|
|
16130
16312
|
const network = opts?.network ?? 'base';
|
|
16131
|
-
//
|
|
16132
|
-
this.
|
|
16313
|
+
// Store for use in X402 payment creation
|
|
16314
|
+
this.origin = origin;
|
|
16315
|
+
this.token = token;
|
|
16316
|
+
this.fetchFn = fetchFn;
|
|
16317
|
+
if (accountId) {
|
|
16318
|
+
this.accountId = `atxp:${accountId}`;
|
|
16319
|
+
}
|
|
16320
|
+
else {
|
|
16321
|
+
this.accountId = `atxp:${crypto$1.randomUUID()}`;
|
|
16322
|
+
}
|
|
16133
16323
|
this.paymentMakers = {
|
|
16134
16324
|
[network]: new ATXPHttpPaymentMaker(origin, token, fetchFn),
|
|
16135
16325
|
};
|
|
16136
16326
|
}
|
|
16327
|
+
async getSigner() {
|
|
16328
|
+
return ATXPLocalAccount.create(this.origin, this.token, this.fetchFn);
|
|
16329
|
+
}
|
|
16137
16330
|
}
|
|
16138
16331
|
|
|
16139
16332
|
class BaseAccount {
|
|
@@ -16144,18 +16337,26 @@ class BaseAccount {
|
|
|
16144
16337
|
if (!sourceSecretKey) {
|
|
16145
16338
|
throw new Error('Source secret key is required');
|
|
16146
16339
|
}
|
|
16147
|
-
|
|
16148
|
-
this.accountId = account.address;
|
|
16149
|
-
|
|
16150
|
-
account: account,
|
|
16340
|
+
this.account = privateKeyToAccount(sourceSecretKey);
|
|
16341
|
+
this.accountId = this.account.address;
|
|
16342
|
+
this.walletClient = createWalletClient({
|
|
16343
|
+
account: this.account,
|
|
16151
16344
|
chain: base,
|
|
16152
16345
|
transport: http(baseRPCUrl),
|
|
16153
16346
|
});
|
|
16154
16347
|
this.paymentMakers = {
|
|
16155
|
-
'base': new BasePaymentMaker(baseRPCUrl, walletClient),
|
|
16348
|
+
'base': new BasePaymentMaker(baseRPCUrl, this.walletClient),
|
|
16156
16349
|
};
|
|
16157
16350
|
}
|
|
16351
|
+
/**
|
|
16352
|
+
* Get a signer that can be used with the x402 library
|
|
16353
|
+
* This is only available for EVM-based accounts
|
|
16354
|
+
*/
|
|
16355
|
+
getSigner() {
|
|
16356
|
+
// Return the viem account directly - it implements LocalAccount interface
|
|
16357
|
+
return this.account;
|
|
16358
|
+
}
|
|
16158
16359
|
}
|
|
16159
16360
|
|
|
16160
|
-
export { ATXPAccount,
|
|
16361
|
+
export { ATXPAccount, ATXPLocalAccount, BaseAccount, BasePaymentMaker, DEFAULT_CLIENT_CONFIG, InsufficientFundsError, OAuthAuthenticationRequiredError, OAuthClient, PaymentNetworkError, SolanaAccount, SolanaPaymentMaker, USDC_CONTRACT_ADDRESS_BASE, ValidateTransferError, atxpClient, atxpFetch, buildClientConfig, buildStreamableTransport };
|
|
16161
16362
|
//# sourceMappingURL=index.js.map
|