uvd-x402-sdk 2.11.1 → 2.13.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 (53) 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 +56 -2
  14. package/dist/index.d.ts +56 -2
  15. package/dist/index.js +59 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +58 -1
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/providers/algorand/index.d.mts +11 -5
  20. package/dist/providers/algorand/index.d.ts +11 -5
  21. package/dist/providers/algorand/index.js +142 -27
  22. package/dist/providers/algorand/index.js.map +1 -1
  23. package/dist/providers/algorand/index.mjs +142 -27
  24. package/dist/providers/algorand/index.mjs.map +1 -1
  25. package/dist/providers/evm/index.d.mts +1 -1
  26. package/dist/providers/evm/index.d.ts +1 -1
  27. package/dist/providers/evm/index.js.map +1 -1
  28. package/dist/providers/evm/index.mjs.map +1 -1
  29. package/dist/providers/near/index.d.mts +1 -1
  30. package/dist/providers/near/index.d.ts +1 -1
  31. package/dist/providers/near/index.js.map +1 -1
  32. package/dist/providers/near/index.mjs.map +1 -1
  33. package/dist/providers/solana/index.d.mts +1 -1
  34. package/dist/providers/solana/index.d.ts +1 -1
  35. package/dist/providers/solana/index.js.map +1 -1
  36. package/dist/providers/solana/index.mjs.map +1 -1
  37. package/dist/providers/stellar/index.d.mts +1 -1
  38. package/dist/providers/stellar/index.d.ts +1 -1
  39. package/dist/providers/stellar/index.js.map +1 -1
  40. package/dist/providers/stellar/index.mjs.map +1 -1
  41. package/dist/react/index.d.mts +3 -3
  42. package/dist/react/index.d.ts +3 -3
  43. package/dist/react/index.js.map +1 -1
  44. package/dist/react/index.mjs.map +1 -1
  45. package/dist/utils/index.d.mts +1 -1
  46. package/dist/utils/index.d.ts +1 -1
  47. package/dist/utils/index.js.map +1 -1
  48. package/dist/utils/index.mjs.map +1 -1
  49. package/package.json +1 -1
  50. package/src/facilitator.ts +106 -0
  51. package/src/index.ts +4 -0
  52. package/src/providers/algorand/index.ts +122 -32
  53. package/src/types/index.ts +18 -22
@@ -1,4 +1,4 @@
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
@@ -82,13 +82,19 @@ declare class AlgorandProvider implements WalletAdapter {
82
82
  */
83
83
  getBalance(chainConfig: ChainConfig): Promise<string>;
84
84
  /**
85
- * Create Algorand ASA transfer payment
85
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
86
86
  *
87
- * Transaction structure:
88
- * 1. ASA Transfer from user to recipient
89
- * 2. Facilitator pays transaction fees
87
+ * Transaction structure (atomic group):
88
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
89
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
90
+ *
91
+ * The facilitator signs transaction 0 and submits the complete atomic group.
90
92
  */
91
93
  signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string>;
94
+ /**
95
+ * Decode signed transaction from wallet response (handles various formats)
96
+ */
97
+ private decodeSignedTxn;
92
98
  /**
93
99
  * Encode Algorand payment as X-PAYMENT header
94
100
  *
@@ -1,4 +1,4 @@
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
@@ -82,13 +82,19 @@ declare class AlgorandProvider implements WalletAdapter {
82
82
  */
83
83
  getBalance(chainConfig: ChainConfig): Promise<string>;
84
84
  /**
85
- * Create Algorand ASA transfer payment
85
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
86
86
  *
87
- * Transaction structure:
88
- * 1. ASA Transfer from user to recipient
89
- * 2. Facilitator pays transaction fees
87
+ * Transaction structure (atomic group):
88
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
89
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
90
+ *
91
+ * The facilitator signs transaction 0 and submits the complete atomic group.
90
92
  */
91
93
  signPayment(paymentInfo: PaymentInfo, chainConfig: ChainConfig): Promise<string>;
94
+ /**
95
+ * Decode signed transaction from wallet response (handles various formats)
96
+ */
97
+ private decodeSignedTxn;
92
98
  /**
93
99
  * Encode Algorand payment as X-PAYMENT header
94
100
  *
@@ -678,6 +678,50 @@ function chainToCAIP2(chainName) {
678
678
  return chainName;
679
679
  }
680
680
 
681
+ // src/facilitator.ts
682
+ var FACILITATOR_ADDRESSES = {
683
+ /**
684
+ * Solana facilitator address (fee payer)
685
+ * Used for: Paying transaction fees on Solana
686
+ */
687
+ solana: "F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq",
688
+ /**
689
+ * Algorand facilitator address (fee payer)
690
+ * Used for: Signing Transaction 0 (fee tx) in atomic groups
691
+ * Note: This is derived from the facilitator's Algorand mnemonic
692
+ */
693
+ algorand: "SXHRBXS22SKKXHXK44DTQMWN2SXK3SFJWBDAQZGF4DRPW7PNFAUM2GYFAQ",
694
+ /**
695
+ * Algorand testnet facilitator address
696
+ */
697
+ "algorand-testnet": "SXHRBXS22SKKXHXK44DTQMWN2SXK3SFJWBDAQZGF4DRPW7PNFAUM2GYFAQ",
698
+ /**
699
+ * EVM facilitator address
700
+ * Used for: Submitting EIP-3009 transferWithAuthorization transactions
701
+ * Note: Same address across all EVM chains
702
+ */
703
+ evm: "0x7c5F3AdB0C7775968Bc7e7cF61b27fECf2e2b500",
704
+ /**
705
+ * Stellar facilitator address
706
+ * Used for: Signing soroban authorization entries
707
+ */
708
+ stellar: "GDUTDNV53WQPOB2JUZPO6SXH4LVT7CJSLCMLFQ7W4CNAXGIX7XYMCNP2",
709
+ /**
710
+ * NEAR facilitator address
711
+ * Used for: Relaying meta-transactions
712
+ */
713
+ near: "uvd-facilitator.near"
714
+ };
715
+ function getFacilitatorAddress(chainName, networkType) {
716
+ const exactMatch = FACILITATOR_ADDRESSES[chainName];
717
+ if (exactMatch) {
718
+ return exactMatch;
719
+ }
720
+ {
721
+ return FACILITATOR_ADDRESSES.algorand;
722
+ }
723
+ }
724
+
681
725
  // src/providers/algorand/index.ts
682
726
  function uint8ArrayToBase64(bytes) {
683
727
  let binary = "";
@@ -881,11 +925,13 @@ var AlgorandProvider = class {
881
925
  }
882
926
  }
883
927
  /**
884
- * Create Algorand ASA transfer payment
928
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
929
+ *
930
+ * Transaction structure (atomic group):
931
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
932
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
885
933
  *
886
- * Transaction structure:
887
- * 1. ASA Transfer from user to recipient
888
- * 2. Facilitator pays transaction fees
934
+ * The facilitator signs transaction 0 and submits the complete atomic group.
889
935
  */
890
936
  async signPayment(paymentInfo, chainConfig) {
891
937
  await loadAlgorandDeps();
@@ -898,40 +944,86 @@ var AlgorandProvider = class {
898
944
  const algodClient = await this.getAlgodClient(chainConfig);
899
945
  const recipient = paymentInfo.recipients?.algorand || paymentInfo.recipient;
900
946
  const assetId = parseInt(chainConfig.usdc.address, 10);
947
+ const chainName = chainConfig?.name || "algorand";
948
+ const facilitatorAddress = paymentInfo.facilitator || getFacilitatorAddress(chainName);
949
+ if (!facilitatorAddress) {
950
+ throw new X402Error(
951
+ "Facilitator address not configured for Algorand",
952
+ "PAYMENT_FAILED"
953
+ );
954
+ }
901
955
  const amount = Math.floor(parseFloat(paymentInfo.amount) * 1e6);
902
956
  try {
903
957
  const suggestedParams = await algodClient.getTransactionParams().do();
904
- const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
958
+ const feeTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
959
+ sender: facilitatorAddress,
960
+ receiver: facilitatorAddress,
961
+ // self-transfer
962
+ amount: 0,
963
+ suggestedParams: {
964
+ ...suggestedParams,
965
+ fee: 2e3,
966
+ // Covers both transactions (1000 each)
967
+ flatFee: true
968
+ }
969
+ });
970
+ const paymentTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
905
971
  sender: this.address,
906
972
  receiver: recipient,
907
973
  amount: BigInt(amount),
908
974
  assetIndex: assetId,
909
- suggestedParams,
975
+ suggestedParams: {
976
+ ...suggestedParams,
977
+ fee: 0,
978
+ // Fee paid by transaction 0
979
+ flatFee: true
980
+ },
910
981
  note: new TextEncoder().encode("x402 payment via uvd-x402-sdk")
911
982
  });
912
- let signedTxn;
983
+ const txnGroup = algosdk.assignGroupID([feeTxn, paymentTxn]);
984
+ const unsignedFeeTxnBytes = algosdk.encodeUnsignedTransaction(txnGroup[0]);
985
+ const unsignedFeeTxnBase64 = uint8ArrayToBase64(unsignedFeeTxnBytes);
986
+ let signedPaymentTxnBytes;
913
987
  if (this.walletType === "lute" && this.luteWallet) {
914
- const txnBase64 = uint8ArrayToBase64(txn.toByte());
915
- const signedTxns = await this.luteWallet.signTxns([{ txn: txnBase64 }]);
916
- if (!signedTxns || signedTxns.length === 0 || !signedTxns[0]) {
988
+ const feeTxnBase64 = uint8ArrayToBase64(txnGroup[0].toByte());
989
+ const paymentTxnBase64 = uint8ArrayToBase64(txnGroup[1].toByte());
990
+ const signedTxns = await this.luteWallet.signTxns([
991
+ { txn: feeTxnBase64, signers: [] },
992
+ // Don't sign - facilitator will
993
+ { txn: paymentTxnBase64 }
994
+ // Sign this one
995
+ ]);
996
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
917
997
  throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
918
998
  }
919
- signedTxn = Uint8Array.from(atob(signedTxns[0]), (c) => c.charCodeAt(0));
999
+ const signedResult = signedTxns[1];
1000
+ signedPaymentTxnBytes = this.decodeSignedTxn(signedResult);
920
1001
  } else if (this.walletType === "pera" && this.peraWallet) {
921
- const signedTxns = await this.peraWallet.signTransaction([[{ txn }]]);
922
- if (!signedTxns || signedTxns.length === 0) {
1002
+ const signedTxns = await this.peraWallet.signTransaction([
1003
+ [
1004
+ { txn: txnGroup[0], signers: [] },
1005
+ // Don't sign - facilitator will
1006
+ { txn: txnGroup[1] }
1007
+ // Sign this one
1008
+ ]
1009
+ ]);
1010
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
923
1011
  throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
924
1012
  }
925
- signedTxn = signedTxns[0];
1013
+ signedPaymentTxnBytes = signedTxns[1];
926
1014
  } else {
927
1015
  throw new X402Error("No wallet available for signing", "WALLET_NOT_CONNECTED");
928
1016
  }
1017
+ const signedPaymentTxnBase64 = uint8ArrayToBase64(signedPaymentTxnBytes);
929
1018
  const payload = {
930
- from: this.address,
931
- to: recipient,
932
- amount: amount.toString(),
933
- assetId,
934
- signedTxn: uint8ArrayToBase64(signedTxn)
1019
+ paymentIndex: 1,
1020
+ // Index of the payment transaction in the group
1021
+ paymentGroup: [
1022
+ unsignedFeeTxnBase64,
1023
+ // Transaction 0: unsigned fee tx
1024
+ signedPaymentTxnBase64
1025
+ // Transaction 1: signed payment tx
1026
+ ]
935
1027
  };
936
1028
  return JSON.stringify(payload);
937
1029
  } catch (error) {
@@ -950,6 +1042,29 @@ var AlgorandProvider = class {
950
1042
  );
951
1043
  }
952
1044
  }
1045
+ /**
1046
+ * Decode signed transaction from wallet response (handles various formats)
1047
+ */
1048
+ decodeSignedTxn(signedResult) {
1049
+ if (signedResult instanceof Uint8Array) {
1050
+ return signedResult;
1051
+ } else if (typeof signedResult === "string") {
1052
+ try {
1053
+ return Uint8Array.from(atob(signedResult), (c) => c.charCodeAt(0));
1054
+ } catch {
1055
+ const standardBase64 = signedResult.replace(/-/g, "+").replace(/_/g, "/");
1056
+ return Uint8Array.from(atob(standardBase64), (c) => c.charCodeAt(0));
1057
+ }
1058
+ } else if (ArrayBuffer.isView(signedResult)) {
1059
+ return new Uint8Array(
1060
+ signedResult.buffer,
1061
+ signedResult.byteOffset,
1062
+ signedResult.byteLength
1063
+ );
1064
+ } else {
1065
+ throw new X402Error("Unexpected signed transaction format", "PAYMENT_FAILED");
1066
+ }
1067
+ }
953
1068
  /**
954
1069
  * Encode Algorand payment as X-PAYMENT header
955
1070
  *
@@ -960,14 +1075,15 @@ var AlgorandProvider = class {
960
1075
  */
961
1076
  encodePaymentHeader(paymentPayload, chainConfig, version = 1) {
962
1077
  const payload = JSON.parse(paymentPayload);
963
- const networkName = chainConfig?.name || "algorand";
1078
+ let networkName;
1079
+ if (chainConfig?.name === "algorand-testnet") {
1080
+ networkName = "algorand-testnet";
1081
+ } else {
1082
+ networkName = "algorand-mainnet";
1083
+ }
964
1084
  const payloadData = {
965
- from: payload.from,
966
- to: payload.to,
967
- amount: payload.amount,
968
- assetId: payload.assetId,
969
- signedTxn: payload.signedTxn,
970
- ...payload.note && { note: payload.note }
1085
+ paymentIndex: payload.paymentIndex,
1086
+ paymentGroup: payload.paymentGroup
971
1087
  };
972
1088
  const x402Payload = version === 2 ? {
973
1089
  x402Version: 2,
@@ -979,7 +1095,6 @@ var AlgorandProvider = class {
979
1095
  x402Version: 1,
980
1096
  scheme: "exact",
981
1097
  network: networkName,
982
- // Plain chain name for v1
983
1098
  payload: payloadData
984
1099
  };
985
1100
  return btoa(JSON.stringify(x402Payload));