@relai-fi/x402 0.5.26 → 0.5.28

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 CHANGED
@@ -544,6 +544,118 @@ const mgmt = createManagementClient({ serviceKey });
544
544
 
545
545
  ---
546
546
 
547
+ ## x402 Bridge
548
+
549
+ Bridge USDC between **Solana** and **SKALE Base** using the x402 protocol. The bridge uses a liquidity network model — instant payouts, no canonical bridge delays.
550
+
551
+ > Requires a service key (`sk_live_...`). Get one via `bootstrapAgentKeySolana` or the RelAI dashboard.
552
+
553
+ ### How it works
554
+
555
+ ```
556
+ Agent pays USDC on Solana (x402)
557
+ ↓ facilitator verifies payment
558
+ Bridge pays out USDC on SKALE Base from its liquidity pool ← instant
559
+ ↓ async in background
560
+ Rebalance via Circle CCTP restores liquidity
561
+ ```
562
+
563
+ ### Quick start
564
+
565
+ ```typescript
566
+ import { createManagementClient } from '@relai-fi/x402/management';
567
+ import { createX402Client } from '@relai-fi/x402/client';
568
+ import { Keypair } from '@solana/web3.js';
569
+
570
+ const serviceKey = process.env.RELAI_SERVICE_KEY!;
571
+ const mgmt = createManagementClient({ serviceKey });
572
+
573
+ // 1. Check liquidity before bridging
574
+ const balances = await mgmt.getBridgeBalances();
575
+ console.log(`SKALE Base liquidity: $${balances.skaleBase.usd} USDC`);
576
+
577
+ // 2. Get a quote
578
+ const quote = await mgmt.getBridgeQuote(10.0, 'solana');
579
+ // { inputUsd: 10, outputUsd: 9.99, feeBps: 10, direction: 'solana-to-skale' }
580
+
581
+ // 3. Bridge Solana → SKALE Base
582
+ const keypair = Keypair.fromSecretKey(Buffer.from(process.env.SOLANA_PRIVATE_KEY!, 'base64'));
583
+ const solanaWallet = {
584
+ publicKey: keypair.publicKey,
585
+ signTransaction: async (tx: any) => { tx.sign([keypair]); return tx; },
586
+ };
587
+
588
+ const x402 = createX402Client({
589
+ wallets: { solana: solanaWallet },
590
+ solanaRpcUrl: process.env.SOLANA_RPC_URL,
591
+ defaultHeaders: { 'X-Service-Key': serviceKey },
592
+ });
593
+
594
+ const result = await mgmt.bridgeSolanaToSkale(
595
+ 10.0, // $10 USDC
596
+ '0xYourSkaleAddress', // destination EVM address on SKALE Base
597
+ x402,
598
+ );
599
+ // { success: true, txHash: '0x...', amountOutUsd: 9.99, explorerUrl: '...' }
600
+ ```
601
+
602
+ ### Bridge SKALE Base → Solana
603
+
604
+ ```typescript
605
+ import { ethers } from 'ethers';
606
+
607
+ const provider = new ethers.JsonRpcProvider(process.env.SKALE_RPC_URL);
608
+ const signer = new ethers.Wallet(process.env.EVM_PRIVATE_KEY!, provider);
609
+
610
+ const evmWallet = {
611
+ address: signer.address,
612
+ signTypedData: (params: any) => signer.signTypedData(
613
+ params.domain, params.types, params.message
614
+ ),
615
+ };
616
+
617
+ const x402 = createX402Client({
618
+ wallets: { evm: evmWallet },
619
+ defaultHeaders: { 'X-Service-Key': serviceKey },
620
+ });
621
+
622
+ const result = await mgmt.bridgeSkaleToSolana(
623
+ 5.0, // $5 USDC
624
+ 'YourSolanaPublicKey', // destination Solana address (base58)
625
+ x402,
626
+ );
627
+ // { success: true, txHash: '...', amountOutUsd: 4.995, explorerUrl: '...' }
628
+ ```
629
+
630
+ ### Bridge API reference
631
+
632
+ | Method | Description |
633
+ |--------|-------------|
634
+ | `getBridgeQuote(amount, from?)` | Fee and net output for a given amount |
635
+ | `getBridgeBalances()` | Current USDC liquidity on Solana / SKALE Base / Base |
636
+ | `bridgeSolanaToSkale(amount, dest, x402Client)` | Bridge Solana → SKALE Base |
637
+ | `bridgeSkaleToSolana(amount, dest, x402Client)` | Bridge SKALE Base → Solana |
638
+
639
+ ### Error handling
640
+
641
+ ```typescript
642
+ try {
643
+ const result = await mgmt.bridgeSolanaToSkale(100.0, '0x...', x402);
644
+ } catch (err) {
645
+ if (err.message.includes('insufficient_liquidity')) {
646
+ // Bridge temporarily unavailable — check balances and retry later
647
+ const { skaleBase } = await mgmt.getBridgeBalances();
648
+ console.log(`Available: $${skaleBase.usd} USDC`);
649
+ }
650
+ }
651
+ ```
652
+
653
+ **Fee:** 0.1% (10 bps) deducted from output amount. Check `getBridgeQuote` for exact amounts.
654
+
655
+ **Limits:** min $0.000001, max $10,000 per transaction.
656
+
657
+ ---
658
+
547
659
  ## Utilities
548
660
 
549
661
  ```typescript
package/dist/client.cjs CHANGED
@@ -31,6 +31,7 @@ var import_spl_token = require("@solana/spl-token");
31
31
  var RELAI_FACILITATOR_URL = "https://facilitator.x402.fi";
32
32
  var NETWORK_CAIP2 = {
33
33
  "solana": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
34
+ "solana-devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
34
35
  "base": "eip155:8453",
35
36
  "avalanche": "eip155:43114",
36
37
  "skale-base": "eip155:1187947933",
@@ -62,6 +63,14 @@ var NETWORK_TOKENS = {
62
63
  decimals: 6
63
64
  }
64
65
  ],
66
+ "solana-devnet": [
67
+ {
68
+ address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
69
+ symbol: "USDC",
70
+ name: "USD Coin (Devnet)",
71
+ decimals: 6
72
+ }
73
+ ],
65
74
  "base": [
66
75
  { address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC", name: "USD Coin", decimals: 6, domainVersion: "2", isStableUsd: true }
67
76
  ],
@@ -186,6 +195,7 @@ var NETWORK_TOKENS = {
186
195
  };
187
196
  var USDC_ADDRESSES = {
188
197
  "solana": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
198
+ "solana-devnet": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU",
189
199
  "base": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
190
200
  "avalanche": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
191
201
  "skale-base": "0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20",
@@ -201,6 +211,7 @@ var USDC_SOLANA = USDC_ADDRESSES["solana"];
201
211
  var USDC_BASE = USDC_ADDRESSES["base"];
202
212
  var RELAI_NETWORKS = [
203
213
  "solana",
214
+ "solana-devnet",
204
215
  "base",
205
216
  "avalanche",
206
217
  "skale-base",
@@ -211,7 +222,7 @@ var RELAI_NETWORKS = [
211
222
  "telos"
212
223
  ];
213
224
  function isSolana(network) {
214
- return network === "solana" || network.startsWith("solana:");
225
+ return network === "solana" || network === "solana-devnet" || network.startsWith("solana:");
215
226
  }
216
227
  function isEvm(network) {
217
228
  return ["base", "avalanche", "skale-base", "skale-base-sepolia", "skale-bite", "polygon", "ethereum", "telos"].includes(network) || network.startsWith("eip155:");
@@ -986,11 +997,19 @@ function createX402Client(config) {
986
997
  [],
987
998
  programId
988
999
  );
1000
+ const createDestAtaIx = (0, import_spl_token.createAssociatedTokenAccountIdempotentInstruction)(
1001
+ feePayerPubkey,
1002
+ // payer (feePayer covers this)
1003
+ destinationAta,
1004
+ merchantPubkey,
1005
+ mintPubkey,
1006
+ programId
1007
+ );
989
1008
  const { blockhash } = await connection.getLatestBlockhash("confirmed");
990
1009
  const message = new import_web3.TransactionMessage({
991
1010
  payerKey: feePayerPubkey,
992
1011
  recentBlockhash: blockhash,
993
- instructions: [transferIx]
1012
+ instructions: [createDestAtaIx, transferIx]
994
1013
  }).compileToV0Message();
995
1014
  const transaction = new import_web3.VersionedTransaction(message);
996
1015
  const signedTx = await solWallet.signTransaction(transaction);