uvd-x402-sdk 2.11.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 +11 -5
  18. package/dist/providers/algorand/index.d.ts +11 -5
  19. package/dist/providers/algorand/index.js +97 -27
  20. package/dist/providers/algorand/index.js.map +1 -1
  21. package/dist/providers/algorand/index.mjs +97 -27
  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 +1 -1
  48. package/src/providers/algorand/index.ts +117 -32
  49. package/src/types/index.ts +18 -22
@@ -877,11 +877,13 @@ var AlgorandProvider = class {
877
877
  }
878
878
  }
879
879
  /**
880
- * Create Algorand ASA transfer payment
880
+ * Create Algorand atomic group payment (GoPlausible x402-avm spec)
881
881
  *
882
- * Transaction structure:
883
- * 1. ASA Transfer from user to recipient
884
- * 2. Facilitator pays transaction fees
882
+ * Transaction structure (atomic group):
883
+ * - Transaction 0: Fee payment (UNSIGNED) - facilitator -> facilitator, covers all fees
884
+ * - Transaction 1: ASA transfer (SIGNED) - client -> merchant
885
+ *
886
+ * The facilitator signs transaction 0 and submits the complete atomic group.
885
887
  */
886
888
  async signPayment(paymentInfo, chainConfig) {
887
889
  await loadAlgorandDeps();
@@ -894,40 +896,85 @@ var AlgorandProvider = class {
894
896
  const algodClient = await this.getAlgodClient(chainConfig);
895
897
  const recipient = paymentInfo.recipients?.algorand || paymentInfo.recipient;
896
898
  const assetId = parseInt(chainConfig.usdc.address, 10);
899
+ const facilitatorAddress = paymentInfo.facilitator;
900
+ if (!facilitatorAddress) {
901
+ throw new X402Error(
902
+ "Facilitator address required for Algorand payments. Set paymentInfo.facilitator",
903
+ "PAYMENT_FAILED"
904
+ );
905
+ }
897
906
  const amount = Math.floor(parseFloat(paymentInfo.amount) * 1e6);
898
907
  try {
899
908
  const suggestedParams = await algodClient.getTransactionParams().do();
900
- const txn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
909
+ const feeTxn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
910
+ sender: facilitatorAddress,
911
+ receiver: facilitatorAddress,
912
+ // self-transfer
913
+ amount: 0,
914
+ suggestedParams: {
915
+ ...suggestedParams,
916
+ fee: 2e3,
917
+ // Covers both transactions (1000 each)
918
+ flatFee: true
919
+ }
920
+ });
921
+ const paymentTxn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
901
922
  sender: this.address,
902
923
  receiver: recipient,
903
924
  amount: BigInt(amount),
904
925
  assetIndex: assetId,
905
- suggestedParams,
926
+ suggestedParams: {
927
+ ...suggestedParams,
928
+ fee: 0,
929
+ // Fee paid by transaction 0
930
+ flatFee: true
931
+ },
906
932
  note: new TextEncoder().encode("x402 payment via uvd-x402-sdk")
907
933
  });
908
- let signedTxn;
934
+ const txnGroup = algosdk.assignGroupID([feeTxn, paymentTxn]);
935
+ const unsignedFeeTxnBytes = algosdk.encodeUnsignedTransaction(txnGroup[0]);
936
+ const unsignedFeeTxnBase64 = uint8ArrayToBase64(unsignedFeeTxnBytes);
937
+ let signedPaymentTxnBytes;
909
938
  if (this.walletType === "lute" && this.luteWallet) {
910
- const txnBase64 = uint8ArrayToBase64(txn.toByte());
911
- const signedTxns = await this.luteWallet.signTxns([{ txn: txnBase64 }]);
912
- if (!signedTxns || signedTxns.length === 0 || !signedTxns[0]) {
939
+ const feeTxnBase64 = uint8ArrayToBase64(txnGroup[0].toByte());
940
+ const paymentTxnBase64 = uint8ArrayToBase64(txnGroup[1].toByte());
941
+ const signedTxns = await this.luteWallet.signTxns([
942
+ { txn: feeTxnBase64, signers: [] },
943
+ // Don't sign - facilitator will
944
+ { txn: paymentTxnBase64 }
945
+ // Sign this one
946
+ ]);
947
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
913
948
  throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
914
949
  }
915
- signedTxn = Uint8Array.from(atob(signedTxns[0]), (c) => c.charCodeAt(0));
950
+ const signedResult = signedTxns[1];
951
+ signedPaymentTxnBytes = this.decodeSignedTxn(signedResult);
916
952
  } else if (this.walletType === "pera" && this.peraWallet) {
917
- const signedTxns = await this.peraWallet.signTransaction([[{ txn }]]);
918
- if (!signedTxns || signedTxns.length === 0) {
953
+ const signedTxns = await this.peraWallet.signTransaction([
954
+ [
955
+ { txn: txnGroup[0], signers: [] },
956
+ // Don't sign - facilitator will
957
+ { txn: txnGroup[1] }
958
+ // Sign this one
959
+ ]
960
+ ]);
961
+ if (!signedTxns || signedTxns.length < 2 || !signedTxns[1]) {
919
962
  throw new X402Error("No signed transaction returned", "SIGNATURE_REJECTED");
920
963
  }
921
- signedTxn = signedTxns[0];
964
+ signedPaymentTxnBytes = signedTxns[1];
922
965
  } else {
923
966
  throw new X402Error("No wallet available for signing", "WALLET_NOT_CONNECTED");
924
967
  }
968
+ const signedPaymentTxnBase64 = uint8ArrayToBase64(signedPaymentTxnBytes);
925
969
  const payload = {
926
- from: this.address,
927
- to: recipient,
928
- amount: amount.toString(),
929
- assetId,
930
- signedTxn: uint8ArrayToBase64(signedTxn)
970
+ paymentIndex: 1,
971
+ // Index of the payment transaction in the group
972
+ paymentGroup: [
973
+ unsignedFeeTxnBase64,
974
+ // Transaction 0: unsigned fee tx
975
+ signedPaymentTxnBase64
976
+ // Transaction 1: signed payment tx
977
+ ]
931
978
  };
932
979
  return JSON.stringify(payload);
933
980
  } catch (error) {
@@ -946,6 +993,29 @@ var AlgorandProvider = class {
946
993
  );
947
994
  }
948
995
  }
996
+ /**
997
+ * Decode signed transaction from wallet response (handles various formats)
998
+ */
999
+ decodeSignedTxn(signedResult) {
1000
+ if (signedResult instanceof Uint8Array) {
1001
+ return signedResult;
1002
+ } else if (typeof signedResult === "string") {
1003
+ try {
1004
+ return Uint8Array.from(atob(signedResult), (c) => c.charCodeAt(0));
1005
+ } catch {
1006
+ const standardBase64 = signedResult.replace(/-/g, "+").replace(/_/g, "/");
1007
+ return Uint8Array.from(atob(standardBase64), (c) => c.charCodeAt(0));
1008
+ }
1009
+ } else if (ArrayBuffer.isView(signedResult)) {
1010
+ return new Uint8Array(
1011
+ signedResult.buffer,
1012
+ signedResult.byteOffset,
1013
+ signedResult.byteLength
1014
+ );
1015
+ } else {
1016
+ throw new X402Error("Unexpected signed transaction format", "PAYMENT_FAILED");
1017
+ }
1018
+ }
949
1019
  /**
950
1020
  * Encode Algorand payment as X-PAYMENT header
951
1021
  *
@@ -956,14 +1026,15 @@ var AlgorandProvider = class {
956
1026
  */
957
1027
  encodePaymentHeader(paymentPayload, chainConfig, version = 1) {
958
1028
  const payload = JSON.parse(paymentPayload);
959
- const networkName = chainConfig?.name || "algorand";
1029
+ let networkName;
1030
+ if (chainConfig?.name === "algorand-testnet") {
1031
+ networkName = "algorand-testnet";
1032
+ } else {
1033
+ networkName = "algorand-mainnet";
1034
+ }
960
1035
  const payloadData = {
961
- from: payload.from,
962
- to: payload.to,
963
- amount: payload.amount,
964
- assetId: payload.assetId,
965
- signedTxn: payload.signedTxn,
966
- ...payload.note && { note: payload.note }
1036
+ paymentIndex: payload.paymentIndex,
1037
+ paymentGroup: payload.paymentGroup
967
1038
  };
968
1039
  const x402Payload = version === 2 ? {
969
1040
  x402Version: 2,
@@ -975,7 +1046,6 @@ var AlgorandProvider = class {
975
1046
  x402Version: 1,
976
1047
  scheme: "exact",
977
1048
  network: networkName,
978
- // Plain chain name for v1
979
1049
  payload: payloadData
980
1050
  };
981
1051
  return btoa(JSON.stringify(x402Payload));