@exodus/headless 2.0.0-alpha.9.2 → 2.0.0-alpha.90
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 +642 -0
- package/README.md +25 -4
- package/package.json +52 -23
- package/src/api.js +11 -66
- package/src/application.js +55 -39
- package/src/atoms/attach.js +6 -17
- package/src/atoms/base-asset-names-to-monitor.js +38 -0
- package/src/constants.js +35 -1
- package/src/dependencies/atoms.js +2 -35
- package/src/dependencies/index.js +2 -2
- package/src/dependencies/modules.js +2 -33
- package/src/dependencies/utils.js +0 -4
- package/src/features/fees/index.js +16 -0
- package/src/features/fees/plugin.js +19 -0
- package/src/features/pricing/api.js +15 -0
- package/src/features/pricing/index.js +35 -0
- package/src/index.js +73 -62
- package/src/ioc.js +32 -6
- package/src/plugins/attach.js +24 -7
- package/src/plugins/index.js +3 -1
- package/src/plugins/log-lifecycle.js +1 -0
- package/src/unlock-encrypted-storage.js +2 -0
- package/src/utils/blockchain-metadata.js +0 -48
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ The headless Exodus wallet SDK
|
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
17
|
import createExodus from '@exodus/headless'
|
|
18
|
+
import referrals from '@exodus/headless/src/modules/referrals'
|
|
18
19
|
import Emitter from '@exodus/wild-emitter'
|
|
19
20
|
|
|
20
21
|
// 1. Create port. Acts as an event bus between headless wallet and client
|
|
@@ -25,10 +26,10 @@ const adapters = {}
|
|
|
25
26
|
const config = {}
|
|
26
27
|
|
|
27
28
|
// 3. Create Exodus container
|
|
28
|
-
const
|
|
29
|
+
const exodusContainer = createExodus({ port, adapters, config })
|
|
29
30
|
|
|
30
31
|
// 4. Register external modules. Does not support overriding modules at the moment.
|
|
31
|
-
|
|
32
|
+
exodusContainer.register({
|
|
32
33
|
definition: {
|
|
33
34
|
id: 'remoteConfig',
|
|
34
35
|
factory: createRemoteConfig,
|
|
@@ -36,11 +37,22 @@ container.register({
|
|
|
36
37
|
},
|
|
37
38
|
})
|
|
38
39
|
|
|
40
|
+
// see an example feature definition:
|
|
41
|
+
// https://github.com/ExodusMovement/exodus-hydra/blob/2e8d63426421ffcbec84a9b6fbc83eb913b47eba/modules/headless/src/modules/geolocation/index.js
|
|
42
|
+
exodusContainer.use(referrals())
|
|
43
|
+
exodusContainer.use(myCustomFeature({ id: 'myCustomFeature', ... }))
|
|
44
|
+
|
|
39
45
|
// 5. Resolve exodus instance
|
|
40
|
-
const exodus =
|
|
46
|
+
const exodus = exodusContainer.resolve()
|
|
47
|
+
|
|
48
|
+
// 6. Start exodus instance
|
|
49
|
+
await exodus.wallet.start()
|
|
41
50
|
|
|
42
|
-
//
|
|
51
|
+
// 7. Use it!
|
|
43
52
|
await exodus.wallet.create({ passphrase: 'my-super-secure-passphrase' })
|
|
53
|
+
|
|
54
|
+
// 8. Use your custom feature API, if any
|
|
55
|
+
exodus.myCustomFeature.doThatThingYouDo()
|
|
44
56
|
```
|
|
45
57
|
|
|
46
58
|
## Lifecycle
|
|
@@ -256,6 +268,15 @@ Currently not used.
|
|
|
256
268
|
| disable | `async (assetNames: string[]) => void` | Disables assets. |
|
|
257
269
|
| addAndEnableToken | `async (assetId: string, baseAssetName: string) => string` | Adds and enables a custom token. Returns the created `asset`'s `.name` |
|
|
258
270
|
|
|
271
|
+
## locale
|
|
272
|
+
|
|
273
|
+
> Type: object
|
|
274
|
+
|
|
275
|
+
| Method | Type | Description |
|
|
276
|
+
| ----------- | ---------------------------------- | ------------------------- |
|
|
277
|
+
| setCurrency | `async (currency: string) => void` | Changes current currency. |
|
|
278
|
+
| setLanguage | `async (language: string) => void` | Changes current language. |
|
|
279
|
+
|
|
259
280
|
## subscribe
|
|
260
281
|
|
|
261
282
|
> Type: function
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exodus/headless",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
4
|
-
"description": "The
|
|
5
|
-
"author": "Exodus Movement Inc",
|
|
3
|
+
"version": "2.0.0-alpha.90",
|
|
4
|
+
"description": "The platform-agnostic Exodus wallet SDK",
|
|
5
|
+
"author": "Exodus Movement Inc.",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/ExodusMovement/exodus-hydra.git"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.com/ExodusMovement/exodus-hydra/tree/master/
|
|
11
|
+
"homepage": "https://github.com/ExodusMovement/exodus-hydra/tree/master/sdks/headless",
|
|
12
12
|
"license": "UNLICENSED",
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/ExodusMovement/exodus-hydra/issues?q=is%3Aissue+is%3Aopen+label%3Aheadless"
|
|
@@ -17,50 +17,79 @@
|
|
|
17
17
|
"src",
|
|
18
18
|
"README.md",
|
|
19
19
|
"CHANGELOG.md",
|
|
20
|
-
"!**/__tests__",
|
|
20
|
+
"!**/__tests__/**",
|
|
21
21
|
"!**/*.test.js"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"lint": "eslint . --ignore-path ../../.gitignore",
|
|
25
25
|
"lint:fix": "yarn lint --fix",
|
|
26
|
-
"test": "jest"
|
|
26
|
+
"test": "jest --runInBand"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@exodus/
|
|
30
|
-
"@exodus/
|
|
29
|
+
"@exodus/address-provider": "^6.0.0",
|
|
30
|
+
"@exodus/atoms": "^5.2.3",
|
|
31
|
+
"@exodus/auto-enable-assets-plugin": "^4.0.1",
|
|
32
|
+
"@exodus/available-assets": "^3.0.0",
|
|
33
|
+
"@exodus/balances": "^7.0.0",
|
|
31
34
|
"@exodus/basic-utils": "^2.0.0",
|
|
32
|
-
"@exodus/blockchain-metadata": "^
|
|
33
|
-
"@exodus/
|
|
34
|
-
"@exodus/dependency-
|
|
35
|
-
"@exodus/
|
|
36
|
-
"@exodus/
|
|
35
|
+
"@exodus/blockchain-metadata": "^10.0.0",
|
|
36
|
+
"@exodus/dependency-injection": "^2.0.1",
|
|
37
|
+
"@exodus/dependency-preprocessors": "^2.8.4",
|
|
38
|
+
"@exodus/enabled-assets": "^7.0.0",
|
|
39
|
+
"@exodus/exodus-pricing-client": "^1.2.0",
|
|
40
|
+
"@exodus/feature-flags": "^4.0.0",
|
|
41
|
+
"@exodus/fee-monitors": "^1.0.0",
|
|
37
42
|
"@exodus/fetch": "^1.2.1",
|
|
43
|
+
"@exodus/fusion": "^6.0.0",
|
|
44
|
+
"@exodus/geolocation": "^2.1.1",
|
|
38
45
|
"@exodus/key-identifier-provider": "^1.1.3",
|
|
39
|
-
"@exodus/keychain": "^4.
|
|
46
|
+
"@exodus/keychain": "^4.1.0",
|
|
47
|
+
"@exodus/locale": "^1.1.0",
|
|
40
48
|
"@exodus/module": "^1.0.0",
|
|
41
|
-
"@exodus/
|
|
42
|
-
"@exodus/
|
|
43
|
-
"@exodus/
|
|
44
|
-
"
|
|
49
|
+
"@exodus/rates-monitor": "^3.0.0",
|
|
50
|
+
"@exodus/remote-config": "^2.0.0",
|
|
51
|
+
"@exodus/restore-progress-tracker": "^2.0.5",
|
|
52
|
+
"@exodus/wallet": "^8.1.1",
|
|
53
|
+
"@exodus/wallet-accounts": "^10.1.0",
|
|
54
|
+
"@exodus/wallet-compatibility-modes": "^3.0.0",
|
|
55
|
+
"bip39": "^2.6.0",
|
|
45
56
|
"events": "^3.3.0",
|
|
46
|
-
"lodash": "
|
|
57
|
+
"lodash": "npm:@exodus/lodash@^4.17.21-exodus.2",
|
|
47
58
|
"minimalistic-assert": "^1.0.1"
|
|
48
59
|
},
|
|
49
60
|
"devDependencies": {
|
|
61
|
+
"@exodus/ab-testing": "^6.0.0",
|
|
62
|
+
"@exodus/algorand-lib": "^2.0.1",
|
|
63
|
+
"@exodus/algorand-meta": "^1.1.4",
|
|
64
|
+
"@exodus/apy-rates": "^3.0.0",
|
|
65
|
+
"@exodus/bitcoin-lib": "^2.2.1",
|
|
50
66
|
"@exodus/bitcoin-meta": "^1.0.0",
|
|
67
|
+
"@exodus/connected-origins": "^2.0.0",
|
|
68
|
+
"@exodus/crypto-news-monitor": "^3.0.0",
|
|
51
69
|
"@exodus/currency": "^2.2.0",
|
|
52
70
|
"@exodus/ethereum-lib": "^2.22.2",
|
|
53
71
|
"@exodus/ethereum-meta": "^1.0.23",
|
|
72
|
+
"@exodus/kyc": "^4.0.0",
|
|
73
|
+
"@exodus/market-history": "^5.0.1",
|
|
54
74
|
"@exodus/models": "^8.11.1",
|
|
75
|
+
"@exodus/nfts": "^4.0.1",
|
|
76
|
+
"@exodus/personal-notes": "^3.3.0",
|
|
77
|
+
"@exodus/referrals": "^6.2.0",
|
|
55
78
|
"@exodus/solana-lib": "^1.3.11",
|
|
56
79
|
"@exodus/solana-meta": "^1.0.2",
|
|
57
|
-
"@exodus/storage-encrypted": "
|
|
58
|
-
"@exodus/storage-memory": "
|
|
80
|
+
"@exodus/storage-encrypted": "^1.1.2",
|
|
81
|
+
"@exodus/storage-memory": "^2.1.0",
|
|
82
|
+
"@exodus/top-movers-monitor": "^3.0.0",
|
|
59
83
|
"@exodus/wild-emitter": "^1.0.0",
|
|
60
84
|
"buffer-json": "^2.0.0",
|
|
61
|
-
"
|
|
85
|
+
"deepmerge": "^4.2.2",
|
|
86
|
+
"delay": "^5.0.0",
|
|
87
|
+
"eslint": "^8.44.0",
|
|
88
|
+
"eslint-plugin-simple-import-sort": "^7.0.0",
|
|
62
89
|
"events": "^3.3.0",
|
|
63
90
|
"jest": "^29.1.2",
|
|
91
|
+
"nock": "^13.3.1",
|
|
64
92
|
"p-defer": "^4.0.0"
|
|
65
|
-
}
|
|
93
|
+
},
|
|
94
|
+
"gitHead": "f223f4b6c217ef5850af8b32df9e3d14def51def"
|
|
66
95
|
}
|
package/src/api.js
CHANGED
|
@@ -1,78 +1,23 @@
|
|
|
1
1
|
import { validateMnemonic as isMnemonicValid } from 'bip39'
|
|
2
2
|
|
|
3
3
|
const createApi = ({ ioc, port }) => {
|
|
4
|
-
const
|
|
4
|
+
const apis = ioc.getByType('api')
|
|
5
|
+
const { remoteConfig } = ioc.getByType('module')
|
|
6
|
+
const { feeMonitors, nftsMonitor } = ioc.getByType('monitor')
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
wallet,
|
|
13
|
-
walletAccounts,
|
|
14
|
-
} = ioc.getByType('module')
|
|
15
|
-
|
|
16
|
-
const { enabledWalletAccountsAtom } = ioc.getByType('atom')
|
|
8
|
+
// TODO: do this on 'unload'
|
|
9
|
+
const stop = () => {
|
|
10
|
+
remoteConfig.stop()
|
|
11
|
+
feeMonitors.stop()
|
|
12
|
+
nftsMonitor?.stop()
|
|
13
|
+
}
|
|
17
14
|
|
|
18
15
|
return {
|
|
19
|
-
|
|
20
|
-
exists: () => wallet.exists(),
|
|
21
|
-
load: application.load,
|
|
22
|
-
unload: application.unload,
|
|
23
|
-
create: application.create,
|
|
24
|
-
lock: application.lock,
|
|
25
|
-
unlock: application.unlock,
|
|
26
|
-
import: application.import,
|
|
27
|
-
delete: application.delete,
|
|
28
|
-
getMnemonic: application.getMnemonic,
|
|
29
|
-
setBackedUp: application.setBackedUp,
|
|
30
|
-
changePassphrase: application.changePassphrase,
|
|
31
|
-
restoreFromCurrentPhrase: async ({ passphrase } = {}) => {
|
|
32
|
-
if (!passphrase) passphrase = await passphraseCache.get()
|
|
33
|
-
const mnemonic = await application.getMnemonic({ passphrase })
|
|
34
|
-
|
|
35
|
-
await application.import({ passphrase, mnemonic })
|
|
36
|
-
},
|
|
37
|
-
changeLockTimer: application.changeLockTimer,
|
|
38
|
-
isLocked: () => wallet.isLocked(),
|
|
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
|
-
},
|
|
16
|
+
...Object.assign({}, ...Object.values(apis)),
|
|
73
17
|
isMnemonicValid,
|
|
74
18
|
subscribe: port.subscribe.bind(port),
|
|
75
19
|
unsubscribe: port.unsubscribe.bind(port),
|
|
20
|
+
stop,
|
|
76
21
|
}
|
|
77
22
|
}
|
|
78
23
|
|
package/src/application.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import ExodusModule from '@exodus/module'
|
|
4
4
|
import assert from 'minimalistic-assert'
|
|
5
5
|
|
|
6
|
+
import { LifecycleHook as Hook } from './constants'
|
|
7
|
+
|
|
6
8
|
// Because we are forced to restart wallet after deleting/importing, we need to store certain flags to persist state between executions
|
|
7
9
|
|
|
8
10
|
// Triggers deletetion logic when wallet starts.
|
|
@@ -17,22 +19,7 @@ const IMPORT_FLAG = 'importFlag'
|
|
|
17
19
|
// Set as true on import method is called, and set to false after restore is completed
|
|
18
20
|
const RESTORE_FLAG = 'restoreFlag'
|
|
19
21
|
|
|
20
|
-
const HOOKS = Object.
|
|
21
|
-
lock: 'lock',
|
|
22
|
-
unlock: 'unlock',
|
|
23
|
-
clear: 'clear',
|
|
24
|
-
import: 'import',
|
|
25
|
-
migrate: 'migrate',
|
|
26
|
-
start: 'start',
|
|
27
|
-
load: 'load',
|
|
28
|
-
unload: 'unload',
|
|
29
|
-
create: 'create',
|
|
30
|
-
backup: 'backup',
|
|
31
|
-
restore: 'restore',
|
|
32
|
-
'restore-completed': 'restore-completed',
|
|
33
|
-
'assets-synced': 'assets-synced',
|
|
34
|
-
'change-passphrase': 'change-passphrase',
|
|
35
|
-
})
|
|
22
|
+
const HOOKS = new Set(Object.values(Hook))
|
|
36
23
|
|
|
37
24
|
class Application extends ExodusModule {
|
|
38
25
|
#hooks = {}
|
|
@@ -69,12 +56,26 @@ class Application extends ExodusModule {
|
|
|
69
56
|
const walletExists = await this.#wallet.exists()
|
|
70
57
|
|
|
71
58
|
if (isImporting || !walletExists) {
|
|
72
|
-
await this.fire(
|
|
59
|
+
await this.fire(Hook.Clear)
|
|
73
60
|
}
|
|
74
61
|
|
|
75
|
-
if (isImporting) await this.fire(
|
|
62
|
+
if (isImporting) await this.fire(Hook.Import)
|
|
63
|
+
|
|
64
|
+
const [hasPassphraseSet, isLocked, isBackedUp, isRestoring] = await Promise.all([
|
|
65
|
+
this.#wallet.hasPassphraseSet(),
|
|
66
|
+
this.#wallet.isLocked(),
|
|
67
|
+
this.#wallet.isBackedUp(),
|
|
68
|
+
this.isRestoring(),
|
|
69
|
+
])
|
|
70
|
+
|
|
71
|
+
await this.fire(Hook.Start, {
|
|
72
|
+
walletExists,
|
|
73
|
+
hasPassphraseSet,
|
|
74
|
+
isLocked,
|
|
75
|
+
isBackedUp,
|
|
76
|
+
isRestoring,
|
|
77
|
+
})
|
|
76
78
|
|
|
77
|
-
await this.fire(HOOKS.start)
|
|
78
79
|
await this.#autoUnlock()
|
|
79
80
|
|
|
80
81
|
const locked = await this.#wallet.isLocked()
|
|
@@ -94,7 +95,7 @@ class Application extends ExodusModule {
|
|
|
94
95
|
this.isRestoring(),
|
|
95
96
|
])
|
|
96
97
|
|
|
97
|
-
await this.fire(
|
|
98
|
+
await this.fire(Hook.Load, {
|
|
98
99
|
walletExists,
|
|
99
100
|
hasPassphraseSet,
|
|
100
101
|
isLocked,
|
|
@@ -105,11 +106,11 @@ class Application extends ExodusModule {
|
|
|
105
106
|
unload = async () => {
|
|
106
107
|
await this.#applicationStarted
|
|
107
108
|
await this.#passphraseCache.scheduleClear()
|
|
108
|
-
await this.fire(
|
|
109
|
+
await this.fire(Hook.Unload)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
hook = (hookName, listener) => {
|
|
112
|
-
assert(HOOKS
|
|
113
|
+
assert(HOOKS.has(hookName), `no such hook: ${hookName}`)
|
|
113
114
|
|
|
114
115
|
if (!this.#hooks[hookName]) {
|
|
115
116
|
this.#hooks[hookName] = []
|
|
@@ -119,13 +120,18 @@ class Application extends ExodusModule {
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
fire = async (hookName, params) => {
|
|
122
|
-
assert(HOOKS
|
|
123
|
+
assert(HOOKS.has(hookName), `no such hook: ${hookName}`)
|
|
123
124
|
this._logger.debug('firing hooks', hookName)
|
|
124
125
|
|
|
125
126
|
const hooks = this.#hooks[hookName] || []
|
|
126
127
|
|
|
127
128
|
for (let i = 0; i < hooks.length; i++) {
|
|
128
|
-
|
|
129
|
+
try {
|
|
130
|
+
await hooks[i](params)
|
|
131
|
+
} catch (err) {
|
|
132
|
+
this._logger.error(`application lifecycle hook failed: ${hookName}`, hooks[i], params)
|
|
133
|
+
throw err
|
|
134
|
+
}
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
this.emit(hookName, params)
|
|
@@ -137,7 +143,15 @@ class Application extends ExodusModule {
|
|
|
137
143
|
await this.#applicationStarted
|
|
138
144
|
await this.#wallet.create(opts)
|
|
139
145
|
|
|
140
|
-
await this.
|
|
146
|
+
const isLocked = await this.#wallet.isLocked()
|
|
147
|
+
|
|
148
|
+
await this.fire(Hook.Create, {
|
|
149
|
+
hasPassphraseSet: !!opts?.passphrase,
|
|
150
|
+
isBackedUp: false,
|
|
151
|
+
isLocked,
|
|
152
|
+
isRestoring: false,
|
|
153
|
+
walletExists: true,
|
|
154
|
+
})
|
|
141
155
|
}
|
|
142
156
|
|
|
143
157
|
import = async (opts) => {
|
|
@@ -149,16 +163,16 @@ class Application extends ExodusModule {
|
|
|
149
163
|
|
|
150
164
|
const walletExists = await this.#wallet.exists()
|
|
151
165
|
|
|
152
|
-
const { forceRestart, ...wallet } = opts
|
|
166
|
+
const { forceRestart, forgotPassphrase, ...wallet } = opts
|
|
153
167
|
|
|
154
168
|
await this.#wallet.import(wallet)
|
|
155
169
|
|
|
156
170
|
if (forceRestart || walletExists) {
|
|
157
171
|
await this.#storage.set(IMPORT_FLAG, true)
|
|
158
172
|
|
|
159
|
-
this.
|
|
173
|
+
await this.fire(Hook.Restart, { reason: 'import' })
|
|
160
174
|
} else {
|
|
161
|
-
await this.fire(
|
|
175
|
+
await this.fire(Hook.Import)
|
|
162
176
|
|
|
163
177
|
this._logger.log('wallet imported')
|
|
164
178
|
}
|
|
@@ -168,7 +182,7 @@ class Application extends ExodusModule {
|
|
|
168
182
|
|
|
169
183
|
setBackedUp = async () => {
|
|
170
184
|
await this.#wallet.setBackedUp()
|
|
171
|
-
await this.fire(
|
|
185
|
+
await this.fire(Hook.Backup)
|
|
172
186
|
}
|
|
173
187
|
|
|
174
188
|
lock = async (opts) => {
|
|
@@ -177,7 +191,7 @@ class Application extends ExodusModule {
|
|
|
177
191
|
await this.#applicationStarted
|
|
178
192
|
await this.#wallet.lock(opts)
|
|
179
193
|
await this.#passphraseCache.clear()
|
|
180
|
-
await this.fire(
|
|
194
|
+
await this.fire(Hook.Lock)
|
|
181
195
|
|
|
182
196
|
this._logger.log('locked')
|
|
183
197
|
}
|
|
@@ -186,13 +200,13 @@ class Application extends ExodusModule {
|
|
|
186
200
|
const isRestoring = await this.isRestoring()
|
|
187
201
|
|
|
188
202
|
if (isRestoring) {
|
|
189
|
-
await this.fire(
|
|
203
|
+
await this.fire(Hook.Restore)
|
|
190
204
|
await this.#storage.delete(RESTORE_FLAG)
|
|
191
205
|
await this.setBackedUp()
|
|
192
|
-
await this.fire(
|
|
206
|
+
await this.fire(Hook.RestoreCompleted)
|
|
193
207
|
}
|
|
194
208
|
|
|
195
|
-
this.fire(
|
|
209
|
+
this.fire(Hook.AssetsSynced)
|
|
196
210
|
}
|
|
197
211
|
|
|
198
212
|
#autoUnlock = async () => {
|
|
@@ -205,7 +219,9 @@ class Application extends ExodusModule {
|
|
|
205
219
|
this._logger.log('unlocking with cache')
|
|
206
220
|
|
|
207
221
|
await this.#wallet.unlock({ passphrase })
|
|
208
|
-
|
|
222
|
+
|
|
223
|
+
await this.fire(Hook.Migrate)
|
|
224
|
+
await this.fire(Hook.Unlock)
|
|
209
225
|
|
|
210
226
|
this.#restoreIfNeeded()
|
|
211
227
|
|
|
@@ -221,8 +237,8 @@ class Application extends ExodusModule {
|
|
|
221
237
|
await this.#applicationStarted
|
|
222
238
|
await this.#wallet.unlock({ passphrase })
|
|
223
239
|
|
|
224
|
-
await this.fire(
|
|
225
|
-
await this.fire(
|
|
240
|
+
await this.fire(Hook.Migrate)
|
|
241
|
+
await this.fire(Hook.Unlock)
|
|
226
242
|
|
|
227
243
|
this.#restoreIfNeeded()
|
|
228
244
|
|
|
@@ -237,14 +253,14 @@ class Application extends ExodusModule {
|
|
|
237
253
|
await this.#applicationStarted
|
|
238
254
|
await this.#wallet.changePassphrase({ currentPassphrase, newPassphrase })
|
|
239
255
|
await this.#passphraseCache.set(newPassphrase)
|
|
240
|
-
await this.fire(
|
|
256
|
+
await this.fire(Hook.ChangePassphrase)
|
|
241
257
|
|
|
242
258
|
this._logger.log('passphrase changed')
|
|
243
259
|
}
|
|
244
260
|
|
|
245
|
-
delete = async () => {
|
|
261
|
+
delete = async ({ forgotPassphrase } = {}) => {
|
|
246
262
|
await this.#storage.set(DELETE_FLAG, true)
|
|
247
|
-
this.
|
|
263
|
+
await this.fire(Hook.Restart, { reason: 'delete', forgotPassphrase })
|
|
248
264
|
}
|
|
249
265
|
|
|
250
266
|
changeLockTimer = async ({ ttl }) => {
|
package/src/atoms/attach.js
CHANGED
|
@@ -7,23 +7,12 @@ const emitAtomValue = async (opts) => {
|
|
|
7
7
|
export const emitFromAtoms = ({ atoms, port }) =>
|
|
8
8
|
Object.entries(atoms).forEach(async ([atomId, atom]) => emitAtomValue({ port, atomId, atom }))
|
|
9
9
|
|
|
10
|
-
const attachAtom = ({ port, application,
|
|
10
|
+
const attachAtom = ({ port, application, atom, atomId }) => {
|
|
11
11
|
let loaded = false
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
}
|
|
13
|
+
application.on('load', async () => {
|
|
14
|
+
loaded = true
|
|
15
|
+
await emitAtomValue({ port, atomId, atom })
|
|
27
16
|
})
|
|
28
17
|
|
|
29
18
|
atom.observe((value) => {
|
|
@@ -31,9 +20,9 @@ const attachAtom = ({ port, application, logger, atom, atomId, lifecycleEvents }
|
|
|
31
20
|
})
|
|
32
21
|
}
|
|
33
22
|
|
|
34
|
-
const attachAtoms = ({ port, application,
|
|
23
|
+
const attachAtoms = ({ port, application, atoms }) => {
|
|
35
24
|
for (const [atomId, atom] of Object.entries(atoms)) {
|
|
36
|
-
attachAtom({ port, application,
|
|
25
|
+
attachAtom({ port, application, atom, atomId })
|
|
37
26
|
}
|
|
38
27
|
}
|
|
39
28
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { combine, compute } from '@exodus/atoms'
|
|
2
|
+
import { uniq } from 'lodash'
|
|
3
|
+
|
|
4
|
+
const getNetworks = (assetNames, assets) =>
|
|
5
|
+
uniq(
|
|
6
|
+
assetNames
|
|
7
|
+
.map((assetName) => assets[assetName]?.baseAsset.name)
|
|
8
|
+
.filter((assetName) => !!assetName && !assets[assetName].isCombined)
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const createBaseAssetNamesToMonitorAtom = ({
|
|
12
|
+
assetsModule,
|
|
13
|
+
enabledAssetsAtom,
|
|
14
|
+
restoreAtom,
|
|
15
|
+
availableAssetNamesAtom,
|
|
16
|
+
}) => {
|
|
17
|
+
const selector = ({ isRestore, enabledAssets, availableAssetNames }) => {
|
|
18
|
+
const assetNames = isRestore ? availableAssetNames : Object.keys(enabledAssets)
|
|
19
|
+
return getNetworks(assetNames, assetsModule.getAssets())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return compute({
|
|
23
|
+
atom: combine({
|
|
24
|
+
isRestore: restoreAtom,
|
|
25
|
+
enabledAssets: enabledAssetsAtom,
|
|
26
|
+
availableAssetNames: availableAssetNamesAtom,
|
|
27
|
+
}),
|
|
28
|
+
selector,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line @exodus/export-default/named
|
|
33
|
+
export default {
|
|
34
|
+
id: 'baseAssetNamesToMonitorAtom',
|
|
35
|
+
type: 'atom',
|
|
36
|
+
factory: createBaseAssetNamesToMonitorAtom,
|
|
37
|
+
dependencies: ['assetsModule', 'availableAssetNamesAtom', 'enabledAssetsAtom', 'restoreAtom'],
|
|
38
|
+
}
|
package/src/constants.js
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
1
|
export const atomsToAttach = [
|
|
2
|
-
|
|
2
|
+
'abTestingAtom',
|
|
3
|
+
'apyRatesAtom',
|
|
3
4
|
'availableAssetNamesAtom',
|
|
5
|
+
'balancesAtom',
|
|
6
|
+
'connectedOriginsAtom',
|
|
7
|
+
'cryptoNewsAtom',
|
|
8
|
+
'currencyAtom',
|
|
9
|
+
'enabledWalletAccountsAtom',
|
|
10
|
+
'featureFlagsAtom',
|
|
11
|
+
'geolocationAtom',
|
|
12
|
+
'kycAtom',
|
|
13
|
+
'languageAtom',
|
|
14
|
+
'nftsConfigAtom',
|
|
15
|
+
'personalNotesAtom',
|
|
16
|
+
'referralsAtom',
|
|
17
|
+
'topMoversAtom',
|
|
18
|
+
'walletAccountsAtom',
|
|
19
|
+
'restoringAssetsAtom',
|
|
4
20
|
]
|
|
21
|
+
|
|
22
|
+
export const LifecycleHook = Object.freeze({
|
|
23
|
+
Lock: 'lock',
|
|
24
|
+
Unlock: 'unlock',
|
|
25
|
+
Clear: 'clear',
|
|
26
|
+
Import: 'import',
|
|
27
|
+
Migrate: 'migrate',
|
|
28
|
+
Start: 'start',
|
|
29
|
+
Restart: 'restart',
|
|
30
|
+
Load: 'load',
|
|
31
|
+
Unload: 'unload',
|
|
32
|
+
Create: 'create',
|
|
33
|
+
Backup: 'backup',
|
|
34
|
+
Restore: 'restore',
|
|
35
|
+
RestoreCompleted: 'restore-completed',
|
|
36
|
+
AssetsSynced: 'assets-synced',
|
|
37
|
+
ChangePassphrase: 'change-passphrase',
|
|
38
|
+
})
|
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
walletAccountsAtomDefinition,
|
|
4
|
-
enabledWalletAccountsAtomDefinition,
|
|
5
|
-
} from '@exodus/wallet-accounts/atoms'
|
|
1
|
+
import baseAssetNamesToMonitorAtomDefinition from '../atoms/base-asset-names-to-monitor'
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
enabledAndDisabledAssetsAtomDefinition,
|
|
9
|
-
enabledAssetsAtomDefinition,
|
|
10
|
-
} from '@exodus/enabled-assets/atoms'
|
|
11
|
-
|
|
12
|
-
import { availableAssetNamesAtomDefinition } from '@exodus/available-assets/atoms'
|
|
13
|
-
|
|
14
|
-
import { withType } from './utils'
|
|
15
|
-
|
|
16
|
-
const createAtomDependencies = () =>
|
|
17
|
-
[
|
|
18
|
-
{
|
|
19
|
-
definition: {
|
|
20
|
-
id: 'lockedAtom',
|
|
21
|
-
factory: () => createInMemoryAtom({ defaultValue: true }),
|
|
22
|
-
dependencies: [],
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
definition: walletAccountsAtomDefinition,
|
|
27
|
-
storage: { namespace: 'walletAccounts' },
|
|
28
|
-
},
|
|
29
|
-
{ definition: enabledWalletAccountsAtomDefinition },
|
|
30
|
-
{
|
|
31
|
-
definition: enabledAndDisabledAssetsAtomDefinition,
|
|
32
|
-
storage: { namespace: 'enabledAssets' },
|
|
33
|
-
},
|
|
34
|
-
{ definition: enabledAssetsAtomDefinition },
|
|
35
|
-
{ definition: availableAssetNamesAtomDefinition },
|
|
36
|
-
].map(withType('atom'))
|
|
3
|
+
const createAtomDependencies = () => [{ definition: baseAssetNamesToMonitorAtomDefinition }]
|
|
37
4
|
|
|
38
5
|
export default createAtomDependencies
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
import assert from 'minimalistic-assert'
|
|
5
5
|
|
|
6
|
-
import createConfigDependencies from './configs'
|
|
7
6
|
import createAdapterDependencies from './adapters'
|
|
8
7
|
import createAtomDependencies from './atoms'
|
|
8
|
+
import createConfigDependencies from './configs'
|
|
9
9
|
import createModuleDependencies from './modules'
|
|
10
|
-
import { wrapConstant } from './utils'
|
|
11
10
|
import createPluginDependencies from './plugins'
|
|
11
|
+
import { wrapConstant } from './utils'
|
|
12
12
|
|
|
13
13
|
const adapterKeys = [
|
|
14
14
|
// ...
|