uvd-x402-sdk 2.10.1 → 2.12.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.
Files changed (49) hide show
  1. package/dist/adapters/index.d.mts +1 -1
  2. package/dist/adapters/index.d.ts +1 -1
  3. package/dist/adapters/index.js.map +1 -1
  4. package/dist/adapters/index.mjs.map +1 -1
  5. package/dist/backend/index.d.mts +1 -1
  6. package/dist/backend/index.d.ts +1 -1
  7. package/dist/backend/index.js.map +1 -1
  8. package/dist/backend/index.mjs.map +1 -1
  9. package/dist/{index-C60c_e5z.d.mts → index-C6Vxnneo.d.mts} +1 -1
  10. package/dist/{index-VIOUicmO.d.ts → index-DmJGKD9r.d.ts} +1 -1
  11. package/dist/{index-D-dO_FoP.d.mts → index-fIhvHqCQ.d.mts} +18 -22
  12. package/dist/{index-D-dO_FoP.d.ts → index-fIhvHqCQ.d.ts} +18 -22
  13. package/dist/index.d.mts +2 -2
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/providers/algorand/index.d.mts +42 -15
  18. package/dist/providers/algorand/index.d.ts +42 -15
  19. package/dist/providers/algorand/index.js +198 -32
  20. package/dist/providers/algorand/index.js.map +1 -1
  21. package/dist/providers/algorand/index.mjs +198 -32
  22. package/dist/providers/algorand/index.mjs.map +1 -1
  23. package/dist/providers/evm/index.d.mts +1 -1
  24. package/dist/providers/evm/index.d.ts +1 -1
  25. package/dist/providers/evm/index.js.map +1 -1
  26. package/dist/providers/evm/index.mjs.map +1 -1
  27. package/dist/providers/near/index.d.mts +1 -1
  28. package/dist/providers/near/index.d.ts +1 -1
  29. package/dist/providers/near/index.js.map +1 -1
  30. package/dist/providers/near/index.mjs.map +1 -1
  31. package/dist/providers/solana/index.d.mts +1 -1
  32. package/dist/providers/solana/index.d.ts +1 -1
  33. package/dist/providers/solana/index.js.map +1 -1
  34. package/dist/providers/solana/index.mjs.map +1 -1
  35. package/dist/providers/stellar/index.d.mts +1 -1
  36. package/dist/providers/stellar/index.d.ts +1 -1
  37. package/dist/providers/stellar/index.js.map +1 -1
  38. package/dist/providers/stellar/index.mjs.map +1 -1
  39. package/dist/react/index.d.mts +3 -3
  40. package/dist/react/index.d.ts +3 -3
  41. package/dist/react/index.js.map +1 -1
  42. package/dist/react/index.mjs.map +1 -1
  43. package/dist/utils/index.d.mts +1 -1
  44. package/dist/utils/index.d.ts +1 -1
  45. package/dist/utils/index.js.map +1 -1
  46. package/dist/utils/index.mjs.map +1 -1
  47. package/package.json +6 -1
  48. package/src/providers/algorand/index.ts +261 -40
  49. package/src/types/index.ts +18 -22
@@ -1,11 +1,16 @@
1
- import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Version } from '../../index-D-dO_FoP.mjs';
1
+ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Version } from '../../index-fIhvHqCQ.mjs';
2
2
 
3
3
  /**
4
4
  * uvd-x402-sdk - Algorand Provider
5
5
  *
6
- * Provides wallet connection and payment creation for Algorand via Pera Wallet.
6
+ * Provides wallet connection and payment creation for Algorand.
7
+ * Supports both Lute Wallet (desktop browser extension) and Pera Wallet (mobile).
7
8
  * Uses ASA (Algorand Standard Assets) transfers for USDC payments.
8
9
  *
10
+ * Wallet Priority:
11
+ * 1. Lute Wallet - Desktop browser extension (preferred for desktop)
12
+ * 2. Pera Wallet - Mobile via WalletConnect (fallback/mobile)
13
+ *
9
14
  * USDC ASA IDs:
10
15
  * - Mainnet: 31566704
11
16
  * - Testnet: 10458941
@@ -17,7 +22,7 @@ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Versio
17
22
  *
18
23
  * const algorand = new AlgorandProvider();
19
24
  *
20
- * // Connect to Pera Wallet
25
+ * // Connect to Lute (desktop) or Pera (mobile) automatically
21
26
  * const address = await algorand.connect();
22
27
  *
23
28
  * // Create Algorand payment
@@ -28,28 +33,44 @@ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Versio
28
33
  */
29
34
 
30
35
  /**
31
- * AlgorandProvider - Wallet adapter for Algorand via Pera Wallet
36
+ * AlgorandProvider - Wallet adapter for Algorand
32
37
  *
33
- * Supports both mainnet and testnet through chain configuration.
38
+ * Supports Lute Wallet (desktop) and Pera Wallet (mobile).
39
+ * Automatically detects and uses the best available wallet.
34
40
  */
35
41
  declare class AlgorandProvider implements WalletAdapter {
36
- readonly id = "pera";
37
- readonly name = "Pera Wallet";
42
+ readonly id = "algorand";
43
+ readonly name = "Algorand Wallet";
38
44
  readonly networkType: "algorand";
45
+ private walletType;
46
+ private luteWallet;
39
47
  private peraWallet;
40
48
  private address;
41
49
  private algodClients;
42
50
  /**
43
- * Check if Pera Wallet is available
44
- * Note: Pera works as a WalletConnect modal, so it's always "available"
51
+ * Check if any Algorand wallet is available
52
+ * Returns true if Lute extension is installed OR we can use Pera (always available via WalletConnect)
45
53
  */
46
54
  isAvailable(): boolean;
47
55
  /**
48
- * Connect to Pera Wallet
56
+ * Get the name of the currently connected wallet
57
+ */
58
+ getWalletName(): string;
59
+ /**
60
+ * Connect to Algorand wallet
61
+ * Priority: Lute (desktop extension) > Pera (mobile via WalletConnect)
49
62
  */
50
63
  connect(_chainName?: string): Promise<string>;
51
64
  /**
52
- * Disconnect from Pera Wallet
65
+ * Connect to Lute Wallet (desktop browser extension)
66
+ */
67
+ private connectLute;
68
+ /**
69
+ * Connect to Pera Wallet (mobile via WalletConnect)
70
+ */
71
+ private connectPera;
72
+ /**
73
+ * Disconnect from wallet
53
74
  */
54
75
  disconnect(): Promise<void>;
55
76
  /**
@@ -61,13 +82,19 @@ declare class AlgorandProvider implements WalletAdapter {
61
82
  */
62
83
  getBalance(chainConfig: ChainConfig): Promise<string>;
63
84
  /**
64
- * Create Algorand ASA transfer payment
85
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
86
+ *
87
+ * Transaction structure (atomic group):
88
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
89
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
65
90
  *
66
- * Transaction structure:
67
- * 1. ASA Transfer from user to recipient
68
- * 2. Facilitator pays transaction fees
91
+ * The facilitator signs transaction 0 and submits the complete atomic group.
69
92
  */
70
93
  signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string>;
94
+ /**
95
+ * Decode signed transaction from wallet response (handles various formats)
96
+ */
97
+ private decodeSignedTxn;
71
98
  /**
72
99
  * Encode Algorand payment as X-PAYMENT header
73
100
  *
@@ -1,11 +1,16 @@
1
- import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Version } from '../../index-D-dO_FoP.js';
1
+ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Version } from '../../index-fIhvHqCQ.js';
2
2
 
3
3
  /**
4
4
  * uvd-x402-sdk - Algorand Provider
5
5
  *
6
- * Provides wallet connection and payment creation for Algorand via Pera Wallet.
6
+ * Provides wallet connection and payment creation for Algorand.
7
+ * Supports both Lute Wallet (desktop browser extension) and Pera Wallet (mobile).
7
8
  * Uses ASA (Algorand Standard Assets) transfers for USDC payments.
8
9
  *
10
+ * Wallet Priority:
11
+ * 1. Lute Wallet - Desktop browser extension (preferred for desktop)
12
+ * 2. Pera Wallet - Mobile via WalletConnect (fallback/mobile)
13
+ *
9
14
  * USDC ASA IDs:
10
15
  * - Mainnet: 31566704
11
16
  * - Testnet: 10458941
@@ -17,7 +22,7 @@ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Versio
17
22
  *
18
23
  * const algorand = new AlgorandProvider();
19
24
  *
20
- * // Connect to Pera Wallet
25
+ * // Connect to Lute (desktop) or Pera (mobile) automatically
21
26
  * const address = await algorand.connect();
22
27
  *
23
28
  * // Create Algorand payment
@@ -28,28 +33,44 @@ import { c as WalletAdapter, C as ChainConfig, P as PaymentInfo, l as X402Versio
28
33
  */
29
34
 
30
35
  /**
31
- * AlgorandProvider - Wallet adapter for Algorand via Pera Wallet
36
+ * AlgorandProvider - Wallet adapter for Algorand
32
37
  *
33
- * Supports both mainnet and testnet through chain configuration.
38
+ * Supports Lute Wallet (desktop) and Pera Wallet (mobile).
39
+ * Automatically detects and uses the best available wallet.
34
40
  */
35
41
  declare class AlgorandProvider implements WalletAdapter {
36
- readonly id = "pera";
37
- readonly name = "Pera Wallet";
42
+ readonly id = "algorand";
43
+ readonly name = "Algorand Wallet";
38
44
  readonly networkType: "algorand";
45
+ private walletType;
46
+ private luteWallet;
39
47
  private peraWallet;
40
48
  private address;
41
49
  private algodClients;
42
50
  /**
43
- * Check if Pera Wallet is available
44
- * Note: Pera works as a WalletConnect modal, so it's always "available"
51
+ * Check if any Algorand wallet is available
52
+ * Returns true if Lute extension is installed OR we can use Pera (always available via WalletConnect)
45
53
  */
46
54
  isAvailable(): boolean;
47
55
  /**
48
- * Connect to Pera Wallet
56
+ * Get the name of the currently connected wallet
57
+ */
58
+ getWalletName(): string;
59
+ /**
60
+ * Connect to Algorand wallet
61
+ * Priority: Lute (desktop extension) > Pera (mobile via WalletConnect)
49
62
  */
50
63
  connect(_chainName?: string): Promise<string>;
51
64
  /**
52
- * Disconnect from Pera Wallet
65
+ * Connect to Lute Wallet (desktop browser extension)
66
+ */
67
+ private connectLute;
68
+ /**
69
+ * Connect to Pera Wallet (mobile via WalletConnect)
70
+ */
71
+ private connectPera;
72
+ /**
73
+ * Disconnect from wallet
53
74
  */
54
75
  disconnect(): Promise<void>;
55
76
  /**
@@ -61,13 +82,19 @@ declare class AlgorandProvider implements WalletAdapter {
61
82
  */
62
83
  getBalance(chainConfig: ChainConfig): Promise<string>;
63
84
  /**
64
- * Create Algorand ASA transfer payment
85
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
86
+ *
87
+ * Transaction structure (atomic group):
88
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
89
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
65
90
  *
66
- * Transaction structure:
67
- * 1. ASA Transfer from user to recipient
68
- * 2. Facilitator pays transaction fees
91
+ * The facilitator signs transaction 0 and submits the complete atomic group.
69
92
  */
70
93
  signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string>;
94
+ /**
95
+ * Decode signed transaction from wallet response (handles various formats)
96
+ */
97
+ private decodeSignedTxn;
71
98
  /**
72
99
  * Encode Algorand payment as X-PAYMENT header
73
100
  *
@@ -688,36 +688,113 @@ function uint8ArrayToBase64(bytes) {
688
688
  }
689
689
  var algosdk = null;
690
690
  var PeraWalletConnect = null;
691
+ var LuteConnect = null;
691
692
  async function loadAlgorandDeps() {
692
693
  if (!algosdk) {
693
694
  algosdk = await import('algosdk');
694
695
  }
696
+ }
697
+ async function loadPeraWallet() {
695
698
  if (!PeraWalletConnect) {
696
699
  const peraModule = await import('@perawallet/connect');
697
700
  PeraWalletConnect = peraModule.PeraWalletConnect;
698
701
  }
699
702
  }
703
+ async function loadLuteWallet() {
704
+ if (!LuteConnect) {
705
+ try {
706
+ const luteModule = await import('lute-connect');
707
+ LuteConnect = luteModule.default;
708
+ } catch {
709
+ LuteConnect = null;
710
+ }
711
+ }
712
+ }
713
+ function isLuteAvailable() {
714
+ if (typeof window === "undefined") return false;
715
+ const win = window;
716
+ return !!(win.algorand || win.lute);
717
+ }
700
718
  var AlgorandProvider = class {
701
- id = "pera";
702
- name = "Pera Wallet";
719
+ id = "algorand";
720
+ name = "Algorand Wallet";
703
721
  networkType = "algorand";
722
+ // Active wallet type
723
+ walletType = null;
724
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
725
+ luteWallet = null;
704
726
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
705
727
  peraWallet = null;
706
728
  address = null;
707
729
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
708
730
  algodClients = /* @__PURE__ */ new Map();
709
731
  /**
710
- * Check if Pera Wallet is available
711
- * Note: Pera works as a WalletConnect modal, so it's always "available"
732
+ * Check if any Algorand wallet is available
733
+ * Returns true if Lute extension is installed OR we can use Pera (always available via WalletConnect)
712
734
  */
713
735
  isAvailable() {
714
736
  return typeof window !== "undefined";
715
737
  }
716
738
  /**
717
- * Connect to Pera Wallet
739
+ * Get the name of the currently connected wallet
740
+ */
741
+ getWalletName() {
742
+ if (this.walletType === "lute") return "Lute Wallet";
743
+ if (this.walletType === "pera") return "Pera Wallet";
744
+ return "Algorand Wallet";
745
+ }
746
+ /**
747
+ * Connect to Algorand wallet
748
+ * Priority: Lute (desktop extension) > Pera (mobile via WalletConnect)
718
749
  */
719
750
  async connect(_chainName) {
720
751
  await loadAlgorandDeps();
752
+ if (isLuteAvailable()) {
753
+ try {
754
+ return await this.connectLute();
755
+ } catch (error) {
756
+ console.warn("Lute connection failed, falling back to Pera:", error);
757
+ }
758
+ }
759
+ return await this.connectPera();
760
+ }
761
+ /**
762
+ * Connect to Lute Wallet (desktop browser extension)
763
+ */
764
+ async connectLute() {
765
+ await loadLuteWallet();
766
+ if (!LuteConnect) {
767
+ throw new X402Error("Lute Wallet SDK not available", "WALLET_NOT_FOUND");
768
+ }
769
+ try {
770
+ this.luteWallet = new LuteConnect("402milly");
771
+ const genesisId = "mainnet-v1.0";
772
+ const accounts = await this.luteWallet.connect(genesisId);
773
+ if (!accounts || accounts.length === 0) {
774
+ throw new X402Error("No accounts returned from Lute Wallet", "WALLET_CONNECTION_REJECTED");
775
+ }
776
+ this.address = accounts[0];
777
+ this.walletType = "lute";
778
+ return accounts[0];
779
+ } catch (error) {
780
+ if (error instanceof X402Error) throw error;
781
+ if (error instanceof Error) {
782
+ if (error.message.includes("rejected") || error.message.includes("cancelled")) {
783
+ throw new X402Error("Connection rejected by user", "WALLET_CONNECTION_REJECTED");
784
+ }
785
+ }
786
+ throw new X402Error(
787
+ `Failed to connect Lute Wallet: ${error instanceof Error ? error.message : "Unknown error"}`,
788
+ "UNKNOWN_ERROR",
789
+ error
790
+ );
791
+ }
792
+ }
793
+ /**
794
+ * Connect to Pera Wallet (mobile via WalletConnect)
795
+ */
796
+ async connectPera() {
797
+ await loadPeraWallet();
721
798
  if (!PeraWalletConnect) {
722
799
  throw new X402Error("Failed to load Pera Wallet SDK", "WALLET_NOT_FOUND");
723
800
  }
@@ -726,6 +803,7 @@ var AlgorandProvider = class {
726
803
  const accounts = await this.peraWallet.reconnectSession();
727
804
  if (accounts.length > 0) {
728
805
  this.address = accounts[0];
806
+ this.walletType = "pera";
729
807
  return accounts[0];
730
808
  }
731
809
  const newAccounts = await this.peraWallet.connect();
@@ -733,8 +811,10 @@ var AlgorandProvider = class {
733
811
  throw new X402Error("No accounts returned from Pera Wallet", "WALLET_CONNECTION_REJECTED");
734
812
  }
735
813
  this.address = newAccounts[0];
814
+ this.walletType = "pera";
736
815
  this.peraWallet.connector?.on("disconnect", () => {
737
816
  this.address = null;
817
+ this.walletType = null;
738
818
  });
739
819
  return newAccounts[0];
740
820
  } catch (error) {
@@ -751,17 +831,21 @@ var AlgorandProvider = class {
751
831
  }
752
832
  }
753
833
  /**
754
- * Disconnect from Pera Wallet
834
+ * Disconnect from wallet
755
835
  */
756
836
  async disconnect() {
757
- if (this.peraWallet) {
837
+ if (this.walletType === "lute" && this.luteWallet) {
838
+ this.luteWallet = null;
839
+ }
840
+ if (this.walletType === "pera" && this.peraWallet) {
758
841
  try {
759
842
  await this.peraWallet.disconnect();
760
843
  } catch {
761
844
  }
845
+ this.peraWallet = null;
762
846
  }
763
- this.peraWallet = null;
764
847
  this.address = null;
848
+ this.walletType = null;
765
849
  this.algodClients.clear();
766
850
  }
767
851
  /**
@@ -797,15 +881,17 @@ var AlgorandProvider = class {
797
881
  }
798
882
  }
799
883
  /**
800
- * Create Algorand ASA transfer payment
884
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
885
+ *
886
+ * Transaction structure (atomic group):
887
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
888
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
801
889
  *
802
- * Transaction structure:
803
- * 1. ASA Transfer from user to recipient
804
- * 2. Facilitator pays transaction fees
890
+ * The facilitator signs transaction 0 and submits the complete atomic group.
805
891
  */
806
892
  async signPayment(paymentInfo, chainConfig) {
807
893
  await loadAlgorandDeps();
808
- if (!this.peraWallet || !this.address) {
894
+ if (!this.address || !this.walletType) {
809
895
  throw new X402Error("Wallet not connected", "WALLET_NOT_CONNECTED");
810
896
  }
811
897
  if (!algosdk) {
@@ -814,28 +900,85 @@ var AlgorandProvider = class {
814
900
  const algodClient = await this.getAlgodClient(chainConfig);
815
901
  const recipient = paymentInfo.recipients?.algorand || paymentInfo.recipient;
816
902
  const assetId = parseInt(chainConfig.usdc.address, 10);
903
+ const facilitatorAddress = paymentInfo.facilitator;
904
+ if (!facilitatorAddress) {
905
+ throw new X402Error(
906
+ "Facilitator address required for Algorand payments. Set paymentInfo.facilitator",
907
+ "PAYMENT_FAILED"
908
+ );
909
+ }
817
910
  const amount = Math.floor(parseFloat(paymentInfo.amount) * 1e6);
818
911
  try {
819
912
  const suggestedParams = await algodClient.getTransactionParams().do();
820
- const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
913
+ const feeTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
914
+ sender: facilitatorAddress,
915
+ receiver: facilitatorAddress,
916
+ // self-transfer
917
+ amount: 0,
918
+ suggestedParams: {
919
+ ...suggestedParams,
920
+ fee: 2e3,
921
+ // Covers both transactions (1000 each)
922
+ flatFee: true
923
+ }
924
+ });
925
+ const paymentTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
821
926
  sender: this.address,
822
927
  receiver: recipient,
823
928
  amount: BigInt(amount),
824
929
  assetIndex: assetId,
825
- suggestedParams,
930
+ suggestedParams: {
931
+ ...suggestedParams,
932
+ fee: 0,
933
+ // Fee paid by transaction 0
934
+ flatFee: true
935
+ },
826
936
  note: new TextEncoder().encode("x402 payment via uvd-x402-sdk")
827
937
  });
828
- const signedTxns = await this.peraWallet.signTransaction([[{ txn }]]);
829
- if (!signedTxns || signedTxns.length === 0) {
830
- throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
938
+ const txnGroup = algosdk.assignGroupID([feeTxn, paymentTxn]);
939
+ const unsignedFeeTxnBytes = algosdk.encodeUnsignedTransaction(txnGroup[0]);
940
+ const unsignedFeeTxnBase64 = uint8ArrayToBase64(unsignedFeeTxnBytes);
941
+ let signedPaymentTxnBytes;
942
+ if (this.walletType === "lute" && this.luteWallet) {
943
+ const feeTxnBase64 = uint8ArrayToBase64(txnGroup[0].toByte());
944
+ const paymentTxnBase64 = uint8ArrayToBase64(txnGroup[1].toByte());
945
+ const signedTxns = await this.luteWallet.signTxns([
946
+ { txn: feeTxnBase64, signers: [] },
947
+ // Don't sign - facilitator will
948
+ { txn: paymentTxnBase64 }
949
+ // Sign this one
950
+ ]);
951
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
952
+ throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
953
+ }
954
+ const signedResult = signedTxns[1];
955
+ signedPaymentTxnBytes = this.decodeSignedTxn(signedResult);
956
+ } else if (this.walletType === "pera" && this.peraWallet) {
957
+ const signedTxns = await this.peraWallet.signTransaction([
958
+ [
959
+ { txn: txnGroup[0], signers: [] },
960
+ // Don't sign - facilitator will
961
+ { txn: txnGroup[1] }
962
+ // Sign this one
963
+ ]
964
+ ]);
965
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
966
+ throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
967
+ }
968
+ signedPaymentTxnBytes = signedTxns[1];
969
+ } else {
970
+ throw new X402Error("No wallet available for signing", "WALLET_NOT_CONNECTED");
831
971
  }
832
- const signedTxn = signedTxns[0];
972
+ const signedPaymentTxnBase64 = uint8ArrayToBase64(signedPaymentTxnBytes);
833
973
  const payload = {
834
- from: this.address,
835
- to: recipient,
836
- amount: amount.toString(),
837
- assetId,
838
- signedTxn: uint8ArrayToBase64(signedTxn)
974
+ paymentIndex: 1,
975
+ // Index of the payment transaction in the group
976
+ paymentGroup: [
977
+ unsignedFeeTxnBase64,
978
+ // Transaction 0: unsigned fee tx
979
+ signedPaymentTxnBase64
980
+ // Transaction 1: signed payment tx
981
+ ]
839
982
  };
840
983
  return JSON.stringify(payload);
841
984
  } catch (error) {
@@ -854,6 +997,29 @@ var AlgorandProvider = class {
854
997
  );
855
998
  }
856
999
  }
1000
+ /**
1001
+ * Decode signed transaction from wallet response (handles various formats)
1002
+ */
1003
+ decodeSignedTxn(signedResult) {
1004
+ if (signedResult instanceof Uint8Array) {
1005
+ return signedResult;
1006
+ } else if (typeof signedResult === "string") {
1007
+ try {
1008
+ return Uint8Array.from(atob(signedResult), (c) => c.charCodeAt(0));
1009
+ } catch {
1010
+ const standardBase64 = signedResult.replace(/-/g, "+").replace(/_/g, "/");
1011
+ return Uint8Array.from(atob(standardBase64), (c) => c.charCodeAt(0));
1012
+ }
1013
+ } else if (ArrayBuffer.isView(signedResult)) {
1014
+ return new Uint8Array(
1015
+ signedResult.buffer,
1016
+ signedResult.byteOffset,
1017
+ signedResult.byteLength
1018
+ );
1019
+ } else {
1020
+ throw new X402Error("Unexpected signed transaction format", "PAYMENT_FAILED");
1021
+ }
1022
+ }
857
1023
  /**
858
1024
  * Encode Algorand payment as X-PAYMENT header
859
1025
  *
@@ -864,14 +1030,15 @@ var AlgorandProvider = class {
864
1030
  */
865
1031
  encodePaymentHeader(paymentPayload, chainConfig, version = 1) {
866
1032
  const payload = JSON.parse(paymentPayload);
867
- const networkName = chainConfig?.name || "algorand";
1033
+ let networkName;
1034
+ if (chainConfig?.name === "algorand-testnet") {
1035
+ networkName = "algorand-testnet";
1036
+ } else {
1037
+ networkName = "algorand-mainnet";
1038
+ }
868
1039
  const payloadData = {
869
- from: payload.from,
870
- to: payload.to,
871
- amount: payload.amount,
872
- assetId: payload.assetId,
873
- signedTxn: payload.signedTxn,
874
- ...payload.note && { note: payload.note }
1040
+ paymentIndex: payload.paymentIndex,
1041
+ paymentGroup: payload.paymentGroup
875
1042
  };
876
1043
  const x402Payload = version === 2 ? {
877
1044
  x402Version: 2,
@@ -883,7 +1050,6 @@ var AlgorandProvider = class {
883
1050
  x402Version: 1,
884
1051
  scheme: "exact",
885
1052
  network: networkName,
886
- // Plain chain name for v1
887
1053
  payload: payloadData
888
1054
  };
889
1055
  return btoa(JSON.stringify(x402Payload));