@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.
- package/dist/index.js +1798 -1986
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence/index.d.ts +1 -1
- package/dist/types/persistence/index.d.ts.map +1 -1
- package/dist/types/persistence/{datastore/db.d.ts → repository.d.ts} +8 -5
- package/dist/types/persistence/repository.d.ts.map +1 -0
- package/dist/types/persistence/wallet-db.d.ts +17 -25
- package/dist/types/persistence/wallet-db.d.ts.map +1 -1
- package/dist/types/services/asset.d.ts +6 -0
- package/dist/types/services/asset.d.ts.map +1 -1
- package/dist/types/services/cache.d.ts +0 -2
- package/dist/types/services/cache.d.ts.map +1 -1
- package/dist/types/services/discovery.d.ts +3 -3
- package/dist/types/services/discovery.d.ts.map +1 -1
- package/dist/types/services/index.d.ts +1 -0
- package/dist/types/services/index.d.ts.map +1 -1
- package/dist/types/services/key.d.ts +3 -0
- package/dist/types/services/key.d.ts.map +1 -1
- package/dist/types/services/market.d.ts +33 -0
- package/dist/types/services/market.d.ts.map +1 -0
- package/dist/types/services/rostrum.d.ts +5 -3
- package/dist/types/services/rostrum.d.ts.map +1 -1
- package/dist/types/services/transaction.d.ts.map +1 -1
- package/dist/types/services/wallet.d.ts +13 -6
- package/dist/types/services/wallet.d.ts.map +1 -1
- package/dist/types/types/db.types.d.ts +4 -0
- package/dist/types/types/db.types.d.ts.map +1 -1
- package/dist/types/utils/asset.d.ts +1 -2
- package/dist/types/utils/asset.d.ts.map +1 -1
- package/dist/types/utils/market.d.ts +0 -3
- package/dist/types/utils/market.d.ts.map +1 -1
- package/package.json +13 -17
- package/src/index.ts +0 -1
- package/src/persistence/index.ts +1 -1
- package/src/persistence/{datastore/db.ts → repository.ts} +9 -5
- package/src/persistence/wallet-db.ts +95 -91
- package/src/services/asset.ts +60 -26
- package/src/services/cache.ts +4 -14
- package/src/services/discovery.ts +54 -42
- package/src/services/index.ts +2 -1
- package/src/services/key.ts +8 -2
- package/src/services/market.ts +143 -0
- package/src/services/rostrum.ts +14 -6
- package/src/services/transaction.ts +3 -10
- package/src/services/wallet.ts +66 -42
- package/src/types/db.types.ts +6 -1
- package/src/utils/asset.ts +2 -21
- package/src/utils/market.ts +0 -54
- package/dist/types/persistence/datastore/db.d.ts.map +0 -1
- package/dist/types/persistence/datastore/index.d.ts +0 -3
- package/dist/types/persistence/datastore/index.d.ts.map +0 -1
- package/dist/types/persistence/datastore/kv.d.ts +0 -34
- package/dist/types/persistence/datastore/kv.d.ts.map +0 -1
- package/dist/types/state/hooks.d.ts +0 -17
- package/dist/types/state/hooks.d.ts.map +0 -1
- package/dist/types/state/index.d.ts +0 -4
- package/dist/types/state/index.d.ts.map +0 -1
- package/dist/types/state/slices/auth.d.ts +0 -17
- package/dist/types/state/slices/auth.d.ts.map +0 -1
- package/dist/types/state/slices/dapp.d.ts +0 -29
- package/dist/types/state/slices/dapp.d.ts.map +0 -1
- package/dist/types/state/slices/index.d.ts +0 -8
- package/dist/types/state/slices/index.d.ts.map +0 -1
- package/dist/types/state/slices/loader.d.ts +0 -15
- package/dist/types/state/slices/loader.d.ts.map +0 -1
- package/dist/types/state/slices/market.d.ts +0 -54
- package/dist/types/state/slices/market.d.ts.map +0 -1
- package/dist/types/state/slices/notifications.d.ts +0 -142
- package/dist/types/state/slices/notifications.d.ts.map +0 -1
- package/dist/types/state/slices/status.d.ts +0 -35
- package/dist/types/state/slices/status.d.ts.map +0 -1
- package/dist/types/state/slices/wallet.d.ts +0 -833
- package/dist/types/state/slices/wallet.d.ts.map +0 -1
- package/dist/types/state/store.d.ts +0 -26
- package/dist/types/state/store.d.ts.map +0 -1
- package/src/persistence/datastore/index.ts +0 -2
- package/src/persistence/datastore/kv.ts +0 -129
- package/src/state/hooks.ts +0 -47
- package/src/state/index.ts +0 -3
- package/src/state/slices/auth.ts +0 -28
- package/src/state/slices/dapp.ts +0 -32
- package/src/state/slices/index.ts +0 -7
- package/src/state/slices/loader.ts +0 -31
- package/src/state/slices/market.ts +0 -47
- package/src/state/slices/notifications.ts +0 -44
- package/src/state/slices/status.ts +0 -41
- package/src/state/slices/wallet.ts +0 -107
- package/src/state/store.ts +0 -27
|
@@ -1,69 +1,65 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
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
|
-
|
|
28
|
-
this.
|
|
11
|
+
constructor(repository: Repository) {
|
|
12
|
+
this.repository = repository;
|
|
29
13
|
}
|
|
30
14
|
|
|
31
|
-
public
|
|
32
|
-
return this.
|
|
15
|
+
public initSchema(): Promise<boolean> {
|
|
16
|
+
return this.repository.initSchema();
|
|
33
17
|
}
|
|
34
18
|
|
|
35
|
-
public
|
|
36
|
-
return this.
|
|
19
|
+
public clearData(): Promise<void> {
|
|
20
|
+
return this.repository.clearData();
|
|
37
21
|
}
|
|
38
22
|
|
|
39
|
-
public
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
|
49
|
-
return this.
|
|
33
|
+
public upsertAssetTransaction(assetTx: AssetTransactionEntity): Promise<void> {
|
|
34
|
+
return this.repository.upsertAssetTransaction(assetTx);
|
|
50
35
|
}
|
|
51
36
|
|
|
52
|
-
public async
|
|
53
|
-
|
|
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
|
|
57
|
-
|
|
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
|
|
61
|
-
return this.
|
|
57
|
+
public countTransactions(account: number, tokenId?: string): Promise<number> {
|
|
58
|
+
return this.repository.countTransactions(account, tokenId);
|
|
62
59
|
}
|
|
63
60
|
|
|
64
|
-
public
|
|
65
|
-
|
|
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.
|
|
72
|
+
await this.repository.upsertToken(token);
|
|
77
73
|
await this.saveAsset(asset);
|
|
78
|
-
this.notify({ type: 'token_refresh' });
|
|
79
74
|
}
|
|
80
75
|
|
|
81
|
-
public
|
|
82
|
-
return this.
|
|
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
|
|
86
|
-
return this.
|
|
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.
|
|
86
|
+
const count = await this.repository.countAssetsById(tokenId);
|
|
92
87
|
if (count == 0) {
|
|
93
|
-
await this.
|
|
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.
|
|
99
|
+
await this.repository.upsertNft(nft);
|
|
106
100
|
await this.saveAsset(asset);
|
|
107
|
-
this.notify({ type: 'nft_refresh' });
|
|
108
101
|
}
|
|
109
102
|
|
|
110
|
-
public
|
|
111
|
-
return this.
|
|
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
|
|
115
|
-
return this.
|
|
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.
|
|
113
|
+
const count = await this.repository.countAssetsById(tokenId);
|
|
121
114
|
if (count == 0) {
|
|
122
|
-
await this.
|
|
115
|
+
await this.repository.deleteNft(tokenId);
|
|
123
116
|
}
|
|
124
|
-
this.notify({ type: 'nft_refresh' });
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
public
|
|
128
|
-
return this.
|
|
119
|
+
public countNfts(account: number): Promise<number> {
|
|
120
|
+
return this.repository.countNfts(account);
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
public
|
|
132
|
-
return this.
|
|
123
|
+
public getAssets(account: number, type: AssetType): Promise<AssetEntity[]> {
|
|
124
|
+
return this.repository.getAssets(account, type);
|
|
133
125
|
}
|
|
134
126
|
|
|
135
|
-
public
|
|
136
|
-
|
|
127
|
+
public saveAsset(asset: AssetEntity): Promise<void> {
|
|
128
|
+
return this.repository.upsertAsset(asset);
|
|
137
129
|
}
|
|
138
130
|
|
|
139
|
-
public
|
|
140
|
-
return this.
|
|
131
|
+
public removeAsset(account: number, id: string): Promise<void> {
|
|
132
|
+
return this.repository.deleteAsset(account, id);
|
|
141
133
|
}
|
|
142
134
|
|
|
143
|
-
public
|
|
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.
|
|
146
|
+
return this.repository.upsertAccount(accountEntity);
|
|
155
147
|
}
|
|
156
148
|
|
|
157
149
|
public async getAccounts(): Promise<AccountDTO[]> {
|
|
158
|
-
const accs = await this.
|
|
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
|
|
168
|
-
return this.
|
|
159
|
+
public countAccounts(): Promise<number> {
|
|
160
|
+
return this.repository.countAccounts();
|
|
169
161
|
}
|
|
170
162
|
|
|
171
|
-
public
|
|
172
|
-
return this.
|
|
163
|
+
public updateAccountName(account: number, name: string): Promise<void> {
|
|
164
|
+
return this.repository.updateAccountName(account, name);
|
|
173
165
|
}
|
|
174
166
|
|
|
175
|
-
public
|
|
176
|
-
return this.
|
|
167
|
+
public saveSession(session: SessionEntity): Promise<void> {
|
|
168
|
+
return this.repository.upsertSession(session);
|
|
177
169
|
}
|
|
178
170
|
|
|
179
|
-
public
|
|
180
|
-
return this.
|
|
171
|
+
public getAccountSessions(accountId: number): Promise<SessionEntity[]> {
|
|
172
|
+
return this.repository.getSessionsByAccount(accountId);
|
|
181
173
|
}
|
|
182
174
|
|
|
183
|
-
public
|
|
184
|
-
return this.
|
|
175
|
+
public removeSession(sessionId: string): Promise<void> {
|
|
176
|
+
return this.repository.deleteSession(sessionId);
|
|
185
177
|
}
|
|
186
178
|
|
|
187
|
-
public
|
|
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.
|
|
190
|
+
return this.repository.upsertAddress(addressEntity);
|
|
199
191
|
}
|
|
200
192
|
|
|
201
193
|
public async getReceiveAddresses(): Promise<AddressDTO[]> {
|
|
202
|
-
const addrs = await this.
|
|
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.
|
|
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
|
|
222
|
-
return this.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
}
|
package/src/services/asset.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { NftEntity, TokenEntity } from "../types/db.types";
|
|
2
|
-
import {
|
|
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
|
-
|
|
21
|
-
|
|
20
|
+
const token = await this.walletCache.getToken(assetId);
|
|
21
|
+
if (token) {
|
|
22
22
|
return {
|
|
23
23
|
type: "token",
|
|
24
|
-
parent: token
|
|
25
|
-
token: token
|
|
26
|
-
tokenIdHex: token
|
|
24
|
+
parent: token.parent,
|
|
25
|
+
token: token.token,
|
|
26
|
+
tokenIdHex: token.tokenIdHex,
|
|
27
27
|
data: {
|
|
28
|
-
name: token
|
|
29
|
-
ticker: token
|
|
30
|
-
decimals: token
|
|
31
|
-
iconUrl: token
|
|
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
|
-
|
|
37
|
-
|
|
36
|
+
const nft = await this.walletCache.getNft(assetId);
|
|
37
|
+
if (nft) {
|
|
38
38
|
return {
|
|
39
39
|
type: "nft",
|
|
40
|
-
parent: nft
|
|
41
|
-
token: nft
|
|
42
|
-
tokenIdHex: nft
|
|
40
|
+
parent: nft.parent,
|
|
41
|
+
token: nft.token,
|
|
42
|
+
tokenIdHex: nft.tokenIdHex,
|
|
43
43
|
data: {
|
|
44
|
-
name: nft
|
|
45
|
-
series: nft
|
|
46
|
-
collection: nft
|
|
47
|
-
author: nft
|
|
48
|
-
public: nft
|
|
49
|
-
front: nft
|
|
50
|
-
back: nft
|
|
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.
|
|
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.
|
|
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
|
+
}
|
package/src/services/cache.ts
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
35
|
-
} while (!stop);
|
|
36
|
-
|
|
37
|
-
return index;
|
|
38
|
-
}
|
|
39
|
+
}
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
68
|
+
private async checkForVaults(history: ITXHistory[]): Promise<Set<string>> {
|
|
63
69
|
const vaults = new Set<string>();
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
+
}
|
package/src/services/index.ts
CHANGED
package/src/services/key.ts
CHANGED
|
@@ -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
|
+
}
|