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.
- package/dist/adapters/index.d.mts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js.map +1 -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.map +1 -1
- package/dist/backend/index.mjs.map +1 -1
- package/dist/{index-C60c_e5z.d.mts → index-C6Vxnneo.d.mts} +1 -1
- package/dist/{index-VIOUicmO.d.ts → index-DmJGKD9r.d.ts} +1 -1
- package/dist/{index-D-dO_FoP.d.mts → index-fIhvHqCQ.d.mts} +18 -22
- package/dist/{index-D-dO_FoP.d.ts → index-fIhvHqCQ.d.ts} +18 -22
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/providers/algorand/index.d.mts +42 -15
- package/dist/providers/algorand/index.d.ts +42 -15
- package/dist/providers/algorand/index.js +198 -32
- package/dist/providers/algorand/index.js.map +1 -1
- package/dist/providers/algorand/index.mjs +198 -32
- 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.map +1 -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.map +1 -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.map +1 -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.map +1 -1
- package/dist/providers/stellar/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js.map +1 -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.map +1 -1
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +6 -1
- package/src/providers/algorand/index.ts +261 -40
- 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-
|
|
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
|
|
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
|
|
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
|
|
36
|
+
* AlgorandProvider - Wallet adapter for Algorand
|
|
32
37
|
*
|
|
33
|
-
* Supports
|
|
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 = "
|
|
37
|
-
readonly name = "
|
|
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
|
|
44
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
36
|
+
* AlgorandProvider - Wallet adapter for Algorand
|
|
32
37
|
*
|
|
33
|
-
* Supports
|
|
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 = "
|
|
37
|
-
readonly name = "
|
|
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
|
|
44
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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 = "
|
|
702
|
-
name = "
|
|
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
|
|
711
|
-
*
|
|
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
|
-
*
|
|
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
|
|
834
|
+
* Disconnect from wallet
|
|
755
835
|
*/
|
|
756
836
|
async disconnect() {
|
|
757
|
-
if (this.
|
|
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
|
|
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
|
-
*
|
|
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.
|
|
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
|
|
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
|
|
829
|
-
|
|
830
|
-
|
|
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
|
|
972
|
+
const signedPaymentTxnBase64 = uint8ArrayToBase64(signedPaymentTxnBytes);
|
|
833
973
|
const payload = {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
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
|
-
|
|
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
|
-
|
|
870
|
-
|
|
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));
|