uvd-x402-sdk 2.15.2 → 2.16.1
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 +209 -1
- package/dist/adapters/index.d.mts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +82 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +82 -1
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/backend/index.d.mts +1 -1
- package/dist/backend/index.d.ts +1 -1
- package/dist/backend/index.js +82 -1
- package/dist/backend/index.js.map +1 -1
- package/dist/backend/index.mjs +82 -1
- package/dist/backend/index.mjs.map +1 -1
- package/dist/{index-D3PO3jLW.d.mts → index-1CWNFuXP.d.mts} +10 -2
- package/dist/{index-Cwi_VM05.d.ts → index-BYsQM8ga.d.ts} +10 -2
- package/dist/{index-BYIugZlE.d.mts → index-B_reIs-L.d.mts} +46 -5
- package/dist/{index-BYIugZlE.d.ts → index-B_reIs-L.d.ts} +46 -5
- package/dist/index.d.mts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +111 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -3
- package/dist/index.mjs.map +1 -1
- package/dist/providers/algorand/index.d.mts +1 -1
- package/dist/providers/algorand/index.d.ts +1 -1
- package/dist/providers/algorand/index.js +95 -2
- package/dist/providers/algorand/index.js.map +1 -1
- package/dist/providers/algorand/index.mjs +95 -2
- package/dist/providers/algorand/index.mjs.map +1 -1
- package/dist/providers/evm/index.d.mts +1 -1
- package/dist/providers/evm/index.d.ts +1 -1
- package/dist/providers/evm/index.js +82 -1
- package/dist/providers/evm/index.js.map +1 -1
- package/dist/providers/evm/index.mjs +82 -1
- package/dist/providers/evm/index.mjs.map +1 -1
- package/dist/providers/near/index.d.mts +1 -1
- package/dist/providers/near/index.d.ts +1 -1
- package/dist/providers/near/index.js +82 -1
- package/dist/providers/near/index.js.map +1 -1
- package/dist/providers/near/index.mjs +82 -1
- package/dist/providers/near/index.mjs.map +1 -1
- package/dist/providers/solana/index.d.mts +1 -1
- package/dist/providers/solana/index.d.ts +1 -1
- package/dist/providers/solana/index.js +82 -1
- package/dist/providers/solana/index.js.map +1 -1
- package/dist/providers/solana/index.mjs +82 -1
- package/dist/providers/solana/index.mjs.map +1 -1
- package/dist/providers/stellar/index.d.mts +1 -1
- package/dist/providers/stellar/index.d.ts +1 -1
- package/dist/providers/stellar/index.js +82 -1
- package/dist/providers/stellar/index.js.map +1 -1
- package/dist/providers/stellar/index.mjs +82 -1
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/providers/sui/index.d.mts +105 -0
- package/dist/providers/sui/index.d.ts +105 -0
- package/dist/providers/sui/index.js +1026 -0
- package/dist/providers/sui/index.js.map +1 -0
- package/dist/providers/sui/index.mjs +1021 -0
- package/dist/providers/sui/index.mjs.map +1 -0
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +82 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +82 -1
- package/dist/react/index.mjs.map +1 -1
- package/dist/utils/index.d.mts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +82 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +82 -1
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +15 -4
- package/src/chains/index.ts +98 -0
- package/src/facilitator.ts +18 -0
- package/src/index.ts +20 -1
- package/src/providers/sui/index.ts +429 -0
- package/src/types/index.ts +53 -3
package/README.md
CHANGED
|
@@ -118,12 +118,17 @@ const header = stellar.encodePaymentHeader(payload);
|
|
|
118
118
|
|
|
119
119
|
### NEAR
|
|
120
120
|
|
|
121
|
+
> **Important:** The SDK's `NEARProvider.signPayment()` only works with **injected wallets** (browser extensions).
|
|
122
|
+
> For **browser-redirect wallets** like MyNearWallet via `@near-wallet-selector`, you must use the popup flow below.
|
|
123
|
+
|
|
124
|
+
#### Option 1: Injected Wallet (Browser Extension)
|
|
125
|
+
|
|
121
126
|
```typescript
|
|
122
127
|
import { NEARProvider } from 'uvd-x402-sdk/near';
|
|
123
128
|
import { getChainByName } from 'uvd-x402-sdk';
|
|
124
129
|
|
|
125
130
|
const near = new NEARProvider();
|
|
126
|
-
const accountId = await near.connect(); // MyNearWallet
|
|
131
|
+
const accountId = await near.connect(); // MyNearWallet browser extension
|
|
127
132
|
const chainConfig = getChainByName('near')!;
|
|
128
133
|
|
|
129
134
|
const payload = await near.signPayment({
|
|
@@ -134,6 +139,209 @@ const payload = await near.signPayment({
|
|
|
134
139
|
const header = near.encodePaymentHeader(payload);
|
|
135
140
|
```
|
|
136
141
|
|
|
142
|
+
#### Option 2: Browser-Redirect Wallet (Popup Flow) - Recommended
|
|
143
|
+
|
|
144
|
+
MyNearWallet via `@near-wallet-selector` is a browser-redirect wallet that requires a popup flow.
|
|
145
|
+
This is the recommended approach and works with the custom MyNearWallet deployment that supports NEP-366.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { setupWalletSelector } from '@near-wallet-selector/core';
|
|
149
|
+
import { setupModal } from '@near-wallet-selector/modal-ui';
|
|
150
|
+
import { setupMyNearWallet } from '@near-wallet-selector/my-near-wallet';
|
|
151
|
+
import '@near-wallet-selector/modal-ui/styles.css';
|
|
152
|
+
|
|
153
|
+
// Configuration
|
|
154
|
+
const NEAR_CONFIG = {
|
|
155
|
+
usdcContract: '17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1',
|
|
156
|
+
recipientAccount: 'merchant.near',
|
|
157
|
+
// Custom MyNearWallet with NEP-366 signDelegateAction support
|
|
158
|
+
walletUrl: 'https://mynearwallet.ultravioletadao.xyz',
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Step 1: Initialize wallet selector
|
|
162
|
+
const selector = await setupWalletSelector({
|
|
163
|
+
network: 'mainnet',
|
|
164
|
+
modules: [
|
|
165
|
+
setupMyNearWallet({ walletUrl: NEAR_CONFIG.walletUrl }),
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const modal = setupModal(selector, {
|
|
170
|
+
contractId: NEAR_CONFIG.usdcContract,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Step 2: Connect wallet
|
|
174
|
+
modal.show(); // User selects wallet
|
|
175
|
+
// Wait for connection via selector.store.observable.subscribe()
|
|
176
|
+
const state = selector.store.getState();
|
|
177
|
+
const accountId = state.accounts[0].accountId;
|
|
178
|
+
|
|
179
|
+
// Step 3: Create payment with popup flow
|
|
180
|
+
async function createNearPayment(amount: string): Promise<string> {
|
|
181
|
+
const amountRaw = Math.floor(parseFloat(amount) * 1_000_000); // 6 decimals
|
|
182
|
+
|
|
183
|
+
// Get access key info and block height from RPC
|
|
184
|
+
const [accessKeyInfo, blockInfo] = await Promise.all([
|
|
185
|
+
getNearAccessKeyInfo(accountId),
|
|
186
|
+
getNearBlockHeight(),
|
|
187
|
+
]);
|
|
188
|
+
|
|
189
|
+
const nonce = accessKeyInfo.nonce + 1;
|
|
190
|
+
const maxBlockHeight = blockInfo.blockHeight + 1000; // ~17 minutes
|
|
191
|
+
|
|
192
|
+
// Build wallet URL for signDelegateAction
|
|
193
|
+
const popupUrl = new URL(NEAR_CONFIG.walletUrl);
|
|
194
|
+
popupUrl.pathname = '/sign-delegate-action';
|
|
195
|
+
popupUrl.searchParams.set('receiverId', NEAR_CONFIG.usdcContract);
|
|
196
|
+
popupUrl.searchParams.set('actions', JSON.stringify([{
|
|
197
|
+
methodName: 'ft_transfer',
|
|
198
|
+
args: {
|
|
199
|
+
receiver_id: NEAR_CONFIG.recipientAccount,
|
|
200
|
+
amount: amountRaw.toString(),
|
|
201
|
+
memo: 'x402 payment',
|
|
202
|
+
},
|
|
203
|
+
gas: '30000000000000', // 30 TGas
|
|
204
|
+
deposit: '1', // 1 yoctoNEAR
|
|
205
|
+
}]));
|
|
206
|
+
popupUrl.searchParams.set('callbackUrl', window.location.origin + '/near-callback');
|
|
207
|
+
popupUrl.searchParams.set('meta', JSON.stringify({
|
|
208
|
+
sender: accountId,
|
|
209
|
+
nonce,
|
|
210
|
+
maxBlockHeight,
|
|
211
|
+
publicKey: accessKeyInfo.publicKey,
|
|
212
|
+
}));
|
|
213
|
+
|
|
214
|
+
// Open popup
|
|
215
|
+
const popup = window.open(popupUrl.toString(), 'nearWallet', 'width=500,height=700');
|
|
216
|
+
if (!popup) throw new Error('Popup blocked. Please allow popups.');
|
|
217
|
+
|
|
218
|
+
// Wait for redirect with signedDelegateAction
|
|
219
|
+
const signedDelegateAction = await new Promise<string>((resolve, reject) => {
|
|
220
|
+
const checkInterval = setInterval(() => {
|
|
221
|
+
if (popup.closed) {
|
|
222
|
+
clearInterval(checkInterval);
|
|
223
|
+
reject(new Error('Wallet popup closed'));
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const url = popup.location.href;
|
|
228
|
+
if (url.includes('signedDelegateAction=')) {
|
|
229
|
+
clearInterval(checkInterval);
|
|
230
|
+
popup.close();
|
|
231
|
+
const params = new URLSearchParams(new URL(url).search);
|
|
232
|
+
const errorCode = params.get('errorCode');
|
|
233
|
+
if (errorCode) {
|
|
234
|
+
reject(new Error(params.get('errorMessage') || errorCode));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
resolve(params.get('signedDelegateAction')!);
|
|
238
|
+
}
|
|
239
|
+
} catch { /* cross-origin, keep waiting */ }
|
|
240
|
+
}, 500);
|
|
241
|
+
|
|
242
|
+
setTimeout(() => {
|
|
243
|
+
clearInterval(checkInterval);
|
|
244
|
+
if (!popup.closed) popup.close();
|
|
245
|
+
reject(new Error('Popup timeout'));
|
|
246
|
+
}, 300000); // 5 min timeout
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Return x402 payload
|
|
250
|
+
return JSON.stringify({
|
|
251
|
+
signedDelegateAction,
|
|
252
|
+
network: 'near',
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Helper: Get access key info from NEAR RPC
|
|
257
|
+
async function getNearAccessKeyInfo(accountId: string) {
|
|
258
|
+
const rpcUrls = [
|
|
259
|
+
'https://near.drpc.org',
|
|
260
|
+
'https://rpc.mainnet.near.org',
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
for (const rpcUrl of rpcUrls) {
|
|
264
|
+
try {
|
|
265
|
+
const response = await fetch(rpcUrl, {
|
|
266
|
+
method: 'POST',
|
|
267
|
+
headers: { 'Content-Type': 'application/json' },
|
|
268
|
+
body: JSON.stringify({
|
|
269
|
+
jsonrpc: '2.0',
|
|
270
|
+
id: 'dontcare',
|
|
271
|
+
method: 'query',
|
|
272
|
+
params: {
|
|
273
|
+
request_type: 'view_access_key_list',
|
|
274
|
+
finality: 'final',
|
|
275
|
+
account_id: accountId,
|
|
276
|
+
},
|
|
277
|
+
}),
|
|
278
|
+
});
|
|
279
|
+
const data = await response.json();
|
|
280
|
+
if (data.error) continue;
|
|
281
|
+
|
|
282
|
+
const fullAccessKey = data.result.keys.find(
|
|
283
|
+
(k: any) => k.access_key.permission === 'FullAccess'
|
|
284
|
+
);
|
|
285
|
+
return {
|
|
286
|
+
nonce: fullAccessKey.access_key.nonce,
|
|
287
|
+
publicKey: fullAccessKey.public_key,
|
|
288
|
+
};
|
|
289
|
+
} catch { continue; }
|
|
290
|
+
}
|
|
291
|
+
throw new Error('Failed to get NEAR access key info');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Helper: Get block height from NEAR RPC
|
|
295
|
+
async function getNearBlockHeight() {
|
|
296
|
+
const rpcUrls = [
|
|
297
|
+
'https://near.drpc.org',
|
|
298
|
+
'https://rpc.mainnet.near.org',
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
for (const rpcUrl of rpcUrls) {
|
|
302
|
+
try {
|
|
303
|
+
const response = await fetch(rpcUrl, {
|
|
304
|
+
method: 'POST',
|
|
305
|
+
headers: { 'Content-Type': 'application/json' },
|
|
306
|
+
body: JSON.stringify({
|
|
307
|
+
jsonrpc: '2.0',
|
|
308
|
+
id: 'dontcare',
|
|
309
|
+
method: 'block',
|
|
310
|
+
params: { finality: 'final' },
|
|
311
|
+
}),
|
|
312
|
+
});
|
|
313
|
+
const data = await response.json();
|
|
314
|
+
if (data.error) continue;
|
|
315
|
+
return { blockHeight: data.result.header.height };
|
|
316
|
+
} catch { continue; }
|
|
317
|
+
}
|
|
318
|
+
throw new Error('Failed to get NEAR block height');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Step 4: Encode payment header
|
|
322
|
+
function encodeNearPaymentHeader(payload: string): string {
|
|
323
|
+
const parsed = JSON.parse(payload);
|
|
324
|
+
const x402Payload = {
|
|
325
|
+
x402Version: 1,
|
|
326
|
+
scheme: 'exact',
|
|
327
|
+
network: 'near',
|
|
328
|
+
payload: {
|
|
329
|
+
signedDelegateAction: parsed.signedDelegateAction,
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
return btoa(JSON.stringify(x402Payload));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Usage
|
|
336
|
+
const payload = await createNearPayment('10.00');
|
|
337
|
+
const header = encodeNearPaymentHeader(payload);
|
|
338
|
+
await fetch('/api/purchase', {
|
|
339
|
+
headers: { 'X-PAYMENT': header },
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
See [402milly's full implementation](https://github.com/UltravioletaDAO/402milly/blob/main/frontend/src/services/x402-sdk.ts) for a production-ready example.
|
|
344
|
+
|
|
137
345
|
## Wagmi/RainbowKit
|
|
138
346
|
|
|
139
347
|
```typescript
|
package/dist/adapters/index.d.ts
CHANGED
package/dist/adapters/index.js
CHANGED
|
@@ -613,6 +613,84 @@ var SUPPORTED_CHAINS = {
|
|
|
613
613
|
facilitatorUrl: DEFAULT_FACILITATOR_URL,
|
|
614
614
|
enabled: true
|
|
615
615
|
}
|
|
616
|
+
},
|
|
617
|
+
// ============================================================================
|
|
618
|
+
// SUI (2 networks) - Uses sponsored transactions (facilitator pays gas)
|
|
619
|
+
// ============================================================================
|
|
620
|
+
sui: {
|
|
621
|
+
chainId: 0,
|
|
622
|
+
// Non-EVM
|
|
623
|
+
chainIdHex: "0x0",
|
|
624
|
+
name: "sui",
|
|
625
|
+
displayName: "Sui",
|
|
626
|
+
networkType: "sui",
|
|
627
|
+
rpcUrl: "https://fullnode.mainnet.sui.io:443",
|
|
628
|
+
explorerUrl: "https://suiscan.xyz/mainnet",
|
|
629
|
+
nativeCurrency: {
|
|
630
|
+
name: "Sui",
|
|
631
|
+
symbol: "SUI",
|
|
632
|
+
decimals: 9
|
|
633
|
+
},
|
|
634
|
+
usdc: {
|
|
635
|
+
// USDC coin type on Sui mainnet
|
|
636
|
+
address: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
|
|
637
|
+
decimals: 6,
|
|
638
|
+
name: "USDC",
|
|
639
|
+
version: "1"
|
|
640
|
+
},
|
|
641
|
+
tokens: {
|
|
642
|
+
usdc: {
|
|
643
|
+
address: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
|
|
644
|
+
decimals: 6,
|
|
645
|
+
name: "USDC",
|
|
646
|
+
version: "1"
|
|
647
|
+
},
|
|
648
|
+
ausd: {
|
|
649
|
+
// AUSD (Agora USD) coin type on Sui mainnet
|
|
650
|
+
address: "0x2053d08c1e2bd02791056171aab0fd12bd7cd7efad2ab8f6b9c8902f14df2ff2::ausd::AUSD",
|
|
651
|
+
decimals: 6,
|
|
652
|
+
name: "AUSD",
|
|
653
|
+
version: "1"
|
|
654
|
+
}
|
|
655
|
+
},
|
|
656
|
+
x402: {
|
|
657
|
+
facilitatorUrl: DEFAULT_FACILITATOR_URL,
|
|
658
|
+
enabled: true
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
"sui-testnet": {
|
|
662
|
+
chainId: 0,
|
|
663
|
+
// Non-EVM
|
|
664
|
+
chainIdHex: "0x0",
|
|
665
|
+
name: "sui-testnet",
|
|
666
|
+
displayName: "Sui Testnet",
|
|
667
|
+
networkType: "sui",
|
|
668
|
+
rpcUrl: "https://fullnode.testnet.sui.io:443",
|
|
669
|
+
explorerUrl: "https://suiscan.xyz/testnet",
|
|
670
|
+
nativeCurrency: {
|
|
671
|
+
name: "Sui",
|
|
672
|
+
symbol: "SUI",
|
|
673
|
+
decimals: 9
|
|
674
|
+
},
|
|
675
|
+
usdc: {
|
|
676
|
+
// USDC coin type on Sui testnet
|
|
677
|
+
address: "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC",
|
|
678
|
+
decimals: 6,
|
|
679
|
+
name: "USDC",
|
|
680
|
+
version: "1"
|
|
681
|
+
},
|
|
682
|
+
tokens: {
|
|
683
|
+
usdc: {
|
|
684
|
+
address: "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC",
|
|
685
|
+
decimals: 6,
|
|
686
|
+
name: "USDC",
|
|
687
|
+
version: "1"
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
x402: {
|
|
691
|
+
facilitatorUrl: DEFAULT_FACILITATOR_URL,
|
|
692
|
+
enabled: true
|
|
693
|
+
}
|
|
616
694
|
}
|
|
617
695
|
};
|
|
618
696
|
function getChainByName(name) {
|
|
@@ -641,7 +719,10 @@ var CAIP2_IDENTIFIERS = {
|
|
|
641
719
|
near: "near:mainnet",
|
|
642
720
|
// Algorand
|
|
643
721
|
algorand: "algorand:mainnet",
|
|
644
|
-
"algorand-testnet": "algorand:testnet"
|
|
722
|
+
"algorand-testnet": "algorand:testnet",
|
|
723
|
+
// Sui
|
|
724
|
+
sui: "sui:mainnet",
|
|
725
|
+
"sui-testnet": "sui:testnet"
|
|
645
726
|
};
|
|
646
727
|
Object.fromEntries(
|
|
647
728
|
Object.entries(CAIP2_IDENTIFIERS).map(([k, v]) => [v, k])
|