@stellar/typescript-wallet-sdk 1.5.0 → 1.6.0-beta.1719865729038

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 (35) hide show
  1. package/CHANGELOG.MD +11 -1
  2. package/lib/bundle.js +7354 -3358
  3. package/lib/bundle.js.map +1 -1
  4. package/lib/bundle_browser.js +1117 -11
  5. package/lib/bundle_browser.js.map +1 -1
  6. package/lib/index.d.ts +1 -0
  7. package/lib/walletSdk/Exceptions/index.d.ts +15 -0
  8. package/lib/walletSdk/Types/anchor.d.ts +5 -1
  9. package/lib/walletSdk/Types/index.d.ts +1 -0
  10. package/lib/walletSdk/Types/sep7.d.ts +15 -0
  11. package/lib/walletSdk/Uri/Sep7Base.d.ts +187 -0
  12. package/lib/walletSdk/Uri/Sep7Pay.d.ts +121 -0
  13. package/lib/walletSdk/Uri/Sep7Tx.d.ts +133 -0
  14. package/lib/walletSdk/Uri/index.d.ts +4 -0
  15. package/lib/walletSdk/Uri/sep7Parser.d.ts +60 -0
  16. package/lib/walletSdk/Utils/index.d.ts +2 -1
  17. package/package.json +3 -3
  18. package/src/index.ts +9 -0
  19. package/src/walletSdk/Auth/WalletSigner.ts +3 -3
  20. package/src/walletSdk/Customer/index.ts +7 -7
  21. package/src/walletSdk/Exceptions/index.ts +38 -1
  22. package/src/walletSdk/Horizon/Account.ts +2 -1
  23. package/src/walletSdk/Types/anchor.ts +4 -0
  24. package/src/walletSdk/Types/index.ts +1 -0
  25. package/src/walletSdk/Types/sep7.ts +19 -0
  26. package/src/walletSdk/Uri/Sep7Base.ts +311 -0
  27. package/src/walletSdk/Uri/Sep7Pay.ts +169 -0
  28. package/src/walletSdk/Uri/Sep7Tx.ts +193 -0
  29. package/src/walletSdk/Uri/index.ts +9 -0
  30. package/src/walletSdk/Uri/sep7Parser.ts +220 -0
  31. package/src/walletSdk/Utils/index.ts +2 -1
  32. package/src/walletSdk/Watcher/index.ts +3 -1
  33. package/test/customer.test.ts +7 -7
  34. package/test/integration/anchorplatform.test.ts +2 -2
  35. package/test/sep7.test.ts +825 -0
@@ -0,0 +1,825 @@
1
+ import { Keypair, Networks, StellarToml } from "@stellar/stellar-sdk";
2
+ import {
3
+ NativeAssetId,
4
+ Sep7Pay,
5
+ Sep7Tx,
6
+ SigningKeypair,
7
+ Stellar,
8
+ Wallet,
9
+ isValidSep7Uri,
10
+ parseSep7Uri,
11
+ sep7ReplacementsFromString,
12
+ sep7ReplacementsToString,
13
+ } from "../src";
14
+ import { Sep7OperationType } from "../src/walletSdk/Types";
15
+ import {
16
+ Sep7InvalidUriError,
17
+ Sep7LongMsgError,
18
+ } from "../src/walletSdk/Exceptions";
19
+
20
+ const testKp1 = SigningKeypair.fromSecret(
21
+ "SBKQDF56C5VY2YQTNQFGY7HM6R3V6QKDUEDXZQUCPQOP2EBZWG2QJ2JL",
22
+ );
23
+
24
+ const testKp2 = SigningKeypair.fromSecret(
25
+ "SBIK5MF5QONDTKA5ZPXLI2XTBIAOWQEEOZ3TM76XVBPPJ2EEUUXTCIVZ",
26
+ );
27
+
28
+ const xdrs = {
29
+ classic: encodeURIComponent(
30
+ "AAAAAgAAAACCMXQVfkjpO2gAJQzKsUsPfdBCyfrvy7sr8+35cOxOSwAAAGQABqQMAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAACCMXQVfkjpO2gAJQzKsUsPfdBCyfrvy7sr8+35cOxOSwAAAAAAmJaAAAAAAAAAAAFw7E5LAAAAQBu4V+/lttEONNM6KFwdSf5TEEogyEBy0jTOHJKuUzKScpLHyvDJGY+xH9Ri4cIuA7AaB8aL+VdlucCfsNYpKAY=",
31
+ ),
32
+ sorobanTransfer: encodeURIComponent(
33
+ "AAAAAgAAAACM6IR9GHiRoVVAO78JJNksy2fKDQNs2jBn8bacsRLcrDucaFsAAAWIAAAAMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABHkEVdJ+UfDnWpBr/qF582IEoDQ0iW0WPzO9CEUdvvh8AAAAIdHJhbnNmZXIAAAADAAAAEgAAAAAAAAAAjOiEfRh4kaFVQDu/CSTZLMtnyg0DbNowZ/G2nLES3KwAAAASAAAAAAAAAADoFl2ACT9HZkbCeuaT9MAIdStpdf58wM3P24nl738AnQAAAAoAAAAAAAAAAAAAAAAAAAAFAAAAAQAAAAAAAAAAAAAAAR5BFXSflHw51qQa/6hefNiBKA0NIltFj8zvQhFHb74fAAAACHRyYW5zZmVyAAAAAwAAABIAAAAAAAAAAIzohH0YeJGhVUA7vwkk2SzLZ8oNA2zaMGfxtpyxEtysAAAAEgAAAAAAAAAA6BZdgAk/R2ZGwnrmk/TACHUraXX+fMDNz9uJ5e9/AJ0AAAAKAAAAAAAAAAAAAAAAAAAABQAAAAAAAAABAAAAAAAAAAIAAAAGAAAAAR5BFXSflHw51qQa/6hefNiBKA0NIltFj8zvQhFHb74fAAAAFAAAAAEAAAAHa35L+/RxV6EuJOVk78H5rCN+eubXBWtsKrRxeLnnpRAAAAACAAAABgAAAAEeQRV0n5R8OdakGv+oXnzYgSgNDSJbRY/M70IRR2++HwAAABAAAAABAAAAAgAAAA8AAAAHQmFsYW5jZQAAAAASAAAAAAAAAACM6IR9GHiRoVVAO78JJNksy2fKDQNs2jBn8bacsRLcrAAAAAEAAAAGAAAAAR5BFXSflHw51qQa/6hefNiBKA0NIltFj8zvQhFHb74fAAAAEAAAAAEAAAACAAAADwAAAAdCYWxhbmNlAAAAABIAAAAAAAAAAOgWXYAJP0dmRsJ65pP0wAh1K2l1/nzAzc/bieXvfwCdAAAAAQBkcwsAACBwAAABKAAAAAAAAB1kAAAAAA==",
34
+ ),
35
+ sorobanMint: encodeURIComponent(
36
+ "AAAAAgAAAACM6IR9GHiRoVVAO78JJNksy2fKDQNs2jBn8bacsRLcrDucQIQAAAWIAAAAMQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABHkEVdJ+UfDnWpBr/qF582IEoDQ0iW0WPzO9CEUdvvh8AAAAEbWludAAAAAIAAAASAAAAAAAAAADoFl2ACT9HZkbCeuaT9MAIdStpdf58wM3P24nl738AnQAAAAoAAAAAAAAAAAAAAAAAAAAFAAAAAQAAAAAAAAAAAAAAAR5BFXSflHw51qQa/6hefNiBKA0NIltFj8zvQhFHb74fAAAABG1pbnQAAAACAAAAEgAAAAAAAAAA6BZdgAk/R2ZGwnrmk/TACHUraXX+fMDNz9uJ5e9/AJ0AAAAKAAAAAAAAAAAAAAAAAAAABQAAAAAAAAABAAAAAAAAAAIAAAAGAAAAAR5BFXSflHw51qQa/6hefNiBKA0NIltFj8zvQhFHb74fAAAAFAAAAAEAAAAHa35L+/RxV6EuJOVk78H5rCN+eubXBWtsKrRxeLnnpRAAAAABAAAABgAAAAEeQRV0n5R8OdakGv+oXnzYgSgNDSJbRY/M70IRR2++HwAAABAAAAABAAAAAgAAAA8AAAAHQmFsYW5jZQAAAAASAAAAAAAAAADoFl2ACT9HZkbCeuaT9MAIdStpdf58wM3P24nl738AnQAAAAEAYpBIAAAfrAAAAJQAAAAAAAAdYwAAAAA=",
37
+ ),
38
+ };
39
+
40
+ let wal: Wallet;
41
+ let stellar: Stellar;
42
+
43
+ describe("Sep7Base", () => {
44
+ it("constructor accepts a string uri", () => {
45
+ const uriStr =
46
+ "web+stellar:tx?xdr=test&callback=https%3A%2F%2Fexample.com%2Fcallback";
47
+ const uri = new Sep7Tx(uriStr);
48
+ expect(uri.operationType).toBe(Sep7OperationType.tx);
49
+ expect(uri.xdr).toBe("test");
50
+ expect(uri.callback).toBe("https://example.com/callback");
51
+ expect(uri.toString()).toBe(uriStr);
52
+ });
53
+
54
+ it("constructor accepts URL uri", () => {
55
+ const uriStr =
56
+ "web+stellar:tx?xdr=test&callback=https%3A%2F%2Fexample.com%2Fcallback";
57
+ const url = new URL(uriStr);
58
+ const uri = new Sep7Tx(url);
59
+ expect(uri.operationType).toBe(Sep7OperationType.tx);
60
+ expect(uri.xdr).toBe("test");
61
+ expect(uri.callback).toBe("https://example.com/callback");
62
+ expect(uri.toString()).toBe(uriStr);
63
+
64
+ // should not hold a reference to the original URL
65
+ url.searchParams.delete("callback");
66
+ expect(uri.callback).toBe("https://example.com/callback");
67
+ });
68
+
69
+ it("should default to public network if not set", () => {
70
+ const uri = new Sep7Tx("web+stellar:tx");
71
+ expect(uri.networkPassphrase).toBe(Networks.PUBLIC);
72
+
73
+ uri.networkPassphrase = Networks.TESTNET;
74
+ expect(uri.networkPassphrase).toBe(Networks.TESTNET);
75
+ });
76
+
77
+ it("allows setting callback with or without 'url:' prefix", () => {
78
+ const uri = new Sep7Tx("web+stellar:tx");
79
+ expect(uri.operationType).toBe(Sep7OperationType.tx);
80
+ expect(uri.callback).toBe(undefined);
81
+
82
+ // should remove "url:" prefix when getting
83
+ uri.callback = "url:https://example.com/callback";
84
+ expect(uri.callback).toBe("https://example.com/callback");
85
+
86
+ uri.callback = "https://example.com/callback";
87
+ expect(uri.callback).toBe("https://example.com/callback");
88
+
89
+ expect(uri.toString()).toBe(
90
+ "web+stellar:tx?callback=url%3Ahttps%3A%2F%2Fexample.com%2Fcallback",
91
+ );
92
+ });
93
+
94
+ it("get/set msg", () => {
95
+ const uri = new Sep7Tx("web+stellar:tx?msg=test%20message");
96
+
97
+ expect(uri.msg).toBe("test message");
98
+
99
+ uri.msg = "another message";
100
+ expect(uri.msg).toBe("another message");
101
+ });
102
+
103
+ it("msg throws error if longer than 300 chars", () => {
104
+ // Should throw when creating from uri string
105
+ try {
106
+ new Sep7Tx(
107
+ "web+stellar:tx?msg=test%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20message%20test%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20message",
108
+ );
109
+ } catch (error) {
110
+ expect(error).toBeInstanceOf(Sep7LongMsgError);
111
+ }
112
+
113
+ const uri = new Sep7Tx("web+stellar:tx?msg=test%20message");
114
+
115
+ // Should throw when setting 'msg' with existing uri
116
+ try {
117
+ uri.msg =
118
+ "another long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long message";
119
+ } catch (error) {
120
+ expect(error).toBeInstanceOf(Sep7LongMsgError);
121
+ }
122
+ });
123
+
124
+ it("get/set network_passphrase", () => {
125
+ const uri = new Sep7Tx("web+stellar:tx?msg=test%20message");
126
+
127
+ // if not present on the uri it should default to Public network
128
+ expect(uri.networkPassphrase).toBe(Networks.PUBLIC);
129
+
130
+ uri.networkPassphrase = Networks.TESTNET;
131
+ expect(uri.networkPassphrase).toBe(Networks.TESTNET);
132
+ });
133
+
134
+ it("get/set origin_domain", () => {
135
+ const uri = new Sep7Tx(
136
+ "web+stellar:tx?msg=test%20message&origin_domain=someDomain.com",
137
+ );
138
+
139
+ expect(uri.originDomain).toBe("someDomain.com");
140
+
141
+ uri.originDomain = "anotherDomain.com";
142
+ expect(uri.originDomain).toBe("anotherDomain.com");
143
+ });
144
+
145
+ it("addSignature() signs the uri and adds a signature to the end", () => {
146
+ const uriStr =
147
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com";
148
+ const uri = new Sep7Pay(uriStr);
149
+
150
+ uri.addSignature(Keypair.fromSecret(testKp1.secretKey));
151
+
152
+ const expectedSignature =
153
+ "juY2Pi1/IubcbIDds2CbnL+Imr7dbpJYMW1nLAesOmyh5v/uTVvJwI06RgCGBtHh5+5DWOhJUlEfOSGXPtqgAA==";
154
+
155
+ expect(uri.signature).toBe(expectedSignature);
156
+ expect(
157
+ uri
158
+ .toString()
159
+ .endsWith(`&signature=${encodeURIComponent(expectedSignature)}`),
160
+ ).toBe(true);
161
+ });
162
+
163
+ it("verifySignature() returns false when there is no origin_domain and signature", async () => {
164
+ const uriStr = "web+stellar:tx?xdr=test";
165
+ const uri = new Sep7Tx(uriStr);
166
+ expect(await uri.verifySignature()).toBe(false);
167
+ });
168
+
169
+ it("verifySignature() returns false when there is origin domain but no signature", async () => {
170
+ const uriStr = "web+stellar:tx?xdr=test&origin_domain=someDomain.com";
171
+ const uri = new Sep7Tx(uriStr);
172
+ expect(await uri.verifySignature()).toBe(false);
173
+ });
174
+
175
+ it("verifySignature() returns false when there is signature but no origin domain", async () => {
176
+ const uriStr = "web+stellar:tx?xdr=test&signature=sig";
177
+ const uri = new Sep7Tx(uriStr);
178
+ expect(await uri.verifySignature()).toBe(false);
179
+ });
180
+
181
+ it("verifySignature() returns false when the stellar.toml fails to resolve", async () => {
182
+ const uriStr =
183
+ "web+stellar:tx?xdr=test&origin_domain=someDomain.com&signature=sig";
184
+ const uri = new Sep7Tx(uriStr);
185
+
186
+ jest
187
+ .spyOn(StellarToml.Resolver, "resolve")
188
+ .mockRejectedValue(new Error("Not Found"));
189
+
190
+ expect(await uri.verifySignature()).toBe(false);
191
+ });
192
+
193
+ it("verifySignature() returns false when the stellar.toml has no URI_REQUEST_SIGNING_KEY field", async () => {
194
+ const uriStr =
195
+ "web+stellar:tx?xdr=test&origin_domain=someDomain.com&signature=sig";
196
+ const uri = new Sep7Tx(uriStr);
197
+
198
+ jest.spyOn(StellarToml.Resolver, "resolve").mockResolvedValue({});
199
+
200
+ expect(await uri.verifySignature()).toBe(false);
201
+ });
202
+
203
+ it("verifySignature() returns false when the signature is not valid", async () => {
204
+ const uriStr =
205
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com?signature=invalid";
206
+ const uri = new Sep7Pay(uriStr);
207
+
208
+ jest.spyOn(StellarToml.Resolver, "resolve").mockResolvedValue({
209
+ URI_REQUEST_SIGNING_KEY: testKp1.publicKey,
210
+ });
211
+
212
+ expect(await uri.verifySignature()).toBe(false);
213
+ });
214
+
215
+ it("verifySignature() returns true when the signature is valid", async () => {
216
+ const uriStr =
217
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com&signature=juY2Pi1%2FIubcbIDds2CbnL%2BImr7dbpJYMW1nLAesOmyh5v%2FuTVvJwI06RgCGBtHh5%2B5DWOhJUlEfOSGXPtqgAA%3D%3D";
218
+ const uri = new Sep7Pay(uriStr);
219
+
220
+ jest.spyOn(StellarToml.Resolver, "resolve").mockResolvedValue({
221
+ URI_REQUEST_SIGNING_KEY: testKp1.publicKey,
222
+ });
223
+
224
+ expect(await uri.verifySignature()).toBe(true);
225
+ });
226
+ });
227
+
228
+ describe("Sep7Tx", () => {
229
+ beforeAll(async () => {
230
+ wal = Wallet.TestNet();
231
+ stellar = wal.stellar();
232
+
233
+ try {
234
+ await stellar.server.loadAccount(testKp1.publicKey);
235
+ await stellar.server.loadAccount(testKp2.publicKey);
236
+ } catch (e) {
237
+ await stellar.fundTestnetAccount(testKp1.publicKey);
238
+ await stellar.fundTestnetAccount(testKp2.publicKey);
239
+ }
240
+ }, 30000);
241
+
242
+ it("forTransaction sets the tx parameter", async () => {
243
+ const txBuilder = await stellar.transaction({
244
+ sourceAddress: testKp1,
245
+ baseFee: 100,
246
+ timebounds: 0,
247
+ });
248
+ txBuilder.transfer(testKp2.publicKey, new NativeAssetId(), "1");
249
+ const tx = txBuilder.build();
250
+
251
+ const xdr = tx.toEnvelope().toXDR().toString("base64");
252
+
253
+ const uri = Sep7Tx.forTransaction(tx);
254
+ expect(uri.operationType).toBe("tx");
255
+ expect(uri.xdr).toBe(xdr);
256
+ expect(uri.toString()).toBe(
257
+ `web+stellar:tx?xdr=${encodeURIComponent(
258
+ xdr,
259
+ )}&network_passphrase=Test+SDF+Network+%3B+September+2015`,
260
+ );
261
+ });
262
+
263
+ it("constructor accepts a string uri", () => {
264
+ const uriStr =
265
+ "web+stellar:tx?xdr=test&callback=https%3A%2F%2Fexample.com%2Fcallback";
266
+ const uri = new Sep7Tx(uriStr);
267
+ expect(uri.operationType).toBe("tx");
268
+ expect(uri.xdr).toBe("test");
269
+ expect(uri.callback).toBe("https://example.com/callback");
270
+ expect(uri.toString()).toBe(uriStr);
271
+ });
272
+
273
+ it("allows adding xdr after construction", () => {
274
+ const uri = new Sep7Tx();
275
+ uri.xdr = "test";
276
+ expect(uri.xdr).toBe("test");
277
+ expect(uri.toString()).toBe("web+stellar:tx?xdr=test");
278
+ });
279
+
280
+ it("get/set xdr", () => {
281
+ const uri = new Sep7Tx(
282
+ "web+stellar:tx?xdr=testA&pubkey=testPubkey&callback=https%3A%2F%2Fexample.com%2Fcallback",
283
+ );
284
+
285
+ expect(uri.xdr).toBe("testA");
286
+
287
+ uri.xdr = "testB";
288
+ expect(uri.xdr).toBe("testB");
289
+ });
290
+
291
+ it("get/set pubkey", () => {
292
+ const uri = new Sep7Tx(
293
+ "web+stellar:tx?xdr=test&pubkey=testPubkey&callback=https%3A%2F%2Fexample.com%2Fcallback",
294
+ );
295
+
296
+ expect(uri.pubkey).toBe("testPubkey");
297
+
298
+ uri.pubkey = testKp1.publicKey;
299
+ expect(uri.pubkey).toBe(testKp1.publicKey);
300
+ });
301
+
302
+ it("get/set chain", () => {
303
+ const uri = new Sep7Tx(
304
+ "web+stellar:tx?xdr=test&pubkey=testPubkey&callback=https%3A%2F%2Fexample.com%2Fcallback&chain=testChain",
305
+ );
306
+
307
+ expect(uri.chain).toBe("testChain");
308
+
309
+ uri.chain =
310
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com&signature=juY2Pi1%2FIubcbIDds2CbnL%2BImr7dbpJYMW1nLAesOmyh5v%2FuTVvJwI06RgCGBtHh5%2B5DWOhJUlEfOSGXPtqgAA%3D%3D";
311
+ expect(uri.chain).toBe(
312
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&msg=pay%20me%20with%20lumens&origin_domain=someDomain.com&signature=juY2Pi1%2FIubcbIDds2CbnL%2BImr7dbpJYMW1nLAesOmyh5v%2FuTVvJwI06RgCGBtHh5%2B5DWOhJUlEfOSGXPtqgAA%3D%3D",
313
+ );
314
+ });
315
+
316
+ it("parses replacements", () => {
317
+ // from doc sample: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0007.md#operation-tx
318
+ const uri = new Sep7Tx(
319
+ "web+stellar:tx?replace=sourceAccount%3AX%2Coperations%5B0%5D.sourceAccount%3AY%2Coperations%5B1%5D.destination%3AY%3BX%3Aaccount%20from%20where%20you%20want%20to%20pay%20fees%2CY%3Aaccount%20that%20needs%20the%20trustline%20and%20which%20will%20receive%20the%20new%20tokens",
320
+ );
321
+
322
+ const replacements = uri.getReplacements();
323
+
324
+ expect(replacements.length).toBe(3);
325
+
326
+ expect(replacements[0].id).toBe("X");
327
+ expect(replacements[0].path).toBe("sourceAccount");
328
+ expect(replacements[0].hint).toBe(
329
+ "account from where you want to pay fees",
330
+ );
331
+
332
+ expect(replacements[1].id).toBe("Y");
333
+ expect(replacements[1].path).toBe("operations[0].sourceAccount");
334
+ expect(replacements[1].hint).toBe(
335
+ "account that needs the trustline and which will receive the new tokens",
336
+ );
337
+
338
+ expect(replacements[2].id).toBe("Y");
339
+ expect(replacements[2].path).toBe("operations[1].destination");
340
+ expect(replacements[2].hint).toBe(
341
+ "account that needs the trustline and which will receive the new tokens",
342
+ );
343
+ });
344
+
345
+ it("addReplacement", () => {
346
+ const uri = new Sep7Tx("web+stellar:tx");
347
+ uri.addReplacement({
348
+ id: "X",
349
+ path: "sourceAccount",
350
+ hint: "account from where you want to pay fees",
351
+ });
352
+
353
+ uri.addReplacement({
354
+ id: "Y",
355
+ path: "operations[0].sourceAccount",
356
+ hint: "account that needs the trustline and which will receive the new tokens",
357
+ });
358
+
359
+ uri.addReplacement({
360
+ id: "Y",
361
+ path: "operations[1].destination",
362
+ hint: "account that needs the trustline and which will receive the new tokens",
363
+ });
364
+
365
+ expect(uri.toString()).toBe(
366
+ "web+stellar:tx?replace=sourceAccount%3AX%2Coperations%5B0%5D.sourceAccount%3AY%2Coperations%5B1%5D.destination%3AY%3BX%3Aaccount+from+where+you+want+to+pay+fees%2CY%3Aaccount+that+needs+the+trustline+and+which+will+receive+the+new+tokens",
367
+ );
368
+ });
369
+
370
+ it("addReplacement with forTransaction", async () => {
371
+ const txBuilder = await stellar.transaction({
372
+ sourceAddress: testKp1,
373
+ baseFee: 100,
374
+ timebounds: 0,
375
+ });
376
+ txBuilder.transfer(testKp2.publicKey, new NativeAssetId(), "1");
377
+ const tx = txBuilder.build();
378
+
379
+ const xdr = tx.toEnvelope().toXDR().toString("base64");
380
+
381
+ const uri = Sep7Tx.forTransaction(tx);
382
+
383
+ uri.addReplacement({
384
+ id: "SRC",
385
+ path: "sourceAccount",
386
+ hint: "source account",
387
+ });
388
+ uri.addReplacement({ id: "SEQ", path: "seqNum", hint: "sequence number" });
389
+ uri.addReplacement({ id: "FEE", path: "fee", hint: "fee" });
390
+
391
+ expect(uri.toString()).toBe(
392
+ `web+stellar:tx?xdr=${encodeURIComponent(
393
+ xdr,
394
+ )}&network_passphrase=Test+SDF+Network+%3B+September+2015&replace=sourceAccount%3ASRC%2CseqNum%3ASEQ%2Cfee%3AFEE%3BSRC%3Asource+account%2CSEQ%3Asequence+number%2CFEE%3Afee`,
395
+ );
396
+ });
397
+
398
+ it("setReplacements", () => {
399
+ const uri = new Sep7Tx("web+stellar:tx");
400
+ uri.setReplacements([
401
+ {
402
+ id: "X",
403
+ path: "sourceAccount",
404
+ hint: "account from where you want to pay fees",
405
+ },
406
+ {
407
+ id: "Y",
408
+ path: "operations[0].sourceAccount",
409
+ hint: "account that needs the trustline and which will receive the new tokens",
410
+ },
411
+ {
412
+ id: "Y",
413
+ path: "operations[1].destination",
414
+ hint: "account that needs the trustline and which will receive the new tokens",
415
+ },
416
+ ]);
417
+
418
+ expect(uri.toString()).toBe(
419
+ "web+stellar:tx?replace=sourceAccount%3AX%2Coperations%5B0%5D.sourceAccount%3AY%2Coperations%5B1%5D.destination%3AY%3BX%3Aaccount+from+where+you+want+to+pay+fees%2CY%3Aaccount+that+needs+the+trustline+and+which+will+receive+the+new+tokens",
420
+ );
421
+ });
422
+
423
+ it("removeReplacement", () => {
424
+ const uri = new Sep7Tx(
425
+ "web+stellar:tx?replace=sourceAccount%3AX%2Coperations%5B0%5D.sourceAccount%3AY%2Coperations%5B1%5D.destination%3AY%3BX%3Aaccount%20from%20where%20you%20want%20to%20pay%20fees%2CY%3Aaccount%20that%20needs%20the%20trustline%20and%20which%20will%20receive%20the%20new%20tokens",
426
+ );
427
+ uri.removeReplacement("Y");
428
+
429
+ expect(uri.getReplacements().length).toBe(1);
430
+ expect(uri.toString()).toBe(
431
+ "web+stellar:tx?replace=sourceAccount%3AX%3BX%3Aaccount+from+where+you+want+to+pay+fees",
432
+ );
433
+ });
434
+
435
+ it("geTransaction", async () => {
436
+ const txBuilder = await stellar.transaction({
437
+ sourceAddress: testKp1,
438
+ baseFee: 100,
439
+ timebounds: 0,
440
+ });
441
+ txBuilder.transfer(testKp2.publicKey, new NativeAssetId(), "1");
442
+ const tx = txBuilder.build();
443
+
444
+ const xdr = tx.toEnvelope().toXDR().toString("base64");
445
+
446
+ const uri = new Sep7Tx(`web+stellar:tx?xdr=${encodeURIComponent(xdr)}`);
447
+
448
+ expect(uri.getTransaction().toEnvelope().toXDR().toString("base64")).toBe(
449
+ xdr,
450
+ );
451
+ });
452
+ });
453
+
454
+ describe("Sep7Pay", () => {
455
+ it("forDestination sets the destination parameter", () => {
456
+ const uri = Sep7Pay.forDestination(testKp2.publicKey);
457
+
458
+ expect(uri.operationType).toBe("pay");
459
+ expect(uri.destination).toBe(testKp2.publicKey);
460
+ expect(uri.toString()).toBe(
461
+ `web+stellar:pay?destination=${testKp2.publicKey}`,
462
+ );
463
+ });
464
+
465
+ it("get/set destination", () => {
466
+ const uri = new Sep7Pay(`web+stellar:pay?destination=${testKp2.publicKey}`);
467
+
468
+ expect(uri.destination).toBe(testKp2.publicKey);
469
+
470
+ uri.destination = "other";
471
+ expect(uri.destination).toBe("other");
472
+ });
473
+
474
+ it("get/set amount", () => {
475
+ const uri = new Sep7Pay(
476
+ `web+stellar:pay?destination=${testKp2.publicKey}&amount=12.3`,
477
+ );
478
+
479
+ expect(uri.amount).toBe("12.3");
480
+
481
+ uri.amount = "4";
482
+ expect(uri.amount).toBe("4");
483
+ });
484
+
485
+ it("get/set assetCode", () => {
486
+ const uri = new Sep7Pay(
487
+ `web+stellar:pay?destination=${testKp2.publicKey}&asset_code=USDC`,
488
+ );
489
+
490
+ expect(uri.assetCode).toBe("USDC");
491
+
492
+ uri.assetCode = "BRLT";
493
+ expect(uri.assetCode).toBe("BRLT");
494
+ });
495
+
496
+ it("get/set assetIssuer", () => {
497
+ const uri = new Sep7Pay(
498
+ `web+stellar:pay?destination=${testKp2.publicKey}&asset_issuer=issuerA`,
499
+ );
500
+
501
+ expect(uri.assetIssuer).toBe("issuerA");
502
+ uri.assetIssuer = "issuerB";
503
+ expect(uri.assetIssuer).toBe("issuerB");
504
+ });
505
+
506
+ it("get/set memo", () => {
507
+ const uri = new Sep7Pay(
508
+ `web+stellar:pay?destination=${testKp2.publicKey}&memo=hello+world`,
509
+ );
510
+
511
+ expect(uri.memo).toBe("hello world");
512
+
513
+ uri.memo = "bye bye world";
514
+ expect(uri.memo).toBe("bye bye world");
515
+ });
516
+
517
+ it("get/set memoType", () => {
518
+ const uri = new Sep7Pay(
519
+ `web+stellar:pay?destination=${testKp2.publicKey}&memo_type=text`,
520
+ );
521
+
522
+ expect(uri.memoType).toBe("text");
523
+
524
+ uri.memoType = "id";
525
+ expect(uri.memoType).toBe("id");
526
+ });
527
+ });
528
+
529
+ describe("sep7Parser", () => {
530
+ it("isValidSep7Uri(uri) returns true when it starts with 'web+stellar:tx?xdr=<valid-url-encoded-xdr-envelope>'", () => {
531
+ expect(
532
+ isValidSep7Uri(
533
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
534
+ ).result,
535
+ ).toBe(true);
536
+
537
+ expect(
538
+ isValidSep7Uri(
539
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline",
540
+ ).result,
541
+ ).toBe(true);
542
+
543
+ expect(
544
+ isValidSep7Uri(
545
+ `web+stellar:tx?xdr=${xdrs.classic}&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
546
+ ).result,
547
+ ).toBe(true);
548
+
549
+ expect(
550
+ isValidSep7Uri(
551
+ `web+stellar:tx?xdr=${xdrs.sorobanTransfer}&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
552
+ ).result,
553
+ ).toBe(true);
554
+
555
+ expect(
556
+ isValidSep7Uri(
557
+ `web+stellar:tx?xdr=${xdrs.sorobanMint}&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
558
+ ).result,
559
+ ).toBe(true);
560
+ });
561
+
562
+ it("isValidSep7Uri(uri) returns true when it starts with 'web+stellar:pay?destination=<valid-stellar-address>'", () => {
563
+ expect(
564
+ isValidSep7Uri(
565
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
566
+ ).result,
567
+ ).toBe(true);
568
+ expect(
569
+ isValidSep7Uri(
570
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
571
+ ).result,
572
+ ).toBe(true);
573
+
574
+ // With Muxed destination
575
+ expect(
576
+ isValidSep7Uri(
577
+ "web+stellar:pay?destination=MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAABUTGI4&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
578
+ ).result,
579
+ ).toBe(true);
580
+
581
+ // With Soroban Contract destination
582
+ expect(
583
+ isValidSep7Uri(
584
+ "web+stellar:pay?destination=CAPECFLUT6KHYOOWUQNP7KC6PTMICKANBURFWRMPZTXUEEKHN67B7UI2&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
585
+ ).result,
586
+ ).toBe(true);
587
+ });
588
+
589
+ it("isValidSep7Uri(uri) returns 'false' with 'reason' when it is not valid in some way", () => {
590
+ const validation1 = isValidSep7Uri(
591
+ "not-a-stellar-uri:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
592
+ );
593
+ expect(validation1.result).toBe(false);
594
+ expect(validation1.reason).toBe("it must start with 'web+stellar:'");
595
+
596
+ const validation2 = isValidSep7Uri(
597
+ "web+steIIar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
598
+ );
599
+ expect(validation2.result).toBe(false);
600
+ expect(validation2.reason).toBe("it must start with 'web+stellar:'");
601
+
602
+ const validation3 = isValidSep7Uri(
603
+ "web-stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
604
+ );
605
+ expect(validation3.result).toBe(false);
606
+ expect(validation3.reason).toBe("it must start with 'web+stellar:'");
607
+
608
+ const validation4 = isValidSep7Uri(
609
+ "web+stellar:send?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
610
+ );
611
+ expect(validation4.result).toBe(false);
612
+ expect(validation4.reason).toBe(
613
+ "operation type 'send' is not currently supported",
614
+ );
615
+
616
+ const validation5 = isValidSep7Uri(
617
+ "web+stellar:pay?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
618
+ );
619
+ expect(validation5.result).toBe(false);
620
+ expect(validation5.reason).toBe(
621
+ "operation type 'pay' must have a 'destination' parameter",
622
+ );
623
+
624
+ const validation6 = isValidSep7Uri(
625
+ "web+stellar:tx?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
626
+ );
627
+ expect(validation6.result).toBe(false);
628
+ expect(validation6.reason).toBe(
629
+ "operation type 'tx' must have a 'xdr' parameter",
630
+ );
631
+
632
+ const validation7 = isValidSep7Uri(
633
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline",
634
+ );
635
+ expect(validation7.result).toBe(false);
636
+ expect(validation7.reason).toBe(
637
+ "the provided 'xdr' parameter is not a valid transaction envelope on the 'Public Global Stellar Network ; September 2015' network",
638
+ );
639
+
640
+ const validation8 = isValidSep7Uri(
641
+ `web+stellar:tx?network_passphrase=${Networks.TESTNET}&xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
642
+ );
643
+ expect(validation8.result).toBe(false);
644
+ expect(validation8.reason).toBe(
645
+ "the provided 'xdr' parameter is not a valid transaction envelope on the 'Test SDF Network ; September 2015' network",
646
+ );
647
+
648
+ const validation9 = isValidSep7Uri(
649
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMST6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
650
+ );
651
+ expect(validation9.result).toBe(false);
652
+ expect(validation9.reason).toBe(
653
+ "the provided 'destination' parameter is not a valid Stellar address",
654
+ );
655
+
656
+ const validation10 = isValidSep7Uri(
657
+ `web+stellar:tx?xdr=${xdrs.classic}&msg=long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20message&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
658
+ );
659
+ expect(validation10.result).toBe(false);
660
+ expect(validation10.reason).toBe(
661
+ "the 'msg' parameter should be no longer than 300 characters",
662
+ );
663
+ });
664
+
665
+ it("parseSep7Uri(uri) parses a valid 'tx' operation uri", () => {
666
+ expect(
667
+ parseSep7Uri(
668
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
669
+ ),
670
+ ).toBeInstanceOf(Sep7Tx);
671
+ expect(
672
+ parseSep7Uri(
673
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline",
674
+ ),
675
+ ).toBeInstanceOf(Sep7Tx);
676
+ expect(
677
+ parseSep7Uri(
678
+ `web+stellar:tx?xdr=${xdrs.classic}&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024`,
679
+ ),
680
+ ).toBeInstanceOf(Sep7Tx);
681
+ expect(
682
+ parseSep7Uri(
683
+ `web+stellar:tx?xdr=${xdrs.sorobanMint}&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024`,
684
+ ),
685
+ ).toBeInstanceOf(Sep7Tx);
686
+ expect(
687
+ parseSep7Uri(
688
+ `web+stellar:tx?xdr=${xdrs.sorobanTransfer}&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024`,
689
+ ),
690
+ ).toBeInstanceOf(Sep7Tx);
691
+ });
692
+
693
+ it("parseSep7Uri(uri) parses a valid 'pay' operation uri", () => {
694
+ expect(
695
+ parseSep7Uri(
696
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567&memo=skdjfasf&memo_type=MEMO_TEXT&msg=pay%20me%20with%20lumens",
697
+ ),
698
+ ).toBeInstanceOf(Sep7Pay);
699
+ expect(
700
+ parseSep7Uri(
701
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
702
+ ),
703
+ ).toBeInstanceOf(Sep7Pay);
704
+
705
+ // With Muxed destination
706
+ expect(
707
+ parseSep7Uri(
708
+ "web+stellar:pay?destination=MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAABUTGI4&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
709
+ ),
710
+ ).toBeInstanceOf(Sep7Pay);
711
+
712
+ // With Soroban Contract destination
713
+ expect(
714
+ parseSep7Uri(
715
+ "web+stellar:pay?destination=CAPECFLUT6KHYOOWUQNP7KC6PTMICKANBURFWRMPZTXUEEKHN67B7UI2&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
716
+ ),
717
+ ).toBeInstanceOf(Sep7Pay);
718
+ });
719
+
720
+ it("parseSep7Uri(uri) throws an error when it is not a valid Stellar uri in some way", () => {
721
+ try {
722
+ parseSep7Uri(
723
+ "not-a-stellar-uri:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
724
+ );
725
+ } catch (error) {
726
+ expect(error).toBeInstanceOf(Sep7InvalidUriError);
727
+ expect(error.toString()).toContain(
728
+ "Invalid Stellar Sep-7 URI, reason: it must start with 'web+stellar:'",
729
+ );
730
+ }
731
+
732
+ try {
733
+ parseSep7Uri(
734
+ "web+stellar:send?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiJ8vuQhf6rHWmAAAAZAB8NHAAAAABAAAAAAAAAAAAAAABAAAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fa8f7asdfkjha&pubkey=GAU2ZSYYEYO5S5ZQSMMUENJ2TANY4FPXYGGIMU6GMGKTNVDG5QYFW6JS&msg=order%20number%2024",
735
+ );
736
+ } catch (error) {
737
+ expect(error).toBeInstanceOf(Sep7InvalidUriError);
738
+ expect(error.toString()).toContain(
739
+ "Invalid Stellar Sep-7 URI, reason: operation type 'send' is not currently supported",
740
+ );
741
+ }
742
+
743
+ try {
744
+ parseSep7Uri(
745
+ "web+stellar:tx?xdr=AAAAAP%2Byw%2BZEuNg533pUmwlYxfrq6%2FBoMJqiAAAAAAAAYAAAABSFVHAAAAAABAH0wIyY3BJBS2qHdRPAV80M8hF7NBpxRjXyjuT9kEbH%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FAAAAAAAAAAA%3D&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline",
746
+ );
747
+ } catch (error) {
748
+ expect(error).toBeInstanceOf(Sep7InvalidUriError);
749
+ expect(error.toString()).toContain(
750
+ "Invalid Stellar Sep-7 URI, reason: the provided 'xdr' parameter is not a valid transaction envelope on the 'Public Global Stellar Network ; September 2015' network",
751
+ );
752
+ }
753
+
754
+ try {
755
+ parseSep7Uri(
756
+ "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMST6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.123&asset_code=USD&asset_issuer=GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB&memo=hasysda987fs&memo_type=MEMO_TEXT&callback=url%3Ahttps%3A%2F%2FsomeSigningService.com%2Fhasysda987fs%3Fasset%3DUSD",
757
+ );
758
+ } catch (error) {
759
+ expect(error).toBeInstanceOf(Sep7InvalidUriError);
760
+ expect(error.toString()).toContain(
761
+ "Invalid Stellar Sep-7 URI, reason: the provided 'destination' parameter is not a valid Stellar address",
762
+ );
763
+ }
764
+
765
+ try {
766
+ parseSep7Uri(
767
+ `web+stellar:tx?xdr=${xdrs.classic}&msg=long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20long%20message&replace=sourceAccount%3AX%3BX%3Aaccount%20on%20which%20to%20create%20the%20trustline`,
768
+ );
769
+ } catch (error) {
770
+ expect(error).toBeInstanceOf(Sep7InvalidUriError);
771
+ expect(error.toString()).toContain(
772
+ "Invalid Stellar Sep-7 URI, reason: the 'msg' parameter should be no longer than 300 characters",
773
+ );
774
+ }
775
+ });
776
+
777
+ it("sep7ReplacementsFromString() parses it successfully", () => {
778
+ const str =
779
+ "sourceAccount:X,operations[0].sourceAccount:Y,operations[1].destination:Y;X:account from where you want to pay fees,Y:account that needs the trustline and which will receive the new tokens";
780
+ const replacements = sep7ReplacementsFromString(str);
781
+
782
+ expect(replacements[0].id).toBe("X");
783
+ expect(replacements[0].path).toBe("sourceAccount");
784
+ expect(replacements[0].hint).toBe(
785
+ "account from where you want to pay fees",
786
+ );
787
+
788
+ expect(replacements[1].id).toBe("Y");
789
+ expect(replacements[1].path).toBe("operations[0].sourceAccount");
790
+ expect(replacements[1].hint).toBe(
791
+ "account that needs the trustline and which will receive the new tokens",
792
+ );
793
+
794
+ expect(replacements[2].id).toBe("Y");
795
+ expect(replacements[2].path).toBe("operations[1].destination");
796
+ expect(replacements[2].hint).toBe(
797
+ "account that needs the trustline and which will receive the new tokens",
798
+ );
799
+ });
800
+
801
+ it("sep7ReplacementsToString outputs the right string", () => {
802
+ const expected =
803
+ "sourceAccount:X,operations[0].sourceAccount:Y,operations[1].destination:Y;X:account from where you want to pay fees,Y:account that needs the trustline and which will receive the new tokens";
804
+ const replacements = [
805
+ {
806
+ id: "X",
807
+ path: "sourceAccount",
808
+ hint: "account from where you want to pay fees",
809
+ },
810
+ {
811
+ id: "Y",
812
+ path: "operations[0].sourceAccount",
813
+ hint: "account that needs the trustline and which will receive the new tokens",
814
+ },
815
+ {
816
+ id: "Y",
817
+ path: "operations[1].destination",
818
+ hint: "account that needs the trustline and which will receive the new tokens",
819
+ },
820
+ ];
821
+
822
+ const actual = sep7ReplacementsToString(replacements);
823
+ expect(actual).toBe(expected);
824
+ });
825
+ });