@exodus/headless 2.0.0-alpha.0 → 2.0.0-alpha.10
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/CHANGELOG.md +70 -0
- package/README.md +137 -20
- package/package.json +23 -7
- package/src/api.js +47 -2
- package/src/application.js +28 -13
- package/src/atoms/attach.js +40 -0
- package/src/constants.js +6 -0
- package/src/dependencies/atoms.js +32 -1
- package/src/dependencies/index.js +7 -0
- package/src/dependencies/modules.js +35 -6
- package/src/dependencies/plugins.js +7 -0
- package/src/index.js +75 -6
- package/src/ioc.js +8 -1
- package/src/plugins/attach.js +19 -0
- package/src/plugins/index.js +3 -0
- package/src/plugins/log-lifecycle.js +25 -0
- package/src/unlock-encrypted-storage.js +19 -0
- package/src/utils/blockchain-metadata.js +48 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,76 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.0.0-alpha.10](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.9...@exodus/headless@2.0.0-alpha.10) (2023-04-30)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- add pricingClient to headless ([#1439](https://github.com/ExodusMovement/exodus-hydra/issues/1439)) ([2a82a4c](https://github.com/ExodusMovement/exodus-hydra/commit/2a82a4c663b542178580908aaaff840524d55369))
|
|
11
|
+
- attach wallet account atoms ([#1437](https://github.com/ExodusMovement/exodus-hydra/issues/1437)) ([2648699](https://github.com/ExodusMovement/exodus-hydra/commit/264869986c175091e6bc7c48e852946bd60911d6))
|
|
12
|
+
|
|
13
|
+
## [2.0.0-alpha.9](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.8...@exodus/headless@2.0.0-alpha.9) (2023-04-26)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- add available-assets to headless ([#1361](https://github.com/ExodusMovement/exodus-hydra/issues/1361)) ([900d142](https://github.com/ExodusMovement/exodus-hydra/commit/900d142018ff112f36ef0f7ef53cf5020020e3ca))
|
|
18
|
+
|
|
19
|
+
## [2.0.0-alpha.8](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.7...@exodus/headless@2.0.0-alpha.8) (2023-04-25)
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- add enabled-assets to headless ([#1235](https://github.com/ExodusMovement/exodus-hydra/issues/1235)) ([a808b75](https://github.com/ExodusMovement/exodus-hydra/commit/a808b750bd911c33241ae710fbf8d8ba7e2073a6))
|
|
24
|
+
- add lifecycle docs ([#1313](https://github.com/ExodusMovement/exodus-hydra/issues/1313)) ([df18faa](https://github.com/ExodusMovement/exodus-hydra/commit/df18faa9c341404c2feaadf51ec46236c54e2f15))
|
|
25
|
+
- add remoteConfig module ([#1370](https://github.com/ExodusMovement/exodus-hydra/issues/1370)) ([ebc888d](https://github.com/ExodusMovement/exodus-hydra/commit/ebc888d6440c509a19dd6c9c600033fd41128ad7))
|
|
26
|
+
- add support for plugins ([#1351](https://github.com/ExodusMovement/exodus-hydra/issues/1351)) ([fac0e2a](https://github.com/ExodusMovement/exodus-hydra/commit/fac0e2a727b0e71ad5f0619b8457c7e80612f707))
|
|
27
|
+
|
|
28
|
+
## [2.0.0-alpha.7](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.6...@exodus/headless@2.0.0-alpha.7) (2023-04-24)
|
|
29
|
+
|
|
30
|
+
### ⚠ BREAKING CHANGES
|
|
31
|
+
|
|
32
|
+
- pass compatibility modes config to wallet (#1223)
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
- add blockchain metadata to headless ([#1293](https://github.com/ExodusMovement/exodus-hydra/issues/1293)) ([04390a7](https://github.com/ExodusMovement/exodus-hydra/commit/04390a71cb01744cd427f470735fa0748b9157ca))
|
|
37
|
+
- add namespaceStorage preprocessor ([#1322](https://github.com/ExodusMovement/exodus-hydra/issues/1322)) ([95f403e](https://github.com/ExodusMovement/exodus-hydra/commit/95f403e59c87f90901247619c727496ebac0a399))
|
|
38
|
+
- pass compatibility modes config to wallet ([#1223](https://github.com/ExodusMovement/exodus-hydra/issues/1223)) ([b49b640](https://github.com/ExodusMovement/exodus-hydra/commit/b49b64097af7969e210e5ecf5395ee7f40a13eac))
|
|
39
|
+
|
|
40
|
+
## [2.0.0-alpha.6](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.5...@exodus/headless@2.0.0-alpha.6) (2023-04-20)
|
|
41
|
+
|
|
42
|
+
### Features
|
|
43
|
+
|
|
44
|
+
- add walletAccounts in headless ([#1184](https://github.com/ExodusMovement/exodus-hydra/issues/1184)) ([8d9c93d](https://github.com/ExodusMovement/exodus-hydra/commit/8d9c93d86173476211d596e883a72b51b645e866))
|
|
45
|
+
|
|
46
|
+
## [2.0.0-alpha.5](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.4...@exodus/headless@2.0.0-alpha.5) (2023-04-20)
|
|
47
|
+
|
|
48
|
+
### Features
|
|
49
|
+
|
|
50
|
+
- force restart on import ([#1297](https://github.com/ExodusMovement/exodus-hydra/issues/1297)) ([3900196](https://github.com/ExodusMovement/exodus-hydra/commit/39001966ce7d962ddde9df8aa3b93619053569f8))
|
|
51
|
+
- **headless:** clear storage when seed not present ([#1300](https://github.com/ExodusMovement/exodus-hydra/issues/1300)) ([c3c76f5](https://github.com/ExodusMovement/exodus-hydra/commit/c3c76f5953d91e5ef308b129f1bb2fec0dc41500))
|
|
52
|
+
- unlock encrypted storage on wallet unlock ([#1304](https://github.com/ExodusMovement/exodus-hydra/issues/1304)) ([09ea5f2](https://github.com/ExodusMovement/exodus-hydra/commit/09ea5f20ff9547557f59d4c416cee3291f348fdf))
|
|
53
|
+
|
|
54
|
+
## [2.0.0-alpha.4](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.3...@exodus/headless@2.0.0-alpha.4) (2023-04-13)
|
|
55
|
+
|
|
56
|
+
**Note:** Version bump only for package @exodus/headless
|
|
57
|
+
|
|
58
|
+
## [2.0.0-alpha.3](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.2...@exodus/headless@2.0.0-alpha.3) (2023-04-11)
|
|
59
|
+
|
|
60
|
+
### Features
|
|
61
|
+
|
|
62
|
+
- export subscribe/unsubscribe ([#1161](https://github.com/ExodusMovement/exodus-hydra/issues/1161)) ([7da465f](https://github.com/ExodusMovement/exodus-hydra/commit/7da465fc1734fd0818a55ff740704adb8c6ae222))
|
|
63
|
+
|
|
64
|
+
## [2.0.0-alpha.2](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0-alpha.1...@exodus/headless@2.0.0-alpha.2) (2023-04-10)
|
|
65
|
+
|
|
66
|
+
### Features
|
|
67
|
+
|
|
68
|
+
- restart reason ([#1163](https://github.com/ExodusMovement/exodus-hydra/issues/1163)) ([d2b10c7](https://github.com/ExodusMovement/exodus-hydra/commit/d2b10c71229078f52883badb5634b377c61b8b1e))
|
|
69
|
+
|
|
70
|
+
## [2.0.0-alpha.1](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@2.0.0...@exodus/headless@2.0.0-alpha.1) (2023-04-05)
|
|
71
|
+
|
|
72
|
+
### Features
|
|
73
|
+
|
|
74
|
+
- backup after restore ([#1123](https://github.com/ExodusMovement/exodus-hydra/issues/1123)) ([c08ece2](https://github.com/ExodusMovement/exodus-hydra/commit/c08ece22d8a80e995a0249abadcc20765350840d))
|
|
75
|
+
|
|
6
76
|
## [2.0.0-alpha.0](https://github.com/ExodusMovement/exodus-hydra/compare/@exodus/headless@1.1.2...@exodus/headless@2.2.0-alpha.0) (2023-04-04)
|
|
7
77
|
|
|
8
78
|
### ⚠ BREAKING CHANGES
|
package/README.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
The headless Exodus wallet SDK
|
|
4
4
|
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Quick Start](#quick-start)
|
|
8
|
+
- [Lifecycle](#lifecycle)
|
|
9
|
+
- [Port](#port)
|
|
10
|
+
- [Adapters](#adapters)
|
|
11
|
+
- [Config](#config)
|
|
12
|
+
- [Headless API](#headless-api)
|
|
13
|
+
|
|
5
14
|
## Quick Start
|
|
6
15
|
|
|
7
16
|
```js
|
|
@@ -34,15 +43,74 @@ const exodus = container.resolve()
|
|
|
34
43
|
await exodus.wallet.create({ passphrase: 'my-super-secure-passphrase' })
|
|
35
44
|
```
|
|
36
45
|
|
|
46
|
+
## Lifecycle
|
|
47
|
+
|
|
48
|
+
The headless wallet instance transitions through different states during his life. When moving from one another, there are two things that are triggered:
|
|
49
|
+
|
|
50
|
+
- Fires hook call: Allows modules to subscribe and halt transition until listener resolves.
|
|
51
|
+
- Fires event call: Emitted after all hooks had been executed and resolved.
|
|
52
|
+
|
|
53
|
+
Below you can find a state diagram that visualize what hooks are triggered between state transitions:
|
|
54
|
+
|
|
55
|
+
```mermaid
|
|
56
|
+
stateDiagram-v2
|
|
57
|
+
direction LR
|
|
58
|
+
[*] --> Starting
|
|
59
|
+
|
|
60
|
+
state Starting {
|
|
61
|
+
direction LR
|
|
62
|
+
|
|
63
|
+
state "Needs clear storage?*" as NeedsClear
|
|
64
|
+
state "Is importing?" as IsImporting
|
|
65
|
+
|
|
66
|
+
NeedsClear --> Clearing : CLEAR
|
|
67
|
+
Clearing --> IsImporting
|
|
68
|
+
IsImporting --> Importing : IMPORT
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Starting --> Started : START
|
|
72
|
+
|
|
73
|
+
state Started {
|
|
74
|
+
direction LR
|
|
75
|
+
|
|
76
|
+
state "Has seed?" as HasSeed
|
|
77
|
+
|
|
78
|
+
HasSeed --> Empty : No
|
|
79
|
+
HasSeed --> Locked : Yes
|
|
80
|
+
|
|
81
|
+
Empty --> Locked : CREATE \n---or---\nIMPORT
|
|
82
|
+
|
|
83
|
+
Locked --> Migrating : MIGRATE
|
|
84
|
+
Migrating --> Unlocked : UNLOCK
|
|
85
|
+
Unlocked --> Locked : LOCK
|
|
86
|
+
|
|
87
|
+
Unlocked --> Restarting : DELETE
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Restarting --> [*] : RESTART
|
|
93
|
+
|
|
94
|
+
Started --> Started : LOAD
|
|
95
|
+
|
|
96
|
+
classDef conditional fill:#ededed,stroke:#c2c2c2,color:#a6a6a6,stroke-width:2;
|
|
97
|
+
|
|
98
|
+
class NeedsClear conditional
|
|
99
|
+
class IsImporting conditional
|
|
100
|
+
class HasSeed conditional
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
\* Wallet needs to clear storage if seed is not present or is restoring a new wallet
|
|
104
|
+
|
|
37
105
|
## Port
|
|
38
106
|
|
|
39
107
|
Event bus between headless wallet and client
|
|
40
108
|
|
|
41
|
-
| Method
|
|
42
|
-
|
|
|
43
|
-
| subscribe
|
|
44
|
-
| unsubscribe
|
|
45
|
-
| emit
|
|
109
|
+
| Method | Type | Description |
|
|
110
|
+
| ----------- | ------------------------------------------ | ------------------------------------------ |
|
|
111
|
+
| subscribe | `({ type: string, payload: any }) => void` | Subscribe to receive events. |
|
|
112
|
+
| unsubscribe | `({ type: string, payload: any }) => void` | Unsubscribe handler from receiving events. |
|
|
113
|
+
| emit | `(type: string, payload: any) => void` | Emit an event. |
|
|
46
114
|
|
|
47
115
|
## Adapters
|
|
48
116
|
|
|
@@ -121,21 +189,21 @@ Currently not used.
|
|
|
121
189
|
|
|
122
190
|
> Type: object
|
|
123
191
|
|
|
124
|
-
| Method | Type
|
|
125
|
-
| ------------------------ |
|
|
126
|
-
| exists | `async () => boolean`
|
|
127
|
-
| create | `async ({ passphrase?: string }) => void`
|
|
128
|
-
| import | `async ({ mnemonic: string, passphrase?: string }) => void`
|
|
129
|
-
| delete | `async ({ passphrase?: string }) => void`
|
|
130
|
-
| lock | `async () => void`
|
|
131
|
-
| unlock | `async ({ passphrase?: string }) => void`
|
|
132
|
-
| isLocked | `async () => boolean`
|
|
133
|
-
| getMnemonic | `async () => void`
|
|
134
|
-
| changePassphrase | `async ({ currentPassphrase?: string. newPassphrase: string }) => void`
|
|
135
|
-
| restoreFromCurrentPhrase | `async ({ passphrase?: string }) => void`
|
|
136
|
-
| load | `async () => void`
|
|
137
|
-
| unload | `async () => void`
|
|
138
|
-
| changeLockTimer | `async ({ ttl: number }) => void`
|
|
192
|
+
| Method | Type | Description |
|
|
193
|
+
| ------------------------ | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
194
|
+
| exists | `async () => boolean` | Checks if a wallet exists on the device. |
|
|
195
|
+
| create | `async ({ passphrase?: string }) => void` | Creates new wallet |
|
|
196
|
+
| import | `async ({ mnemonic: string, passphrase?: string, forceRestart?: boolean }) => void` | Imports existing wallet |
|
|
197
|
+
| delete | `async ({ passphrase?: string }) => void` | Deletes wallet. Passphrase is mandatory if wallet was created with one |
|
|
198
|
+
| lock | `async () => void` | Locks wallet |
|
|
199
|
+
| unlock | `async ({ passphrase?: string }) => void` | Unlocks wallet. Passphrase is mandatory if wallet was created with one |
|
|
200
|
+
| isLocked | `async () => boolean` | Checks if wallet is locked |
|
|
201
|
+
| getMnemonic | `async () => void` | Sets wallet as backed up |
|
|
202
|
+
| changePassphrase | `async ({ currentPassphrase?: string. newPassphrase: string }) => void` | Change passphrase. Current passphrase is mandatory if wallet was created with one |
|
|
203
|
+
| restoreFromCurrentPhrase | `async ({ passphrase?: string }) => void` | Restore current wallet. Passphrase is mandatory if wallet was created with one |
|
|
204
|
+
| load | `async () => void` | Loads UI by rehydratating data through port (`BE Only`) |
|
|
205
|
+
| unload | `async () => void` | Unloads UI by rehydratating data through port (`BE Only`) |
|
|
206
|
+
| changeLockTimer | `async ({ ttl: number }) => void` | Change auto unlock ttl (`BE Only`) |
|
|
139
207
|
|
|
140
208
|
## isMnemonicValid
|
|
141
209
|
|
|
@@ -147,3 +215,52 @@ Currently not used.
|
|
|
147
215
|
| wordlist | `string[]` | Words list to check against. |
|
|
148
216
|
|
|
149
217
|
**Returns**: `boolean`
|
|
218
|
+
|
|
219
|
+
## walletAccounts
|
|
220
|
+
|
|
221
|
+
> Type: object
|
|
222
|
+
|
|
223
|
+
| Method | Type | Description |
|
|
224
|
+
| ---------- | ------------------------------------------- | -------------------------------------------------------------- |
|
|
225
|
+
| create | `async (walletAccountFields) => void` | Creates a new WalletAccount with the provided fields. |
|
|
226
|
+
| update | `async (name, walletAccountFields) => void` | Updates an existing WalletAccount with the provided fields. |
|
|
227
|
+
| enable | `async (name) => void` | Enables an existing WalletAccount. |
|
|
228
|
+
| disable | `async (name) => void` | Disables an existing WalletAccount. |
|
|
229
|
+
| getEnabled | `async () => object` | Returns enabled walletAccounts as `{ [name]: WalletAccount }`. |
|
|
230
|
+
|
|
231
|
+
## blockchainMetadata
|
|
232
|
+
|
|
233
|
+
> Type: object
|
|
234
|
+
|
|
235
|
+
| Method | Type | Description |
|
|
236
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
237
|
+
| getTxLog | `async ({ assetName, walletAccount }) => TxSet` | Get the TxSet for the provided `assetName`/`walletAccount` combination (AssetSource) |
|
|
238
|
+
| getLoadedTxLogs | `async () => object` | Get the all loaded `TxSet`s as a `{ [walletAccount]: { [assetName]: TxSet } } object` |
|
|
239
|
+
| updateTxs | `async ({ assetName: string, walletAccount: string, txs: object[] }) => void` | Add or update txs with updates provided in `txs` |
|
|
240
|
+
| overwriteTxs | `async ({ assetName: string, walletAccount: string, txs: object[], notifyReceivedTxs: ?boolean }) => void` | Overwrite specified txs. |
|
|
241
|
+
| clearTxs | `async ({ assetName: string, walletAccount: string }) => void` | Remove txs for AssetSource. |
|
|
242
|
+
| removeTxs | `async ({ assetName: string, walletAccount: string, txs: object[] }) => void` | Remove provided txs. |
|
|
243
|
+
| getAccountState | `async ({ assetName, walletAccount }) => AccountState` | Get the AccountState for the provided AssetSource |
|
|
244
|
+
| getLoadedAccountStates | `async () => object` | Get the all loaded `AccountState`s as a `{ [walletAccount]: { [assetName]: AccountState } } object` |
|
|
245
|
+
| updateAccountState | `async ({ assetName: string, walletAccount: string, newData: object }) => void` | Update accountState for AssetSource. |
|
|
246
|
+
| removeAccountState | `async ({ assetName: string, walletAccount: string }) => void` | Remove accountState for AssetSource. |
|
|
247
|
+
| batch | `() => Batch` | Create a batch of updates. See [blockchainMetadata](../blockchain-metadata) README for batching details. |
|
|
248
|
+
|
|
249
|
+
## assets
|
|
250
|
+
|
|
251
|
+
> Type: object
|
|
252
|
+
|
|
253
|
+
| Method | Type | Description |
|
|
254
|
+
| ----------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
255
|
+
| enable | `async (assetNames: string[]) => void` | Enables assets. |
|
|
256
|
+
| disable | `async (assetNames: string[]) => void` | Disables assets. |
|
|
257
|
+
| addAndEnableToken | `async (assetId: string, baseAssetName: string) => string` | Adds and enables a custom token. Returns the created `asset`'s `.name` |
|
|
258
|
+
|
|
259
|
+
## subscribe
|
|
260
|
+
|
|
261
|
+
> Type: function
|
|
262
|
+
|
|
263
|
+
| Argument | Type | Description |
|
|
264
|
+
| ----------- | ------------------------------------------ | ------------------------------------------ |
|
|
265
|
+
| subscribe | `({ type: string, payload: any }) => void` | Subscribe to receive events. |
|
|
266
|
+
| unsubscribe | `({ type: string, payload: any }) => void` | Unsubscribe handler from receiving events. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/headless",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.10",
|
|
4
4
|
"description": "The headless Exodus wallet SDK",
|
|
5
5
|
"author": "Exodus Movement Inc",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -27,26 +27,42 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@exodus/atoms": "^2.9.0",
|
|
30
|
+
"@exodus/available-assets": "^2.0.0",
|
|
31
|
+
"@exodus/basic-utils": "^2.0.0",
|
|
32
|
+
"@exodus/blockchain-metadata": "^8.0.1",
|
|
33
|
+
"@exodus/config": "7.0.0",
|
|
30
34
|
"@exodus/dependency-injection": "^1.2.0",
|
|
31
35
|
"@exodus/dependency-preprocessors": "^2.0.2",
|
|
36
|
+
"@exodus/enabled-assets": "^5.0.4",
|
|
37
|
+
"@exodus/exodus-pricing-client": "^1.1.0",
|
|
32
38
|
"@exodus/fetch": "^1.2.1",
|
|
33
|
-
"@exodus/key-identifier-provider": "^1.1.
|
|
34
|
-
"@exodus/keychain": "^
|
|
39
|
+
"@exodus/key-identifier-provider": "^1.1.3",
|
|
40
|
+
"@exodus/keychain": "^4.0.0",
|
|
35
41
|
"@exodus/module": "^1.0.0",
|
|
36
|
-
"@exodus/wallet": "^
|
|
37
|
-
"@exodus/wallet-
|
|
42
|
+
"@exodus/wallet": "^6.0.1",
|
|
43
|
+
"@exodus/wallet-accounts": "^8.0.1",
|
|
44
|
+
"@exodus/wallet-compatibility-modes": "^2.0.0",
|
|
38
45
|
"bip39": "2.6.0",
|
|
46
|
+
"events": "^3.3.0",
|
|
39
47
|
"lodash": "https://registry.yarnpkg.com/@exodus/lodash/-/lodash-4.17.21-exodus.2.tgz",
|
|
40
48
|
"minimalistic-assert": "^1.0.1"
|
|
41
49
|
},
|
|
42
50
|
"devDependencies": {
|
|
51
|
+
"@exodus/bitcoin-meta": "^1.0.0",
|
|
52
|
+
"@exodus/currency": "^2.2.0",
|
|
43
53
|
"@exodus/ethereum-lib": "^2.22.2",
|
|
54
|
+
"@exodus/ethereum-meta": "^1.0.23",
|
|
55
|
+
"@exodus/models": "^8.11.1",
|
|
44
56
|
"@exodus/solana-lib": "^1.3.11",
|
|
57
|
+
"@exodus/solana-meta": "^1.0.2",
|
|
58
|
+
"@exodus/storage-encrypted": "^1.1.2",
|
|
45
59
|
"@exodus/storage-memory": "^1.1.0",
|
|
46
60
|
"@exodus/wild-emitter": "^1.0.0",
|
|
47
61
|
"buffer-json": "^2.0.0",
|
|
48
62
|
"eslint": "^8.33.0",
|
|
49
|
-
"
|
|
63
|
+
"events": "^3.3.0",
|
|
64
|
+
"jest": "^29.1.2",
|
|
65
|
+
"p-defer": "^4.0.0"
|
|
50
66
|
},
|
|
51
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "468f15a295d9b9cd5463c33bbae6d3bb93028689"
|
|
52
68
|
}
|
package/src/api.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { validateMnemonic as isMnemonicValid } from 'bip39'
|
|
2
2
|
|
|
3
|
-
const createApi = ({ ioc }) => {
|
|
3
|
+
const createApi = ({ ioc, port }) => {
|
|
4
4
|
const { passphraseCache } = ioc.getByType('adapter')
|
|
5
5
|
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
application,
|
|
8
|
+
assetsModule,
|
|
9
|
+
blockchainMetadata,
|
|
10
|
+
enabledAssets,
|
|
11
|
+
remoteConfig,
|
|
12
|
+
wallet,
|
|
13
|
+
walletAccounts,
|
|
14
|
+
} = ioc.getByType('module')
|
|
15
|
+
|
|
16
|
+
const { enabledWalletAccountsAtom } = ioc.getByType('atom')
|
|
7
17
|
|
|
8
18
|
return {
|
|
9
19
|
wallet: {
|
|
@@ -27,7 +37,42 @@ const createApi = ({ ioc }) => {
|
|
|
27
37
|
changeLockTimer: application.changeLockTimer,
|
|
28
38
|
isLocked: () => wallet.isLocked(),
|
|
29
39
|
},
|
|
40
|
+
walletAccounts: {
|
|
41
|
+
create: walletAccounts.create,
|
|
42
|
+
update: walletAccounts.update,
|
|
43
|
+
disable: walletAccounts.disable,
|
|
44
|
+
enable: walletAccounts.enable,
|
|
45
|
+
getEnabled: enabledWalletAccountsAtom.get,
|
|
46
|
+
},
|
|
47
|
+
blockchainMetadata: {
|
|
48
|
+
getTxLog: blockchainMetadata.getTxLog,
|
|
49
|
+
getLoadedTxLogs: blockchainMetadata.getLoadedTxLogs,
|
|
50
|
+
updateTxs: blockchainMetadata.updateTxs,
|
|
51
|
+
overwriteTxs: blockchainMetadata.overwriteTxs,
|
|
52
|
+
clearTxs: blockchainMetadata.clearTxs,
|
|
53
|
+
removeTxs: blockchainMetadata.removeTxs,
|
|
54
|
+
getAccountState: blockchainMetadata.getAccountState,
|
|
55
|
+
getLoadedAccountStates: blockchainMetadata.getLoadedAccountStates,
|
|
56
|
+
updateAccountState: blockchainMetadata.updateAccountState,
|
|
57
|
+
removeAccountState: blockchainMetadata.removeAccountState,
|
|
58
|
+
batch: blockchainMetadata.batch,
|
|
59
|
+
},
|
|
60
|
+
assets: {
|
|
61
|
+
enable: enabledAssets.enable,
|
|
62
|
+
disable: enabledAssets.disable,
|
|
63
|
+
addAndEnableToken: async (...args) => {
|
|
64
|
+
const asset = await assetsModule.addToken(...args)
|
|
65
|
+
await enabledAssets.enable([asset.name])
|
|
66
|
+
return asset.name
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
remoteConfig: {
|
|
70
|
+
get: remoteConfig.get,
|
|
71
|
+
getAll: remoteConfig.getAll,
|
|
72
|
+
},
|
|
30
73
|
isMnemonicValid,
|
|
74
|
+
subscribe: port.subscribe.bind(port),
|
|
75
|
+
unsubscribe: port.unsubscribe.bind(port),
|
|
31
76
|
}
|
|
32
77
|
}
|
|
33
78
|
|
package/src/application.js
CHANGED
|
@@ -50,6 +50,7 @@ class Application extends ExodusModule {
|
|
|
50
50
|
this.#storage = unsafeStorage.namespace('flags')
|
|
51
51
|
|
|
52
52
|
this.#applicationStarted = new Promise((resolve) => (this.#resolveStart = resolve))
|
|
53
|
+
this.setMaxListeners(Number.POSITIVE_INFINITY)
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
start = async () => {
|
|
@@ -63,6 +64,11 @@ class Application extends ExodusModule {
|
|
|
63
64
|
if (isDeleting || isImporting) {
|
|
64
65
|
await this.#storage.batchDelete([DELETE_FLAG, IMPORT_FLAG])
|
|
65
66
|
await this.#passphraseCache.clear()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const walletExists = await this.#wallet.exists()
|
|
70
|
+
|
|
71
|
+
if (isImporting || !walletExists) {
|
|
66
72
|
await this.fire(HOOKS.clear)
|
|
67
73
|
}
|
|
68
74
|
|
|
@@ -80,16 +86,22 @@ class Application extends ExodusModule {
|
|
|
80
86
|
load = async () => {
|
|
81
87
|
await this.#applicationStarted
|
|
82
88
|
|
|
83
|
-
const [walletExists, hasPassphraseSet, isLocked, isBackedUp] = await Promise.all([
|
|
89
|
+
const [walletExists, hasPassphraseSet, isLocked, isBackedUp, isRestoring] = await Promise.all([
|
|
84
90
|
this.#wallet.exists(),
|
|
85
91
|
this.#wallet.hasPassphraseSet(),
|
|
86
92
|
this.#wallet.isLocked(),
|
|
87
93
|
this.#wallet.isBackedUp(),
|
|
94
|
+
this.isRestoring(),
|
|
88
95
|
])
|
|
89
96
|
|
|
90
|
-
await this.fire(HOOKS.load, {
|
|
97
|
+
await this.fire(HOOKS.load, {
|
|
98
|
+
walletExists,
|
|
99
|
+
hasPassphraseSet,
|
|
100
|
+
isLocked,
|
|
101
|
+
isBackedUp,
|
|
102
|
+
isRestoring,
|
|
103
|
+
})
|
|
91
104
|
}
|
|
92
|
-
|
|
93
105
|
unload = async () => {
|
|
94
106
|
await this.#applicationStarted
|
|
95
107
|
await this.#passphraseCache.scheduleClear()
|
|
@@ -135,19 +147,21 @@ class Application extends ExodusModule {
|
|
|
135
147
|
|
|
136
148
|
await this.#applicationStarted
|
|
137
149
|
|
|
138
|
-
|
|
139
|
-
await this.#wallet.import(opts)
|
|
140
|
-
await this.#storage.set(IMPORT_FLAG, true)
|
|
150
|
+
const walletExists = await this.#wallet.exists()
|
|
141
151
|
|
|
142
|
-
|
|
152
|
+
const { forceRestart, ...wallet } = opts
|
|
143
153
|
|
|
144
|
-
|
|
145
|
-
|
|
154
|
+
await this.#wallet.import(wallet)
|
|
155
|
+
|
|
156
|
+
if (forceRestart || walletExists) {
|
|
157
|
+
await this.#storage.set(IMPORT_FLAG, true)
|
|
146
158
|
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
this.emit('restart', { reason: 'import' })
|
|
160
|
+
} else {
|
|
161
|
+
await this.fire(HOOKS.import)
|
|
149
162
|
|
|
150
|
-
|
|
163
|
+
this._logger.log('wallet imported')
|
|
164
|
+
}
|
|
151
165
|
}
|
|
152
166
|
|
|
153
167
|
getMnemonic = async (opts) => this.#wallet.getMnemonic(opts)
|
|
@@ -174,6 +188,7 @@ class Application extends ExodusModule {
|
|
|
174
188
|
if (isRestoring) {
|
|
175
189
|
await this.fire(HOOKS.restore)
|
|
176
190
|
await this.#storage.delete(RESTORE_FLAG)
|
|
191
|
+
await this.setBackedUp()
|
|
177
192
|
await this.fire(HOOKS['restore-completed'])
|
|
178
193
|
}
|
|
179
194
|
|
|
@@ -229,7 +244,7 @@ class Application extends ExodusModule {
|
|
|
229
244
|
|
|
230
245
|
delete = async () => {
|
|
231
246
|
await this.#storage.set(DELETE_FLAG, true)
|
|
232
|
-
this.emit('restart')
|
|
247
|
+
this.emit('restart', { reason: 'delete' })
|
|
233
248
|
}
|
|
234
249
|
|
|
235
250
|
changeLockTimer = async ({ ttl }) => {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const emitAtomValue = async (opts) => {
|
|
2
|
+
const { port, atomId, atom } = opts
|
|
3
|
+
const value = 'value' in opts ? opts.value : await atom.get()
|
|
4
|
+
port.emit(atomId, value)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const emitFromAtoms = ({ atoms, port }) =>
|
|
8
|
+
Object.entries(atoms).forEach(async ([atomId, atom]) => emitAtomValue({ port, atomId, atom }))
|
|
9
|
+
|
|
10
|
+
const attachAtom = ({ port, application, logger, atom, atomId, lifecycleEvents }) => {
|
|
11
|
+
let loaded = false
|
|
12
|
+
|
|
13
|
+
lifecycleEvents.forEach((event) =>
|
|
14
|
+
application.on(event, async () => {
|
|
15
|
+
loaded = true
|
|
16
|
+
await emitAtomValue({ port, atomId, atom })
|
|
17
|
+
})
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
application.on('clear', async () => {
|
|
21
|
+
try {
|
|
22
|
+
await atom?.set(undefined)
|
|
23
|
+
} catch (error) {
|
|
24
|
+
logger.debug('failed to clear atom', error)
|
|
25
|
+
// noop. atom might not support set
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
atom.observe((value) => {
|
|
30
|
+
if (loaded) emitAtomValue({ port, atomId, atom, value })
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const attachAtoms = ({ port, application, logger, atoms, lifecycleEvents = ['start'] }) => {
|
|
35
|
+
for (const [atomId, atom] of Object.entries(atoms)) {
|
|
36
|
+
attachAtom({ port, application, logger, atom, atomId, lifecycleEvents })
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default attachAtoms
|
package/src/constants.js
ADDED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import { createInMemoryAtom } from '@exodus/atoms'
|
|
1
|
+
import { createInMemoryAtom, createRemoteConfigAtomFactory } from '@exodus/atoms'
|
|
2
|
+
import {
|
|
3
|
+
walletAccountsAtomDefinition,
|
|
4
|
+
enabledWalletAccountsAtomDefinition,
|
|
5
|
+
} from '@exodus/wallet-accounts/atoms'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
enabledAndDisabledAssetsAtomDefinition,
|
|
9
|
+
enabledAssetsAtomDefinition,
|
|
10
|
+
} from '@exodus/enabled-assets/atoms'
|
|
11
|
+
|
|
12
|
+
import { availableAssetNamesAtomDefinition } from '@exodus/available-assets/atoms'
|
|
13
|
+
|
|
2
14
|
import { withType } from './utils'
|
|
3
15
|
|
|
4
16
|
const createAtomDependencies = () =>
|
|
@@ -10,6 +22,25 @@ const createAtomDependencies = () =>
|
|
|
10
22
|
dependencies: [],
|
|
11
23
|
},
|
|
12
24
|
},
|
|
25
|
+
{
|
|
26
|
+
definition: walletAccountsAtomDefinition,
|
|
27
|
+
storage: { namespace: 'walletAccounts' },
|
|
28
|
+
},
|
|
29
|
+
{ definition: enabledWalletAccountsAtomDefinition },
|
|
30
|
+
{ definition: enabledAndDisabledAssetsAtomDefinition },
|
|
31
|
+
{ definition: enabledAssetsAtomDefinition },
|
|
32
|
+
{ definition: availableAssetNamesAtomDefinition },
|
|
33
|
+
{
|
|
34
|
+
definition: {
|
|
35
|
+
id: 'pricingServerUrlAtom',
|
|
36
|
+
factory: ({ config, remoteConfig }) =>
|
|
37
|
+
createRemoteConfigAtomFactory({ remoteConfig })({
|
|
38
|
+
path: config.pricingServerPath,
|
|
39
|
+
defaultValue: config.defaultPricingServerUrl,
|
|
40
|
+
}),
|
|
41
|
+
dependencies: ['config', 'remoteConfig'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
13
44
|
].map(withType('atom'))
|
|
14
45
|
|
|
15
46
|
export default createAtomDependencies
|
|
@@ -8,6 +8,7 @@ import createAdapterDependencies from './adapters'
|
|
|
8
8
|
import createAtomDependencies from './atoms'
|
|
9
9
|
import createModuleDependencies from './modules'
|
|
10
10
|
import { wrapConstant } from './utils'
|
|
11
|
+
import createPluginDependencies from './plugins'
|
|
11
12
|
|
|
12
13
|
const adapterKeys = [
|
|
13
14
|
// ...
|
|
@@ -16,6 +17,9 @@ const adapterKeys = [
|
|
|
16
17
|
'legacyPrivToPub',
|
|
17
18
|
'seedStorage',
|
|
18
19
|
'unsafeStorage',
|
|
20
|
+
'fusion',
|
|
21
|
+
'fetch',
|
|
22
|
+
'freeze',
|
|
19
23
|
]
|
|
20
24
|
|
|
21
25
|
const createDependencies = ({ adapters, config }) => {
|
|
@@ -33,11 +37,14 @@ const createDependencies = ({ adapters, config }) => {
|
|
|
33
37
|
|
|
34
38
|
const adaptersTree = createAdapterDependencies({ adapters, config })
|
|
35
39
|
|
|
40
|
+
const plugins = createPluginDependencies()
|
|
41
|
+
|
|
36
42
|
return []
|
|
37
43
|
.concat(adaptersTree)
|
|
38
44
|
.concat(configs)
|
|
39
45
|
.concat(modules)
|
|
40
46
|
.concat(atoms)
|
|
47
|
+
.concat(plugins)
|
|
41
48
|
.concat(wrapConstant({ id: 'logger', type: 'module', value: logger }))
|
|
42
49
|
}
|
|
43
50
|
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import createRemoteConfig from '@exodus/config/remote'
|
|
2
|
+
import keychainDefinition from '@exodus/keychain/module'
|
|
2
3
|
import walletDefinition from '@exodus/wallet/module'
|
|
4
|
+
import walletAccountsDefinition from '@exodus/wallet-accounts/module'
|
|
5
|
+
import blockchainMetadataDefinition from '@exodus/blockchain-metadata/module'
|
|
6
|
+
import enabledAssetsModuleDefinition from '@exodus/enabled-assets/module'
|
|
7
|
+
import availableAssetsModuleDefinition from '@exodus/available-assets/module'
|
|
3
8
|
import createKeyIdentifierProvider from '@exodus/key-identifier-provider'
|
|
4
9
|
import walletCompatibilityModesDefinition from '@exodus/wallet-compatibility-modes/module'
|
|
10
|
+
import EventEmitter from 'events/'
|
|
5
11
|
|
|
6
12
|
import createApplication from '../application'
|
|
7
13
|
import { withType } from './utils'
|
|
14
|
+
import unlockEncryptedStorageDefinition from '../unlock-encrypted-storage'
|
|
15
|
+
import createExodusPricingClient from '@exodus/exodus-pricing-client'
|
|
8
16
|
|
|
9
17
|
const createModuleDependencies = () =>
|
|
10
18
|
[
|
|
@@ -23,11 +31,7 @@ const createModuleDependencies = () =>
|
|
|
23
31
|
},
|
|
24
32
|
},
|
|
25
33
|
{
|
|
26
|
-
definition:
|
|
27
|
-
id: 'keychain',
|
|
28
|
-
factory: createKeychain,
|
|
29
|
-
dependencies: ['legacyPrivToPub'],
|
|
30
|
-
},
|
|
34
|
+
definition: keychainDefinition,
|
|
31
35
|
},
|
|
32
36
|
{
|
|
33
37
|
definition: walletDefinition,
|
|
@@ -35,6 +39,31 @@ const createModuleDependencies = () =>
|
|
|
35
39
|
{
|
|
36
40
|
definition: walletCompatibilityModesDefinition,
|
|
37
41
|
},
|
|
42
|
+
{ definition: unlockEncryptedStorageDefinition },
|
|
43
|
+
{ definition: walletAccountsDefinition },
|
|
44
|
+
{
|
|
45
|
+
definition: blockchainMetadataDefinition,
|
|
46
|
+
storage: { namespace: ['blockchain', 'v1'] },
|
|
47
|
+
},
|
|
48
|
+
{ definition: enabledAssetsModuleDefinition },
|
|
49
|
+
{
|
|
50
|
+
definition: {
|
|
51
|
+
id: 'remoteConfig',
|
|
52
|
+
factory: (deps) => {
|
|
53
|
+
const eventEmitter = new EventEmitter().setMaxListeners(Number.POSITIVE_INFINITY)
|
|
54
|
+
return createRemoteConfig({ eventEmitter, ...deps })
|
|
55
|
+
},
|
|
56
|
+
dependencies: ['fetch', 'freeze', 'config', 'logger'],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{ definition: availableAssetsModuleDefinition },
|
|
60
|
+
{
|
|
61
|
+
definition: {
|
|
62
|
+
id: 'pricingClient',
|
|
63
|
+
factory: createExodusPricingClient,
|
|
64
|
+
dependencies: ['fetch', 'pricingServerUrlAtom'],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
38
67
|
].map(withType('module'))
|
|
39
68
|
|
|
40
69
|
export default createModuleDependencies
|
package/src/index.js
CHANGED
|
@@ -1,35 +1,104 @@
|
|
|
1
|
+
import { pick } from '@exodus/basic-utils'
|
|
1
2
|
import createIOC from './ioc'
|
|
2
3
|
import createApi from './api'
|
|
4
|
+
import {
|
|
5
|
+
createAccountStatesUpdateHandler,
|
|
6
|
+
createLoadWalletAccountsHandler,
|
|
7
|
+
} from './utils/blockchain-metadata'
|
|
8
|
+
|
|
9
|
+
import attachPlugins from './plugins/attach'
|
|
10
|
+
import attachAtoms from './atoms/attach'
|
|
11
|
+
import { atomsToAttach } from './constants'
|
|
3
12
|
|
|
4
13
|
const createExodus = ({ adapters, config, port }) => {
|
|
5
14
|
const ioc = createIOC({ adapters, config })
|
|
15
|
+
const { headless: headlessConfig } = config
|
|
6
16
|
|
|
7
17
|
const resolve = () => {
|
|
8
18
|
ioc.resolve()
|
|
9
19
|
|
|
10
|
-
const { assetsModule } = ioc.getByType('adapter')
|
|
20
|
+
const { assetsModule, storage } = ioc.getByType('adapter')
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
application,
|
|
24
|
+
blockchainMetadata,
|
|
25
|
+
enabledAssets,
|
|
26
|
+
remoteConfig,
|
|
27
|
+
unlockEncryptedStorage,
|
|
28
|
+
walletAccounts,
|
|
29
|
+
} = ioc.getByType('module')
|
|
30
|
+
|
|
31
|
+
const handleLoadWalletAccounts = createLoadWalletAccountsHandler({
|
|
32
|
+
blockchainMetadata,
|
|
33
|
+
port,
|
|
34
|
+
config,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const handleAccountStatesUpdate = createAccountStatesUpdateHandler({
|
|
38
|
+
blockchainMetadata,
|
|
39
|
+
port,
|
|
40
|
+
config,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
blockchainMetadata.on('load-wallet-accounts', handleLoadWalletAccounts)
|
|
44
|
+
blockchainMetadata.on('tx-logs-update', (payload) => port.emit('tx-logs-update', payload))
|
|
45
|
+
blockchainMetadata.on('account-states-update', handleAccountStatesUpdate)
|
|
11
46
|
|
|
12
|
-
|
|
47
|
+
remoteConfig.on('sync', ({ current }) => port.emit('remote-config', current))
|
|
13
48
|
|
|
14
49
|
application.hook('start', () => {
|
|
50
|
+
remoteConfig.load()
|
|
51
|
+
|
|
15
52
|
port.emit('start')
|
|
16
53
|
})
|
|
17
54
|
|
|
18
55
|
application.hook('unlock', async () => {
|
|
56
|
+
if (typeof storage.unlock === 'function') unlockEncryptedStorage(storage)
|
|
57
|
+
|
|
58
|
+
remoteConfig.sync()
|
|
59
|
+
|
|
19
60
|
await assetsModule.load()
|
|
61
|
+
await walletAccounts.load()
|
|
62
|
+
await Promise.all([
|
|
63
|
+
//
|
|
64
|
+
blockchainMetadata.load(),
|
|
65
|
+
enabledAssets.load(),
|
|
66
|
+
])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
application.on('unlock', () => {
|
|
70
|
+
port.emit('unlock')
|
|
20
71
|
})
|
|
21
72
|
|
|
22
73
|
application.hook('clear', async () => {
|
|
23
|
-
await Promise.all([
|
|
74
|
+
await Promise.all([
|
|
75
|
+
//
|
|
76
|
+
assetsModule.clear(),
|
|
77
|
+
walletAccounts.clear(),
|
|
78
|
+
blockchainMetadata.clear(),
|
|
79
|
+
enabledAssets.clear(),
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
port.emit('clear')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
application.on('restart', (payload) => {
|
|
86
|
+
port.emit('restart', payload)
|
|
24
87
|
})
|
|
25
88
|
|
|
26
|
-
|
|
27
|
-
port
|
|
89
|
+
attachAtoms({
|
|
90
|
+
port,
|
|
91
|
+
application,
|
|
92
|
+
logger: ioc.get('createLogger')('attachAtoms'),
|
|
93
|
+
atoms: pick(ioc.getByType('atom'), atomsToAttach),
|
|
94
|
+
lifecycleEvents: headlessConfig?.attachAtomsLifecycleEvents,
|
|
28
95
|
})
|
|
29
96
|
|
|
97
|
+
attachPlugins({ application, plugins: ioc.getByType('plugin') })
|
|
98
|
+
|
|
30
99
|
application.start()
|
|
31
100
|
|
|
32
|
-
return createApi({ ioc })
|
|
101
|
+
return createApi({ ioc, port })
|
|
33
102
|
}
|
|
34
103
|
|
|
35
104
|
return { ...ioc, resolve }
|
package/src/ioc.js
CHANGED
|
@@ -3,6 +3,7 @@ import preprocess from '@exodus/dependency-preprocessors'
|
|
|
3
3
|
import alias from '@exodus/dependency-preprocessors/src/preprocessors/alias'
|
|
4
4
|
import logify from '@exodus/dependency-preprocessors/src/preprocessors/logify'
|
|
5
5
|
import namespaceConfig from '@exodus/dependency-preprocessors/src/preprocessors/namespace-config'
|
|
6
|
+
import namespaceStorage from '@exodus/dependency-preprocessors/src/preprocessors/namespace-storage'
|
|
6
7
|
|
|
7
8
|
import createDependencies from './dependencies'
|
|
8
9
|
|
|
@@ -11,7 +12,13 @@ const createIOC = ({ adapters, config }) => {
|
|
|
11
12
|
|
|
12
13
|
const logger = createLogger('exodus:ioc')
|
|
13
14
|
const dependencies = createDependencies({ adapters, config })
|
|
14
|
-
const preprocessors = [
|
|
15
|
+
const preprocessors = [
|
|
16
|
+
logify({ createLogger }),
|
|
17
|
+
namespaceConfig(),
|
|
18
|
+
alias(),
|
|
19
|
+
// NOTE: order matters, this should come after `alias`
|
|
20
|
+
namespaceStorage(),
|
|
21
|
+
]
|
|
15
22
|
const definitions = preprocess({ dependencies, preprocessors })
|
|
16
23
|
const ioc = createIocContainer({ logger })
|
|
17
24
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { kebabCase, memoize } from 'lodash'
|
|
2
|
+
|
|
3
|
+
// e.g. onUnlock -> unlock -> onUnlock, onChangePassphrase -> change-passphrase
|
|
4
|
+
const getApplicationHookName = memoize((lifecycleMethod) =>
|
|
5
|
+
kebabCase(lifecycleMethod.replace(/^on/, ''))
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
const attachPlugins = ({ plugins, application }) => {
|
|
9
|
+
Object.entries(plugins).forEach(([name, lifecycleMethods]) => {
|
|
10
|
+
const entries = Object.entries(lifecycleMethods || {})
|
|
11
|
+
|
|
12
|
+
for (const [lifecycleMethod, fn] of entries) {
|
|
13
|
+
const hookName = getApplicationHookName(lifecycleMethod)
|
|
14
|
+
application.hook(hookName, fn)
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default attachPlugins
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const logLifecycle = {
|
|
2
|
+
id: 'logLifecyclePlugin',
|
|
3
|
+
type: 'plugin',
|
|
4
|
+
factory: ({ logger }) => {
|
|
5
|
+
return {
|
|
6
|
+
onLock: () => logger.debug('onLock'),
|
|
7
|
+
onUnlock: () => logger.debug('onUnlock'),
|
|
8
|
+
onClear: () => logger.debug('onClear'),
|
|
9
|
+
onImport: () => logger.debug('onImport'),
|
|
10
|
+
onMigrate: () => logger.debug('onMigrate'),
|
|
11
|
+
onStart: () => logger.debug('onStart'),
|
|
12
|
+
onLoad: () => logger.debug('onLoad'),
|
|
13
|
+
onUnload: () => logger.debug('onUnload'),
|
|
14
|
+
onCreate: () => logger.debug('onCreate'),
|
|
15
|
+
onBackup: () => logger.debug('onBackup'),
|
|
16
|
+
onRestore: () => logger.debug('onRestore'),
|
|
17
|
+
onRestoreCompleted: () => logger.debug('onRestoreCompleted'),
|
|
18
|
+
onAssetsSynced: () => logger.debug('onAssetsSynced'),
|
|
19
|
+
onChangePassphrase: () => logger.debug('onChangePassphrase'),
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
dependencies: ['logger'],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default logLifecycle
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EXODUS_KEY_IDS } from '@exodus/keychain/module'
|
|
2
|
+
|
|
3
|
+
const createUnlockEncryptedStorage = ({ keychain }) => {
|
|
4
|
+
return async (encryptedStorage) => {
|
|
5
|
+
// should the key id be part of a `config` dep?
|
|
6
|
+
const sodiumEncryptor = keychain.createSodiumEncryptor(EXODUS_KEY_IDS.WALLET_INFO)
|
|
7
|
+
|
|
8
|
+
await encryptedStorage.unlock({
|
|
9
|
+
encrypt: (data) => sodiumEncryptor.encryptSecretBox({ data }),
|
|
10
|
+
decrypt: (data) => sodiumEncryptor.decryptSecretBox({ data }),
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
id: 'unlockEncryptedStorage',
|
|
17
|
+
factory: createUnlockEncryptedStorage,
|
|
18
|
+
dependencies: ['keychain'],
|
|
19
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mapValues } from '@exodus/basic-utils'
|
|
2
|
+
|
|
3
|
+
const createAccountStatesTransformer = ({ serializePortPayloads, blockchainMetadata }) => {
|
|
4
|
+
return serializePortPayloads
|
|
5
|
+
? (payload) =>
|
|
6
|
+
mapValues(payload, (byAsset, walletAccount) =>
|
|
7
|
+
mapValues(
|
|
8
|
+
byAsset,
|
|
9
|
+
(accountState, assetName) =>
|
|
10
|
+
blockchainMetadata.serializePayload({ walletAccount, assetName, accountState })
|
|
11
|
+
.accountState
|
|
12
|
+
)
|
|
13
|
+
)
|
|
14
|
+
: (payload) => payload
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createAccountStatesUpdateHandler({
|
|
18
|
+
port,
|
|
19
|
+
blockchainMetadata,
|
|
20
|
+
config: { serializePortPayloads = false },
|
|
21
|
+
}) {
|
|
22
|
+
const transform = createAccountStatesTransformer({ serializePortPayloads, blockchainMetadata })
|
|
23
|
+
|
|
24
|
+
return (payload) => {
|
|
25
|
+
port.emit('account-states-update', transform(payload))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createLoadWalletAccountsHandler({
|
|
30
|
+
port,
|
|
31
|
+
blockchainMetadata,
|
|
32
|
+
config: { serializePortPayloads = false },
|
|
33
|
+
}) {
|
|
34
|
+
const transformAccountStates = createAccountStatesTransformer({
|
|
35
|
+
serializePortPayloads,
|
|
36
|
+
blockchainMetadata,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return async () => {
|
|
40
|
+
const [txLogs, accountStates] = await Promise.all([
|
|
41
|
+
blockchainMetadata.getLoadedTxLogs(),
|
|
42
|
+
blockchainMetadata.getLoadedAccountStates(),
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
port.emit('tx-logs', txLogs)
|
|
46
|
+
port.emit('account-states', transformAccountStates(accountStates))
|
|
47
|
+
}
|
|
48
|
+
}
|