@stellar/typescript-wallet-sdk 1.0.0-beta.0 → 1.0.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/.husky/pre-commit +4 -0
  2. package/docs/WalletGuide.md +323 -0
  3. package/lib/bundle.js +28367 -3664
  4. package/lib/bundle.js.map +1 -1
  5. package/lib/index.d.ts +4 -4
  6. package/lib/walletSdk/Exceptions/index.d.ts +19 -0
  7. package/lib/walletSdk/Types/auth.d.ts +7 -6
  8. package/lib/walletSdk/Types/horizon.d.ts +8 -0
  9. package/lib/walletSdk/Types/index.d.ts +2 -4
  10. package/lib/walletSdk/Types/{interactive.d.ts → sep24.d.ts} +9 -6
  11. package/lib/walletSdk/Watcher/index.d.ts +17 -17
  12. package/lib/walletSdk/anchor/Sep24.d.ts +48 -0
  13. package/lib/walletSdk/anchor/index.d.ts +6 -54
  14. package/lib/walletSdk/auth/WalletSigner.d.ts +2 -2
  15. package/lib/walletSdk/auth/index.d.ts +3 -3
  16. package/lib/walletSdk/horizon/Account.d.ts +1 -2
  17. package/lib/walletSdk/horizon/Stellar.d.ts +6 -0
  18. package/lib/walletSdk/horizon/transaction/TransactionBuilder.d.ts +12 -0
  19. package/lib/walletSdk/index.d.ts +9 -8
  20. package/lib/walletSdk/interactive/index.d.ts +20 -9
  21. package/package.json +7 -1
  22. package/prettier.config.js +1 -0
  23. package/src/index.ts +12 -12
  24. package/src/walletSdk/Anchor/Sep24.ts +267 -0
  25. package/src/walletSdk/Anchor/index.ts +19 -213
  26. package/src/walletSdk/Auth/WalletSigner.ts +13 -11
  27. package/src/walletSdk/Auth/index.ts +42 -24
  28. package/src/walletSdk/Exceptions/index.ts +81 -29
  29. package/src/walletSdk/Horizon/Account.ts +4 -4
  30. package/src/walletSdk/Horizon/Stellar.ts +62 -1
  31. package/src/walletSdk/Horizon/index.ts +1 -1
  32. package/src/walletSdk/Horizon/transaction/TransactionBuilder.ts +65 -0
  33. package/src/walletSdk/Recovery/index.ts +1 -6
  34. package/src/walletSdk/Types/anchor.ts +14 -14
  35. package/src/walletSdk/Types/auth.ts +12 -11
  36. package/src/walletSdk/Types/horizon.ts +11 -1
  37. package/src/walletSdk/Types/index.ts +8 -9
  38. package/src/walletSdk/Types/{interactive.ts → sep24.ts} +15 -10
  39. package/src/walletSdk/Types/utils.ts +1 -1
  40. package/src/walletSdk/Types/watcher.ts +2 -2
  41. package/src/walletSdk/Utils/camelToSnakeCase.ts +11 -8
  42. package/src/walletSdk/Utils/index.ts +1 -1
  43. package/src/walletSdk/Watcher/index.ts +94 -97
  44. package/src/walletSdk/index.ts +40 -55
  45. package/test/account.test.ts +10 -3
  46. package/test/fixtures/TransactionsResponse.ts +144 -127
  47. package/test/stellar.test.ts +65 -0
  48. package/test/wallet.test.ts +155 -170
  49. package/tsconfig.json +3 -7
  50. package/webpack.config.js +2 -0
  51. package/lib/walletSdk/anchor/Types.d.ts +0 -75
  52. package/lib/walletSdk/util/sleep.d.ts +0 -1
  53. package/src/walletSdk/Interactive/index.ts +0 -126
@@ -0,0 +1,267 @@
1
+ import { AxiosInstance } from "axios";
2
+ import queryString from "query-string";
3
+
4
+ import { Anchor } from "../Anchor";
5
+ import {
6
+ AssetNotSupportedError,
7
+ ServerRequestFailedError,
8
+ MissingTransactionIdError,
9
+ InvalidTransactionResponseError,
10
+ InvalidTransactionsResponseError,
11
+ } from "../Exceptions";
12
+ import {
13
+ FLOW_TYPE,
14
+ Sep24PostParams,
15
+ Sep24PostResponse,
16
+ AnchorTransaction,
17
+ GetTransactionParams,
18
+ GetTransactionsParams,
19
+ TransactionStatus,
20
+ AnchorServiceInfo,
21
+ } from "../Types";
22
+ import { Watcher } from "../Watcher";
23
+ import { camelToSnakeCaseObject } from "../Utils";
24
+
25
+ // Let's prevent exporting this constructor type as
26
+ // we should not create this Sep24 class directly.
27
+ type Sep24Params = {
28
+ anchor: Anchor;
29
+ httpClient: AxiosInstance;
30
+ };
31
+
32
+ // Do not create this object directly, use the Wallet class.
33
+ export class Sep24 {
34
+ private anchor: Anchor;
35
+ private httpClient: AxiosInstance;
36
+
37
+ constructor(params: Sep24Params) {
38
+ const { anchor, httpClient } = params;
39
+
40
+ this.anchor = anchor;
41
+ this.httpClient = httpClient;
42
+ }
43
+
44
+ async deposit({
45
+ assetCode,
46
+ authToken,
47
+ lang,
48
+ extraFields,
49
+ destinationMemo,
50
+ destinationAccount,
51
+ }: Sep24PostParams): Promise<Sep24PostResponse> {
52
+ return this.flow({
53
+ assetCode,
54
+ authToken,
55
+ lang,
56
+ extraFields,
57
+ destinationMemo,
58
+ account: destinationAccount,
59
+ type: FLOW_TYPE.DEPOSIT,
60
+ });
61
+ }
62
+
63
+ async withdraw({
64
+ assetCode,
65
+ authToken,
66
+ lang,
67
+ extraFields,
68
+ withdrawalAccount,
69
+ }: Sep24PostParams): Promise<Sep24PostResponse> {
70
+ return this.flow({
71
+ assetCode,
72
+ authToken,
73
+ lang,
74
+ extraFields,
75
+ account: withdrawalAccount,
76
+ type: FLOW_TYPE.WITHDRAW,
77
+ });
78
+ }
79
+
80
+ private async flow(
81
+ params: Sep24PostParams & { type: FLOW_TYPE },
82
+ ): Promise<Sep24PostResponse> {
83
+ const {
84
+ assetCode,
85
+ authToken,
86
+ lang = this.anchor.language,
87
+ extraFields,
88
+ destinationMemo,
89
+ account,
90
+ type,
91
+ } = params;
92
+
93
+ const toml = await this.anchor.sep1();
94
+ const transferServerEndpoint = toml.transferServerSep24;
95
+
96
+ const serviceInfo = await this.anchor.getServicesInfo();
97
+
98
+ let assets: string[];
99
+ if (type === FLOW_TYPE.DEPOSIT) {
100
+ assets = Object.keys(serviceInfo.deposit);
101
+ } else {
102
+ assets = Object.keys(serviceInfo.withdraw);
103
+ }
104
+ if (!assets.includes(assetCode)) {
105
+ throw new AssetNotSupportedError(type, assetCode);
106
+ }
107
+ let memoMap = {};
108
+ if (destinationMemo) {
109
+ memoMap["memo_type"] = destinationMemo.type;
110
+ memoMap["memo"] = destinationMemo.value;
111
+ }
112
+
113
+ try {
114
+ const resp = await this.httpClient.post(
115
+ `${transferServerEndpoint}/transactions/${type}/interactive`,
116
+ {
117
+ asset_code: assetCode,
118
+ lang,
119
+ account,
120
+ ...memoMap,
121
+ ...extraFields,
122
+ },
123
+ {
124
+ headers: {
125
+ "Content-Type": "application/json",
126
+ Authorization: `Bearer ${authToken}`,
127
+ },
128
+ },
129
+ );
130
+
131
+ const interactiveResponse: Sep24PostResponse = resp.data;
132
+
133
+ return interactiveResponse;
134
+ } catch (e) {
135
+ throw new ServerRequestFailedError(e);
136
+ }
137
+ }
138
+
139
+ async getServicesInfo(): Promise<AnchorServiceInfo> {
140
+ return this.anchor.getServicesInfo();
141
+ }
142
+
143
+ watcher(): Watcher {
144
+ return new Watcher(this.anchor);
145
+ }
146
+
147
+ /**
148
+ * Get single transaction's current status and details. One of the [id], [stellarTransactionId],
149
+ * [externalTransactionId] must be provided.
150
+ *
151
+ * @param authToken auth token of the account authenticated with the anchor
152
+ * @param id transaction ID
153
+ * @param stellarTransactionId stellar transaction ID
154
+ * @param externalTransactionId external transaction ID
155
+ * @return transaction object
156
+ * @throws [MissingTransactionIdError] if none of the id params is provided
157
+ * @throws [InvalidTransactionResponseError] if Anchor returns an invalid transaction
158
+ * @throws [ServerRequestFailedError] if server request fails
159
+ */
160
+ async getTransactionBy({
161
+ authToken,
162
+ id,
163
+ stellarTransactionId,
164
+ externalTransactionId,
165
+ lang = this.anchor.language,
166
+ }: GetTransactionParams): Promise<AnchorTransaction> {
167
+ if (!id && !stellarTransactionId && !externalTransactionId) {
168
+ throw new MissingTransactionIdError();
169
+ }
170
+
171
+ const toml = await this.anchor.sep1();
172
+ const transferServerEndpoint = toml.transferServerSep24;
173
+
174
+ let qs: { [name: string]: string } = {};
175
+
176
+ if (id) {
177
+ qs = { id };
178
+ } else if (stellarTransactionId) {
179
+ qs = { stellar_transaction_id: stellarTransactionId };
180
+ } else if (externalTransactionId) {
181
+ qs = { external_transaction_id: externalTransactionId };
182
+ }
183
+
184
+ qs = { lang, ...qs };
185
+
186
+ try {
187
+ const resp = await this.httpClient.get(
188
+ `${transferServerEndpoint}/transaction?${queryString.stringify(qs)}`,
189
+ {
190
+ headers: {
191
+ Authorization: `Bearer ${authToken}`,
192
+ },
193
+ },
194
+ );
195
+
196
+ const transaction: AnchorTransaction = resp.data.transaction;
197
+
198
+ if (!transaction || Object.keys(transaction).length === 0) {
199
+ throw new InvalidTransactionResponseError(transaction);
200
+ }
201
+
202
+ return transaction;
203
+ } catch (e) {
204
+ throw new ServerRequestFailedError(e);
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Get account's transactions specified by asset and other params.
210
+ *
211
+ * @param authToken auth token of the account authenticated with the anchor
212
+ * @param assetCode target asset to query for
213
+ * @param noOlderThan response should contain transactions starting on or after this date & time
214
+ * @param limit response should contain at most 'limit' transactions
215
+ * @param kind kind of transaction that is desired. E.g.: 'deposit', 'withdrawal'
216
+ * @param pagingId response should contain transactions starting prior to this ID (exclusive)
217
+ * @param lang desired language (localization), it can also accept locale in the format 'en-US'
218
+ * @return list of transactions as requested by the client, sorted in time-descending order
219
+ * @throws [InvalidTransactionsResponseError] if Anchor returns an invalid response
220
+ * @throws [ServerRequestFailedError] if server request fails
221
+ */
222
+ async getTransactionsForAsset({
223
+ authToken,
224
+ assetCode,
225
+ noOlderThan,
226
+ limit,
227
+ kind,
228
+ pagingId,
229
+ lang = this.anchor.language,
230
+ }: GetTransactionsParams): Promise<AnchorTransaction[]> {
231
+ const toml = await this.anchor.sep1();
232
+ const transferServerEndpoint = toml.transferServerSep24;
233
+
234
+ // Let's convert all params to snake case for the API call
235
+ const apiParams = camelToSnakeCaseObject({
236
+ assetCode,
237
+ noOlderThan,
238
+ limit,
239
+ kind,
240
+ pagingId,
241
+ lang,
242
+ });
243
+
244
+ try {
245
+ const resp = await this.httpClient.get(
246
+ `${transferServerEndpoint}/transactions?${queryString.stringify(
247
+ apiParams,
248
+ )}`,
249
+ {
250
+ headers: {
251
+ Authorization: `Bearer ${authToken}`,
252
+ },
253
+ },
254
+ );
255
+
256
+ const transactions: AnchorTransaction[] = resp.data.transactions;
257
+
258
+ if (!transactions || !Array.isArray(transactions)) {
259
+ throw new InvalidTransactionsResponseError(transactions);
260
+ }
261
+
262
+ return transactions;
263
+ } catch (e) {
264
+ throw new ServerRequestFailedError(e);
265
+ }
266
+ }
267
+ }
@@ -1,27 +1,12 @@
1
1
  import { AxiosInstance } from "axios";
2
- import queryString from "query-string";
3
2
  import { StellarTomlResolver } from "stellar-sdk";
4
3
 
5
4
  import { Config } from "walletSdk";
6
- import { Auth } from "../Auth";
7
- import {
8
- MissingTransactionIdError,
9
- ServerRequestFailedError,
10
- InvalidTransactionResponseError,
11
- InvalidTransactionsResponseError,
12
- AssetNotSupportedError,
13
- } from "../Exceptions";
14
- import { Interactive } from "../Interactive";
15
- import {
16
- AnchorServiceInfo,
17
- AnchorTransaction,
18
- GetTransactionParams,
19
- GetTransactionsParams,
20
- TomlInfo,
21
- TransactionStatus
22
- } from "../Types";
23
- import { Watcher } from "../Watcher";
24
- import { camelToSnakeCaseObject, parseToml } from "../Utils";
5
+ import { Sep10 } from "../Auth";
6
+ import { ServerRequestFailedError } from "../Exceptions";
7
+ import { Sep24 } from "./Sep24";
8
+ import { AnchorServiceInfo, TomlInfo } from "../Types";
9
+ import { parseToml } from "../Utils";
25
10
 
26
11
  // Let's prevent exporting this constructor type as
27
12
  // we should not create this Anchor class directly.
@@ -42,12 +27,7 @@ export class Anchor {
42
27
  private toml: TomlInfo;
43
28
 
44
29
  constructor(params: AnchorParams) {
45
- const {
46
- cfg,
47
- homeDomain,
48
- httpClient,
49
- language,
50
- } = params;
30
+ const { cfg, homeDomain, httpClient, language } = params;
51
31
 
52
32
  this.cfg = cfg;
53
33
  this.homeDomain = homeDomain;
@@ -55,7 +35,7 @@ export class Anchor {
55
35
  this.language = language;
56
36
  }
57
37
 
58
- async getInfo(shouldRefresh?: boolean): Promise<TomlInfo> {
38
+ async sep1(shouldRefresh?: boolean): Promise<TomlInfo> {
59
39
  // return cached TOML values by default
60
40
  if (this.toml && !shouldRefresh) {
61
41
  return this.toml;
@@ -68,26 +48,24 @@ export class Anchor {
68
48
  return parsedToml;
69
49
  }
70
50
 
71
- async auth(): Promise<Auth> {
72
- const tomlInfo = await this.getInfo();
73
- return new Auth({
51
+ async sep10(): Promise<Sep10> {
52
+ const tomlInfo = await this.sep1();
53
+ return new Sep10({
74
54
  cfg: this.cfg,
75
55
  webAuthEndpoint: tomlInfo.webAuthEndpoint,
76
56
  homeDomain: this.homeDomain,
77
- httpClient: this.httpClient
57
+ httpClient: this.httpClient,
78
58
  });
79
59
  }
80
60
 
81
- interactive(): Interactive {
82
- return new Interactive({ anchor: this, httpClient: this.httpClient});
61
+ sep24(): Sep24 {
62
+ return new Sep24({ anchor: this, httpClient: this.httpClient });
83
63
  }
84
64
 
85
- watcher(): Watcher {
86
- return new Watcher(this);
87
- }
88
-
89
- async getServicesInfo(lang: string = this.language): Promise<AnchorServiceInfo> {
90
- const toml = await this.getInfo();
65
+ async getServicesInfo(
66
+ lang: string = this.language,
67
+ ): Promise<AnchorServiceInfo> {
68
+ const toml = await this.sep1();
91
69
  const transferServerEndpoint = toml.transferServerSep24;
92
70
 
93
71
  try {
@@ -97,186 +75,14 @@ export class Anchor {
97
75
  headers: {
98
76
  "Content-Type": "application/json",
99
77
  },
100
- }
78
+ },
101
79
  );
102
80
 
103
81
  const servicesInfo: AnchorServiceInfo = resp.data;
104
-
105
- return servicesInfo;
106
- } catch (e) {
107
- throw new ServerRequestFailedError(e);
108
- }
109
- }
110
-
111
- /**
112
- * Get single transaction's current status and details. One of the [id], [stellarTransactionId],
113
- * [externalTransactionId] must be provided.
114
- *
115
- * @param authToken auth token of the account authenticated with the anchor
116
- * @param id transaction ID
117
- * @param stellarTransactionId stellar transaction ID
118
- * @param externalTransactionId external transaction ID
119
- * @return transaction object
120
- * @throws [MissingTransactionIdError] if none of the id params is provided
121
- * @throws [InvalidTransactionResponseError] if Anchor returns an invalid transaction
122
- * @throws [ServerRequestFailedError] if server request fails
123
- */
124
- async getTransactionBy({
125
- authToken,
126
- id,
127
- stellarTransactionId,
128
- externalTransactionId,
129
- lang = this.language,
130
- }: GetTransactionParams): Promise<AnchorTransaction> {
131
-
132
- if (!id && !stellarTransactionId && !externalTransactionId) {
133
- throw new MissingTransactionIdError();
134
- }
135
-
136
- const toml = await this.getInfo();
137
- const transferServerEndpoint = toml.transferServerSep24;
138
-
139
- let qs: { [name: string]: string } = {};
140
82
 
141
- if (id) {
142
- qs = { id };
143
- } else if (stellarTransactionId) {
144
- qs = { stellar_transaction_id: stellarTransactionId };
145
- } else if (externalTransactionId) {
146
- qs = { external_transaction_id: externalTransactionId };
147
- }
148
-
149
- qs = { lang, ...qs };
150
-
151
- try {
152
- const resp = await this.httpClient.get(
153
- `${transferServerEndpoint}/transaction?${queryString.stringify(qs)}`,
154
- {
155
- headers: {
156
- Authorization: `Bearer ${authToken}`,
157
- },
158
- }
159
- );
160
-
161
- const transaction: AnchorTransaction = resp.data.transaction;
162
-
163
- if (!transaction || Object.keys(transaction).length === 0) {
164
- throw new InvalidTransactionResponseError(transaction);
165
- }
166
-
167
- return transaction;
168
- } catch (e) {
169
- throw new ServerRequestFailedError(e);
170
- }
171
- }
172
-
173
- /**
174
- * Get account's transactions specified by asset and other params.
175
- *
176
- * @param authToken auth token of the account authenticated with the anchor
177
- * @param assetCode target asset to query for
178
- * @param noOlderThan response should contain transactions starting on or after this date & time
179
- * @param limit response should contain at most 'limit' transactions
180
- * @param kind kind of transaction that is desired. E.g.: 'deposit', 'withdrawal'
181
- * @param pagingId response should contain transactions starting prior to this ID (exclusive)
182
- * @param lang desired language (localization), it can also accept locale in the format 'en-US'
183
- * @return list of transactions as requested by the client, sorted in time-descending order
184
- * @throws [InvalidTransactionsResponseError] if Anchor returns an invalid response
185
- * @throws [ServerRequestFailedError] if server request fails
186
- */
187
- async getTransactionsForAsset({
188
- authToken,
189
- assetCode,
190
- noOlderThan,
191
- limit,
192
- kind,
193
- pagingId,
194
- lang = this.language,
195
- }: GetTransactionsParams): Promise<AnchorTransaction[]> {
196
- const toml = await this.getInfo();
197
- const transferServerEndpoint = toml.transferServerSep24;
198
-
199
- // Let's convert all params to snake case for the API call
200
- const apiParams = camelToSnakeCaseObject({
201
- assetCode,
202
- noOlderThan,
203
- limit,
204
- kind,
205
- pagingId,
206
- lang,
207
- });
208
-
209
- try {
210
- const resp = await this.httpClient.get(
211
- `${transferServerEndpoint}/transactions?${queryString.stringify(
212
- apiParams
213
- )}`,
214
- {
215
- headers: {
216
- Authorization: `Bearer ${authToken}`,
217
- },
218
- }
219
- );
220
-
221
- const transactions: AnchorTransaction[] = resp.data.transactions;
222
-
223
- if (!transactions || !Array.isArray(transactions)) {
224
- throw new InvalidTransactionsResponseError(transactions);
225
- }
226
-
227
- return transactions;
83
+ return servicesInfo;
228
84
  } catch (e) {
229
85
  throw new ServerRequestFailedError(e);
230
86
  }
231
87
  }
232
-
233
- /**
234
- * Get all successfully finished (either completed or refunded) account transactions for specified
235
- * asset. Optional field implementation depends on anchor.
236
- *
237
- * @param authToken auth token of the account authenticated with the anchor
238
- * @param assetCode target asset to query for
239
- * @param noOlderThan response should contain transactions starting on or after this date & time
240
- * @param limit response should contain at most 'limit' transactions
241
- * @param kind kind of transaction that is desired. E.g.: 'deposit', 'withdrawal'
242
- * @param pagingId response should contain transactions starting prior to this ID (exclusive)
243
- * @param lang desired language (localization), it can also accept locale in the format 'en-US'
244
- * @return list of filtered transactions that achieved a final state (completed or refunded)
245
- * @throws [AssetNotSupportedError] if asset is not supported by the anchor
246
- * @throws [InvalidTransactionsResponseError] if Anchor returns an invalid response
247
- * @throws [ServerRequestFailedError] if server request fails
248
- */
249
-
250
- async getHistory({
251
- authToken,
252
- assetCode,
253
- noOlderThan,
254
- limit,
255
- kind,
256
- pagingId,
257
- lang = this.language,
258
- }: GetTransactionsParams): Promise<AnchorTransaction[]> {
259
- const toml = await this.getInfo();
260
- if (!toml.currencies?.find(({ code }) => code === assetCode)) {
261
- throw new AssetNotSupportedError(null, assetCode);
262
- }
263
-
264
- const transactions = await this.getTransactionsForAsset({
265
- authToken,
266
- assetCode,
267
- noOlderThan,
268
- limit,
269
- kind,
270
- pagingId,
271
- lang,
272
- });
273
-
274
- const finishedTransactions = transactions
275
- .filter(({ status }) => [
276
- TransactionStatus.completed,
277
- TransactionStatus.refunded
278
- ].includes(status));
279
-
280
- return finishedTransactions;
281
- }
282
88
  }
@@ -1,28 +1,30 @@
1
1
  import { Transaction } from "stellar-sdk";
2
- import {
3
- SignWithClientAccountParams,
4
- SignWithDomainAccountParams
2
+ import {
3
+ SignWithClientAccountParams,
4
+ SignWithDomainAccountParams,
5
5
  } from "../Types";
6
6
 
7
7
  export interface WalletSigner {
8
- signWithClientAccount({
9
- transaction,
10
- accountKp
8
+ signWithClientAccount({
9
+ transaction,
10
+ accountKp,
11
11
  }: SignWithClientAccountParams): Transaction;
12
12
 
13
13
  signWithDomainAccount({
14
14
  transactionXDR,
15
15
  networkPassphrase,
16
- accountKp
17
- }: SignWithDomainAccountParams): Transaction;
16
+ accountKp,
17
+ }: SignWithDomainAccountParams): Promise<Transaction>;
18
18
  }
19
19
 
20
20
  export const DefaultSigner: WalletSigner = {
21
21
  signWithClientAccount: ({ transaction, accountKp }) => {
22
- transaction.sign(accountKp);
22
+ transaction.sign(accountKp.keypair);
23
23
  return transaction;
24
24
  },
25
- signWithDomainAccount: () => {
26
- throw new Error("The DefaultSigner can't sign transactions with domain account");
25
+ signWithDomainAccount: async () => {
26
+ throw new Error(
27
+ "The DefaultSigner can't sign transactions with domain account",
28
+ );
27
29
  },
28
30
  };