@otoplo/wallet-common 0.2.2 → 0.4.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 (90) hide show
  1. package/dist/index.js +1798 -1986
  2. package/dist/index.js.map +1 -1
  3. package/dist/types/index.d.ts +0 -1
  4. package/dist/types/index.d.ts.map +1 -1
  5. package/dist/types/persistence/index.d.ts +1 -1
  6. package/dist/types/persistence/index.d.ts.map +1 -1
  7. package/dist/types/persistence/{datastore/db.d.ts → repository.d.ts} +8 -5
  8. package/dist/types/persistence/repository.d.ts.map +1 -0
  9. package/dist/types/persistence/wallet-db.d.ts +17 -25
  10. package/dist/types/persistence/wallet-db.d.ts.map +1 -1
  11. package/dist/types/services/asset.d.ts +6 -0
  12. package/dist/types/services/asset.d.ts.map +1 -1
  13. package/dist/types/services/cache.d.ts +0 -2
  14. package/dist/types/services/cache.d.ts.map +1 -1
  15. package/dist/types/services/discovery.d.ts +3 -3
  16. package/dist/types/services/discovery.d.ts.map +1 -1
  17. package/dist/types/services/index.d.ts +1 -0
  18. package/dist/types/services/index.d.ts.map +1 -1
  19. package/dist/types/services/key.d.ts +3 -0
  20. package/dist/types/services/key.d.ts.map +1 -1
  21. package/dist/types/services/market.d.ts +33 -0
  22. package/dist/types/services/market.d.ts.map +1 -0
  23. package/dist/types/services/rostrum.d.ts +5 -3
  24. package/dist/types/services/rostrum.d.ts.map +1 -1
  25. package/dist/types/services/transaction.d.ts.map +1 -1
  26. package/dist/types/services/wallet.d.ts +13 -6
  27. package/dist/types/services/wallet.d.ts.map +1 -1
  28. package/dist/types/types/db.types.d.ts +4 -0
  29. package/dist/types/types/db.types.d.ts.map +1 -1
  30. package/dist/types/utils/asset.d.ts +1 -2
  31. package/dist/types/utils/asset.d.ts.map +1 -1
  32. package/dist/types/utils/market.d.ts +0 -3
  33. package/dist/types/utils/market.d.ts.map +1 -1
  34. package/package.json +13 -17
  35. package/src/index.ts +0 -1
  36. package/src/persistence/index.ts +1 -1
  37. package/src/persistence/{datastore/db.ts → repository.ts} +9 -5
  38. package/src/persistence/wallet-db.ts +95 -91
  39. package/src/services/asset.ts +60 -26
  40. package/src/services/cache.ts +4 -14
  41. package/src/services/discovery.ts +54 -42
  42. package/src/services/index.ts +2 -1
  43. package/src/services/key.ts +8 -2
  44. package/src/services/market.ts +143 -0
  45. package/src/services/rostrum.ts +14 -6
  46. package/src/services/transaction.ts +3 -10
  47. package/src/services/wallet.ts +66 -42
  48. package/src/types/db.types.ts +6 -1
  49. package/src/utils/asset.ts +2 -21
  50. package/src/utils/market.ts +0 -54
  51. package/dist/types/persistence/datastore/db.d.ts.map +0 -1
  52. package/dist/types/persistence/datastore/index.d.ts +0 -3
  53. package/dist/types/persistence/datastore/index.d.ts.map +0 -1
  54. package/dist/types/persistence/datastore/kv.d.ts +0 -34
  55. package/dist/types/persistence/datastore/kv.d.ts.map +0 -1
  56. package/dist/types/state/hooks.d.ts +0 -17
  57. package/dist/types/state/hooks.d.ts.map +0 -1
  58. package/dist/types/state/index.d.ts +0 -4
  59. package/dist/types/state/index.d.ts.map +0 -1
  60. package/dist/types/state/slices/auth.d.ts +0 -17
  61. package/dist/types/state/slices/auth.d.ts.map +0 -1
  62. package/dist/types/state/slices/dapp.d.ts +0 -29
  63. package/dist/types/state/slices/dapp.d.ts.map +0 -1
  64. package/dist/types/state/slices/index.d.ts +0 -8
  65. package/dist/types/state/slices/index.d.ts.map +0 -1
  66. package/dist/types/state/slices/loader.d.ts +0 -15
  67. package/dist/types/state/slices/loader.d.ts.map +0 -1
  68. package/dist/types/state/slices/market.d.ts +0 -54
  69. package/dist/types/state/slices/market.d.ts.map +0 -1
  70. package/dist/types/state/slices/notifications.d.ts +0 -142
  71. package/dist/types/state/slices/notifications.d.ts.map +0 -1
  72. package/dist/types/state/slices/status.d.ts +0 -35
  73. package/dist/types/state/slices/status.d.ts.map +0 -1
  74. package/dist/types/state/slices/wallet.d.ts +0 -833
  75. package/dist/types/state/slices/wallet.d.ts.map +0 -1
  76. package/dist/types/state/store.d.ts +0 -26
  77. package/dist/types/state/store.d.ts.map +0 -1
  78. package/src/persistence/datastore/index.ts +0 -2
  79. package/src/persistence/datastore/kv.ts +0 -129
  80. package/src/state/hooks.ts +0 -47
  81. package/src/state/index.ts +0 -3
  82. package/src/state/slices/auth.ts +0 -28
  83. package/src/state/slices/dapp.ts +0 -32
  84. package/src/state/slices/index.ts +0 -7
  85. package/src/state/slices/loader.ts +0 -31
  86. package/src/state/slices/market.ts +0 -47
  87. package/src/state/slices/notifications.ts +0 -44
  88. package/src/state/slices/status.ts +0 -41
  89. package/src/state/slices/wallet.ts +0 -107
  90. package/src/state/store.ts +0 -27
@@ -1,69 +1,65 @@
1
- import type { DBStore } from "./datastore/db";
1
+ import type { Repository } from "./repository";
2
2
  import { AccountType } from "../utils/enums";
3
- import type { AccountDTO, AccountEntity, AddressDTO, AddressEntity, AssetEntity, AssetTransactionEntity, NftEntity, SessionEntity, TokenEntity, TransactionEntity, VaultDTO, VaultEntity } from "../types/db.types";
3
+ import type { AccountDTO, AccountEntity, AddressDTO, AddressEntity, AssetEntity, AssetTransactionEntity, NftEntity, SessionEntity, TokenEntity, TransactionDTO, TransactionEntity, VaultDTO, VaultEntity } from "../types/db.types";
4
4
  import type { AssetType } from "../types/wallet.types";
5
5
  import { currentTimestamp } from "../utils/common";
6
6
 
7
- export type DBEvent =
8
- | { type: 'tx_refresh'; }
9
- | { type: 'nft_refresh'; }
10
- | { type: 'token_refresh'; }
11
-
12
- export type DBUpdateCallback = (event: DBEvent) => void;
13
-
14
7
  export class WalletDB {
15
8
 
16
- private readonly store: DBStore;
17
- private updateCallback?: DBUpdateCallback;
18
-
19
- constructor(store: DBStore) {
20
- this.store = store;
21
- }
22
-
23
- public onUpdate(callback: DBUpdateCallback): void {
24
- this.updateCallback = callback;
25
- }
9
+ private readonly repository: Repository;
26
10
 
27
- private notify(event: DBEvent): void {
28
- this.updateCallback?.(event);
11
+ constructor(repository: Repository) {
12
+ this.repository = repository;
29
13
  }
30
14
 
31
- public async initSchema(): Promise<boolean> {
32
- return this.store.initSchema();
15
+ public initSchema(): Promise<boolean> {
16
+ return this.repository.initSchema();
33
17
  }
34
18
 
35
- public async clearData(): Promise<void> {
36
- return this.store.clearData();
19
+ public clearData(): Promise<void> {
20
+ return this.repository.clearData();
37
21
  }
38
22
 
39
- public async addLocalTransaction(tx: TransactionEntity): Promise<void> {
40
- try {
41
- await this.store.upsertTransaction(tx);
42
- this.notify({ type: 'tx_refresh' });
43
- } catch (error) {
44
- console.error(error);
45
- }
23
+ public upsertTransaction(tx: TransactionDTO): Promise<void> {
24
+ const txEntity: TransactionEntity = {
25
+ ...tx,
26
+ othersOutputs: JSON.stringify(tx.othersOutputs),
27
+ myOutputs: JSON.stringify(tx.myOutputs),
28
+ myInputs: JSON.stringify(tx.myInputs)
29
+ };
30
+ return this.repository.upsertTransaction(txEntity);
46
31
  }
47
32
 
48
- public async addAssetTransaction(assetTx: AssetTransactionEntity): Promise<void> {
49
- return this.store.upsertAssetTransaction(assetTx);
33
+ public upsertAssetTransaction(assetTx: AssetTransactionEntity): Promise<void> {
34
+ return this.repository.upsertAssetTransaction(assetTx);
50
35
  }
51
36
 
52
- public async getLocalTransactions(account: number, tokenId?: string): Promise<TransactionEntity[]> {
53
- return this.store.getTransactions(account, tokenId);
37
+ public async getTransactions(account: number, tokenId?: string): Promise<TransactionEntity[]> {
38
+ const txs = await this.repository.getTransactions(account, tokenId);
39
+ return txs.map(tx => ({
40
+ ...tx,
41
+ othersOutputs: JSON.parse(tx.othersOutputs),
42
+ myOutputs: JSON.parse(tx.myOutputs),
43
+ myInputs: JSON.parse(tx.myInputs)
44
+ }));
54
45
  }
55
46
 
56
- public async getPageLocalTransactions(account: number, pageNum: number, pageSize: number, tokenId?: string): Promise<TransactionEntity[]> {
57
- return this.store.getPageTransactions(account, pageNum, pageSize, tokenId);
47
+ public async getPageTransactions(account: number, pageNum: number, pageSize: number, tokenId?: string): Promise<TransactionEntity[]> {
48
+ const txs = await this.repository.getPageTransactions(account, pageNum, pageSize, tokenId);
49
+ return txs.map(tx => ({
50
+ ...tx,
51
+ othersOutputs: JSON.parse(tx.othersOutputs),
52
+ myOutputs: JSON.parse(tx.myOutputs),
53
+ myInputs: JSON.parse(tx.myInputs)
54
+ }));
58
55
  }
59
56
 
60
- public async countLocalTransactions(account: number, tokenId?: string): Promise<number> {
61
- return this.store.countTransactions(account, tokenId);
57
+ public countTransactions(account: number, tokenId?: string): Promise<number> {
58
+ return this.repository.countTransactions(account, tokenId);
62
59
  }
63
60
 
64
- public async clearLocalTransactions(account: number): Promise<void> {
65
- await this.store.clearTransactions(account);
66
- this.notify({ type: 'tx_refresh' });
61
+ public clearTransactions(account: number): Promise<void> {
62
+ return this.repository.clearTransactions(account);
67
63
  }
68
64
 
69
65
  public async saveToken(account: number, token: TokenEntity): Promise<void> {
@@ -73,26 +69,24 @@ export class WalletDB {
73
69
  type: "token",
74
70
  addedTime: currentTimestamp()
75
71
  }
76
- await this.store.upsertToken(token);
72
+ await this.repository.upsertToken(token);
77
73
  await this.saveAsset(asset);
78
- this.notify({ type: 'token_refresh' });
79
74
  }
80
75
 
81
- public async getLocalTokens(account: number, pageNum: number, pageSize: number): Promise<TokenEntity[]> {
82
- return this.store.getTokens(account, pageNum, pageSize);
76
+ public getTokens(account: number, pageNum: number, pageSize: number): Promise<TokenEntity[]> {
77
+ return this.repository.getTokens(account, pageNum, pageSize);
83
78
  }
84
79
 
85
- public async getToken(id: string): Promise<TokenEntity | undefined> {
86
- return this.store.getToken(id);
80
+ public getToken(id: string): Promise<TokenEntity | undefined> {
81
+ return this.repository.getToken(id);
87
82
  }
88
83
 
89
84
  public async deleteToken(account: number, tokenId: string): Promise<void> {
90
85
  await this.removeAsset(account, tokenId);
91
- const count = await this.store.countAssetsById(tokenId);
86
+ const count = await this.repository.countAssetsById(tokenId);
92
87
  if (count == 0) {
93
- await this.store.deleteToken(tokenId);
88
+ await this.repository.deleteToken(tokenId);
94
89
  }
95
- this.notify({ type: 'token_refresh' });
96
90
  }
97
91
 
98
92
  public async saveNft(account: number, nft: NftEntity, time: number): Promise<void> {
@@ -102,45 +96,43 @@ export class WalletDB {
102
96
  type: "nft",
103
97
  addedTime: time
104
98
  }
105
- await this.store.upsertNft(nft);
99
+ await this.repository.upsertNft(nft);
106
100
  await this.saveAsset(asset);
107
- this.notify({ type: 'nft_refresh' });
108
101
  }
109
102
 
110
- public async getLocalNfts(account: number, pageNum: number, pageSize: number): Promise<NftEntity[]> {
111
- return this.store.getNfts(account, pageNum, pageSize);
103
+ public getNfts(account: number, pageNum: number, pageSize: number): Promise<NftEntity[]> {
104
+ return this.repository.getNfts(account, pageNum, pageSize);
112
105
  }
113
106
 
114
- public async getLocalNft(id: string): Promise<NftEntity | undefined> {
115
- return this.store.getNft(id);
107
+ public getNft(id: string): Promise<NftEntity | undefined> {
108
+ return this.repository.getNft(id);
116
109
  }
117
110
 
118
111
  public async deleteNft(account: number, tokenId: string): Promise<void> {
119
112
  await this.removeAsset(account, tokenId);
120
- const count = await this.store.countAssetsById(tokenId);
113
+ const count = await this.repository.countAssetsById(tokenId);
121
114
  if (count == 0) {
122
- await this.store.deleteNft(tokenId);
115
+ await this.repository.deleteNft(tokenId);
123
116
  }
124
- this.notify({ type: 'nft_refresh' });
125
117
  }
126
118
 
127
- public async countLocalNfts(account: number): Promise<number> {
128
- return this.store.countNfts(account);
119
+ public countNfts(account: number): Promise<number> {
120
+ return this.repository.countNfts(account);
129
121
  }
130
122
 
131
- public async getAssets(account: number, type: AssetType): Promise<AssetEntity[]> {
132
- return this.store.getAssets(account, type);
123
+ public getAssets(account: number, type: AssetType): Promise<AssetEntity[]> {
124
+ return this.repository.getAssets(account, type);
133
125
  }
134
126
 
135
- public async saveAsset(asset: AssetEntity): Promise<void> {
136
- await this.store.upsertAsset(asset);
127
+ public saveAsset(asset: AssetEntity): Promise<void> {
128
+ return this.repository.upsertAsset(asset);
137
129
  }
138
130
 
139
- public async removeAsset(account: number, id: string): Promise<void> {
140
- return this.store.deleteAsset(account, id);
131
+ public removeAsset(account: number, id: string): Promise<void> {
132
+ return this.repository.deleteAsset(account, id);
141
133
  }
142
134
 
143
- public async saveAccount(account: AccountDTO): Promise<void> {
135
+ public saveAccount(account: AccountDTO): Promise<void> {
144
136
  const accountEntity: AccountEntity = {
145
137
  id: account.id,
146
138
  address: account.address,
@@ -151,11 +143,11 @@ export class WalletDB {
151
143
  balance: JSON.stringify(account.balance),
152
144
  tokensBalance: JSON.stringify(account.tokensBalance)
153
145
  }
154
- return this.store.upsertAccount(accountEntity);
146
+ return this.repository.upsertAccount(accountEntity);
155
147
  }
156
148
 
157
149
  public async getAccounts(): Promise<AccountDTO[]> {
158
- const accs = await this.store.getAccounts();
150
+ const accs = await this.repository.getAccounts();
159
151
  return accs.map(a => ({
160
152
  ...a,
161
153
  type: AccountType.DAPP,
@@ -164,27 +156,27 @@ export class WalletDB {
164
156
  }));
165
157
  }
166
158
 
167
- public async countAccounts(): Promise<number> {
168
- return this.store.countAccounts();
159
+ public countAccounts(): Promise<number> {
160
+ return this.repository.countAccounts();
169
161
  }
170
162
 
171
- public async updateAccountName(account: number, name: string): Promise<void> {
172
- return this.store.updateAccountName(account, name);
163
+ public updateAccountName(account: number, name: string): Promise<void> {
164
+ return this.repository.updateAccountName(account, name);
173
165
  }
174
166
 
175
- public async saveSession(session: SessionEntity): Promise<void> {
176
- return this.store.upsertSession(session);
167
+ public saveSession(session: SessionEntity): Promise<void> {
168
+ return this.repository.upsertSession(session);
177
169
  }
178
170
 
179
- public async getAccountSessions(accountId: number): Promise<SessionEntity[]> {
180
- return this.store.getSessionsByAccount(accountId);
171
+ public getAccountSessions(accountId: number): Promise<SessionEntity[]> {
172
+ return this.repository.getSessionsByAccount(accountId);
181
173
  }
182
174
 
183
- public async removeSession(sessionId: string): Promise<void> {
184
- return this.store.deleteSession(sessionId);
175
+ public removeSession(sessionId: string): Promise<void> {
176
+ return this.repository.deleteSession(sessionId);
185
177
  }
186
178
 
187
- public async saveAddress(address: AddressDTO): Promise<void> {
179
+ public saveAddress(address: AddressDTO): Promise<void> {
188
180
  const addressEntity: AddressEntity = {
189
181
  address: address.address,
190
182
  idx: address.idx,
@@ -195,11 +187,11 @@ export class WalletDB {
195
187
  balance: JSON.stringify(address.balance),
196
188
  tokensBalance: JSON.stringify(address.tokensBalance)
197
189
  }
198
- return this.store.upsertAddress(addressEntity);
190
+ return this.repository.upsertAddress(addressEntity);
199
191
  }
200
192
 
201
193
  public async getReceiveAddresses(): Promise<AddressDTO[]> {
202
- const addrs = await this.store.getReceiveAddresses();
194
+ const addrs = await this.repository.getReceiveAddresses();
203
195
  return addrs.map(a => ({
204
196
  ...a,
205
197
  type: AccountType.MAIN,
@@ -209,7 +201,7 @@ export class WalletDB {
209
201
  }
210
202
 
211
203
  public async getChangeAddresses(): Promise<AddressDTO[]> {
212
- const addrs = await this.store.getChangeAddresses();
204
+ const addrs = await this.repository.getChangeAddresses();
213
205
  return addrs.map(a => ({
214
206
  ...a,
215
207
  type: AccountType.MAIN,
@@ -218,12 +210,12 @@ export class WalletDB {
218
210
  }));
219
211
  }
220
212
 
221
- public async countAddresses(): Promise<number> {
222
- return this.store.countAddresses();
213
+ public countAddresses(): Promise<number> {
214
+ return this.repository.countAddresses();
223
215
  }
224
216
 
225
217
  public async getVaults(): Promise<VaultDTO[]> {
226
- const vaults = await this.store.getVaults();
218
+ const vaults = await this.repository.getVaults();
227
219
  return vaults.map(v => ({
228
220
  ...v,
229
221
  type: AccountType.VAULT,
@@ -232,7 +224,7 @@ export class WalletDB {
232
224
  }));
233
225
  }
234
226
 
235
- public async saveVault(vault: VaultDTO): Promise<void> {
227
+ public saveVault(vault: VaultDTO): Promise<void> {
236
228
  const vaultEntity: VaultEntity = {
237
229
  address: vault.address,
238
230
  idx: vault.idx,
@@ -242,6 +234,18 @@ export class WalletDB {
242
234
  balance: JSON.stringify(vault.balance),
243
235
  tokensBalance: JSON.stringify(vault.tokensBalance)
244
236
  };
245
- return this.store.upsertVault(vaultEntity);
237
+ return this.repository.upsertVault(vaultEntity);
238
+ }
239
+
240
+ public getSetting(name: string): Promise<string | undefined> {
241
+ return this.repository.getSetting(name);
242
+ }
243
+
244
+ public saveSetting(name: string, value: string): Promise<void> {
245
+ return this.repository.saveSetting(name, value);
246
+ }
247
+
248
+ public removeSetting(name: string): Promise<void> {
249
+ return this.repository.deleteSetting(name);
246
250
  }
247
251
  }
@@ -1,5 +1,5 @@
1
1
  import type { NftEntity, TokenEntity } from "../types/db.types";
2
- import { getAssetMetadata } from "../utils/asset";
2
+ import { getAssetFileUrl, getAssetMetadataUrl } from "../utils/asset";
3
3
  import { currentTimestamp, tokenIdToHex } from "../utils/common";
4
4
  import type { WalletDB } from "../persistence/wallet-db";
5
5
  import type { WalletCache } from "./cache";
@@ -17,42 +17,42 @@ export class AssetService {
17
17
 
18
18
  public async getAssetInfo(assetId: string): Promise<AssetInfo | undefined> {
19
19
  try {
20
- if (this.walletCache.hasToken(assetId)) {
21
- const token = await this.walletCache.getToken(assetId);
20
+ const token = await this.walletCache.getToken(assetId);
21
+ if (token) {
22
22
  return {
23
23
  type: "token",
24
- parent: token!.parent,
25
- token: token!.token,
26
- tokenIdHex: token!.tokenIdHex,
24
+ parent: token.parent,
25
+ token: token.token,
26
+ tokenIdHex: token.tokenIdHex,
27
27
  data: {
28
- name: token!.name,
29
- ticker: token!.ticker,
30
- decimals: token!.decimals,
31
- iconUrl: token!.iconUrl
28
+ name: token.name,
29
+ ticker: token.ticker,
30
+ decimals: token.decimals,
31
+ iconUrl: token.iconUrl
32
32
  }
33
33
  }
34
34
  }
35
35
 
36
- if (this.walletCache.hasNft(assetId)) {
37
- const nft = await this.walletCache.getNft(assetId);
36
+ const nft = await this.walletCache.getNft(assetId);
37
+ if (nft) {
38
38
  return {
39
39
  type: "nft",
40
- parent: nft!.parent,
41
- token: nft!.token,
42
- tokenIdHex: nft!.tokenIdHex,
40
+ parent: nft.parent,
41
+ token: nft.token,
42
+ tokenIdHex: nft.tokenIdHex,
43
43
  data: {
44
- name: nft!.name,
45
- series: nft!.series,
46
- collection: nft!.collection,
47
- author: nft!.author,
48
- public: nft!.public,
49
- front: nft!.front,
50
- back: nft!.back
44
+ name: nft.name,
45
+ series: nft.series,
46
+ collection: nft.collection,
47
+ author: nft.author,
48
+ public: nft.public,
49
+ front: nft.front,
50
+ back: nft.back
51
51
  }
52
52
  }
53
53
  }
54
54
 
55
- return await getAssetMetadata(assetId);
55
+ return await this.getAssetMetadata(assetId);
56
56
  } catch (e) {
57
57
  console.error(e);
58
58
  return undefined;
@@ -68,7 +68,7 @@ export class AssetService {
68
68
  parent: nft.parent,
69
69
  ...nft.data
70
70
  }
71
- await this.walletDb.saveNft(accountId, nftEntity, time);
71
+ await this.saveNft(accountId, nftEntity, time);
72
72
  }
73
73
  }
74
74
 
@@ -84,7 +84,7 @@ export class AssetService {
84
84
  parent: token.parent,
85
85
  ...token.data
86
86
  };
87
- await this.walletDb.saveToken(accountId, tokenEntity);
87
+ await this.saveToken(accountId, tokenEntity);
88
88
  }
89
89
  }
90
90
  }
@@ -115,13 +115,47 @@ export class AssetService {
115
115
  }
116
116
  }
117
117
 
118
+ public async saveToken(accountId: number, token: TokenEntity): Promise<void> {
119
+ await this.walletDb.saveToken(accountId, token);
120
+ }
121
+
118
122
  public async deleteToken(accountId: number, tokenId: string): Promise<void> {
119
123
  await this.walletDb.deleteToken(accountId, tokenId);
120
124
  this.walletCache.removeToken(tokenId);
121
125
  }
122
126
 
127
+ public async saveNft(accountId: number, nft: NftEntity, time: number): Promise<void> {
128
+ await this.walletDb.saveNft(accountId, nft, time);
129
+ }
130
+
123
131
  public async deleteNft(accountId: number, tokenId: string): Promise<void> {
124
132
  await this.walletDb.deleteNft(accountId, tokenId);
125
133
  this.walletCache.removeNft(tokenId);
126
134
  }
127
- }
135
+
136
+ public getAssetFile(token: string, asset: string): Promise<Uint8Array> {
137
+ return this.performGet(getAssetFileUrl(token, asset), 'raw');
138
+ }
139
+
140
+ private getAssetMetadata(token: string): Promise<AssetInfo> {
141
+ return this.performGet(getAssetMetadataUrl(token), 'json');
142
+ }
143
+
144
+ private async performGet(url: string, responseType?: 'json' | 'raw'): Promise<any> {
145
+ try {
146
+ const response = await fetch(url);
147
+ if (!response.ok) {
148
+ throw new Error(`Failed to perform GET. status: ${response.status}`);
149
+ }
150
+
151
+ if (responseType === 'raw') {
152
+ const arrayBuffer = await response.arrayBuffer();
153
+ return new Uint8Array(arrayBuffer);
154
+ } else {
155
+ return await response.json();
156
+ }
157
+ } catch (e) {
158
+ throw new Error(`Unexpected Error: ${e}`);
159
+ }
160
+ }
161
+ }
@@ -18,20 +18,10 @@ export class WalletCache {
18
18
  this.nfts.clear();
19
19
  }
20
20
 
21
- public hasToken(id: string): boolean {
22
- id = tokenIdToHex(id);
23
- return this.tokens.has(id);
24
- }
25
-
26
- public hasNft(id: string): boolean {
27
- id = tokenIdToHex(id);
28
- return this.nfts.has(id);
29
- }
30
-
31
21
  public async getToken(id: string): Promise<TokenEntity | undefined> {
32
22
  id = tokenIdToHex(id);
33
23
  if (this.tokens.has(id)) {
34
- return this.tokens.get(id)!;
24
+ return this.tokens.get(id);
35
25
  }
36
26
 
37
27
  const token = await this.walletDb.getToken(id);
@@ -44,10 +34,10 @@ export class WalletCache {
44
34
  public async getNft(id: string): Promise<NftEntity | undefined> {
45
35
  id = tokenIdToHex(id);
46
36
  if (this.nfts.has(id)) {
47
- return this.nfts.get(id)!;
37
+ return this.nfts.get(id);
48
38
  }
49
39
 
50
- const nft = await this.walletDb.getLocalNft(id);
40
+ const nft = await this.walletDb.getNft(id);
51
41
  if (nft) {
52
42
  this.nfts.set(id, nft);
53
43
  }
@@ -61,4 +51,4 @@ export class WalletCache {
61
51
  public removeNft(id: string): void {
62
52
  this.nfts.delete(tokenIdToHex(id));
63
53
  }
64
- }
54
+ }
@@ -1,7 +1,7 @@
1
1
  import { Address, BNExtended, BufferWriter, Script, ScriptOpcode } from "libnexa-ts";
2
- import type { VaultDTO } from "../types";
2
+ import type { ITXHistory, VaultDTO } from "../types";
3
3
  import { AccountType, generateVaultAddress, KeySpace } from "../utils";
4
- import type { KeyManager } from "./key";
4
+ import { KeyManager } from "./key";
5
5
  import type { RostrumService } from "./rostrum";
6
6
 
7
7
  const HODL_FIRST_BLOCK = 274710;
@@ -18,58 +18,70 @@ export class WalletDiscoveryService {
18
18
  }
19
19
 
20
20
  public async discoverWalletIndex(type: AccountType, keySpace: KeySpace): Promise<number> {
21
- let index = 0, stop = false, addrBatch = 0;
22
-
23
- do {
24
- stop = true;
25
- for (let i = addrBatch; i < addrBatch+20; i++) {
26
- const keyPath = { account: type, type: keySpace, index: i };
27
- const rAddr = this.keyManager.getKey(keyPath).privateKey.toAddress().toString();
28
- const isUsed = await this.rostrumService.isAddressUsed(rAddr);
29
- if (isUsed) {
30
- index = i;
31
- stop = false;
32
- }
21
+ let batchStart = 0;
22
+ let lastUsedBatchStart = -1;
23
+ let lastUsedBatchResults: boolean[] = [];
24
+
25
+ while (true) {
26
+ const results = await Promise.all(
27
+ Array.from({ length: KeyManager.GAP_LIMIT }, (_, i) =>
28
+ this.rostrumService.isAddressUsed(this.keyManager.deriveAddress(type, keySpace, batchStart + i))
29
+ )
30
+ );
31
+
32
+ if (results.some(used => used)) {
33
+ lastUsedBatchStart = batchStart;
34
+ lastUsedBatchResults = results;
35
+ batchStart += KeyManager.GAP_LIMIT;
36
+ } else {
37
+ break;
33
38
  }
34
- addrBatch += 20;
35
- } while (!stop);
36
-
37
- return index;
38
- }
39
+ }
39
40
 
40
- public async discoverVaults(addresses: string[]): Promise<Map<string, VaultDTO>> {
41
- const vaultsPromises: Promise<Set<string>>[] = [];
42
- for (const address of addresses) {
43
- const p = this.checkVaultsForAddress(address);
44
- vaultsPromises.push(p);
41
+ if (lastUsedBatchStart === -1) {
42
+ return -1;
45
43
  }
46
44
 
47
- const res = await Promise.all(vaultsPromises);
45
+ for (let i = KeyManager.GAP_LIMIT - 1; i >= 0; i--) {
46
+ if (lastUsedBatchResults[i]) {
47
+ return lastUsedBatchStart + i;
48
+ }
49
+ }
50
+
51
+ return lastUsedBatchStart;
52
+ }
53
+
54
+ public async discoverVaults(walletTxs: ITXHistory[]): Promise<Map<string, VaultDTO>> {
55
+ const vaultsHex = await this.checkForVaults(walletTxs);
48
56
  const vaults = new Map<string, VaultDTO>();
49
57
 
50
- res.forEach(set => {
51
- set.forEach(hex => {
52
- const vault = this.parseVaultDetails(hex);
53
- if (vault) {
54
- vaults.set(vault.address, vault);
55
- }
56
- });
58
+ vaultsHex.forEach(hex => {
59
+ const vault = this.parseVaultDetails(hex);
60
+ if (vault) {
61
+ vaults.set(vault.address, vault);
62
+ }
57
63
  });
58
64
 
59
65
  return vaults;
60
66
  }
61
67
 
62
- private async checkVaultsForAddress(address: string): Promise<Set<string>> {
68
+ private async checkForVaults(history: ITXHistory[]): Promise<Set<string>> {
63
69
  const vaults = new Set<string>();
64
70
 
65
- const history = await this.rostrumService.getTransactionsHistory(address, HODL_FIRST_BLOCK);
66
- for (const txHistory of history) {
67
- const tx = await this.rostrumService.getTransaction(txHistory.tx_hash);
68
- const hodls = tx.vout.filter(out => out.scriptPubKey.hex.startsWith(HODL_SCRIPT_PREFIX));
69
- for (const hodl of hodls) {
70
- vaults.add(hodl.scriptPubKey.hex);
71
- }
72
- }
71
+ await Promise.all(
72
+ history.map(async txHistory => {
73
+ if (txHistory.height > 0 && txHistory.height < HODL_FIRST_BLOCK) {
74
+ return;
75
+ }
76
+
77
+ const tx = await this.rostrumService.getTransaction(txHistory.tx_hash);
78
+ for (const out of tx.vout) {
79
+ if (out.scriptPubKey.hex.startsWith(HODL_SCRIPT_PREFIX)) {
80
+ vaults.add(out.scriptPubKey.hex);
81
+ }
82
+ }
83
+ })
84
+ );
73
85
 
74
86
  return vaults;
75
87
  }
@@ -107,4 +119,4 @@ export class WalletDiscoveryService {
107
119
 
108
120
  return dto;
109
121
  }
110
- }
122
+ }
@@ -5,4 +5,5 @@ export * from './asset';
5
5
  export * from './transaction';
6
6
  export * from './session';
7
7
  export * from './tx-transformer';
8
- export * from './wallet';
8
+ export * from './wallet';
9
+ export * from './market';
@@ -1,11 +1,13 @@
1
1
  import { mnemonicToSeedSync } from "@scure/bip39";
2
2
  import { HDPrivateKey } from "libnexa-ts";
3
- import type { AccountType } from "../utils/enums";
3
+ import type { AccountType, KeySpace } from "../utils/enums";
4
4
  import type { KeyPath } from "../types/wallet.types";
5
5
  import { keyPathToString, stringToKeyPath } from "../utils/keypath";
6
6
 
7
7
  export class KeyManager {
8
8
 
9
+ public static readonly GAP_LIMIT = 20;
10
+
9
11
  private seed!: Uint8Array;
10
12
  private masterKey!: HDPrivateKey;
11
13
  private accountKeys = new Map<number, HDPrivateKey>();
@@ -35,6 +37,10 @@ export class KeyManager {
35
37
  return key;
36
38
  }
37
39
 
40
+ public deriveAddress(account: AccountType, space: KeySpace, index: number): string {
41
+ return this.getKey({ account, type: space, index }).privateKey.toAddress().toString();
42
+ }
43
+
38
44
  public getKey(keyPath: string | KeyPath): HDPrivateKey {
39
45
  const path = typeof keyPath === 'string'
40
46
  ? keyPath
@@ -52,4 +58,4 @@ export class KeyManager {
52
58
 
53
59
  return key;
54
60
  }
55
- }
61
+ }