@unisat/wallet-state 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +54 -0
- package/package.json +44 -0
- package/src/hooks/accounts.ts +244 -0
- package/src/hooks/global.ts +7 -0
- package/src/hooks/index.ts +15 -0
- package/src/hooks/keyrings.ts +7 -0
- package/src/hooks/settings.ts +7 -0
- package/src/hooks/transactions.ts +574 -0
- package/src/hooks/ui.ts +7 -0
- package/src/index.ts +5 -0
- package/src/slices/accounts.ts +282 -0
- package/src/slices/global.ts +52 -0
- package/src/slices/index.ts +10 -0
- package/src/slices/keyrings.ts +81 -0
- package/src/slices/settings.ts +71 -0
- package/src/slices/transactions.ts +255 -0
- package/src/slices/ui.ts +203 -0
- package/src/store/index.ts +43 -0
- package/src/types/index.ts +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 UniSat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
ADDITIONAL TERMS:
|
|
24
|
+
This software is primarily intended for use with UniSat products and internal
|
|
25
|
+
development purposes. Third-party usage is at your own risk. UniSat does not
|
|
26
|
+
provide support or warranty for external usage of this toolkit.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @unisat/wallet-state
|
|
2
|
+
|
|
3
|
+
Redux state management for UniSat wallet, designed to be shared between browser extension and mobile applications.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🔄 Cross-platform Redux store configuration
|
|
8
|
+
- 🏪 Typed state slices for all wallet data
|
|
9
|
+
- 🪝 Typed React hooks for state access
|
|
10
|
+
- 🔧 Flexible middleware and persistence configuration
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import { createWalletStore, useAccountsState, useWalletDispatch } from '@unisat/wallet-state';
|
|
16
|
+
|
|
17
|
+
// Create store with platform-specific persistence
|
|
18
|
+
const store = createWalletStore({
|
|
19
|
+
persistedKeys: ['ui', 'settings'],
|
|
20
|
+
middleware: [/* platform-specific middleware */]
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Use in React components
|
|
24
|
+
function WalletComponent() {
|
|
25
|
+
const accounts = useAccountsState();
|
|
26
|
+
const dispatch = useWalletDispatch();
|
|
27
|
+
|
|
28
|
+
// Component logic...
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
This package contains the Redux state management logic extracted from the browser extension, designed to be reused in the mobile application.
|
|
35
|
+
|
|
36
|
+
### Store
|
|
37
|
+
- `createWalletStore()` - Configurable store factory with platform-specific options
|
|
38
|
+
|
|
39
|
+
### Slices
|
|
40
|
+
- `accounts` - Account and keyring data
|
|
41
|
+
- `transactions` - Transaction history and pending transactions
|
|
42
|
+
- `settings` - User preferences and configuration
|
|
43
|
+
- `global` - Global application state
|
|
44
|
+
- `keyrings` - Keyring management state
|
|
45
|
+
- `ui` - UI-specific state (modals, navigation, etc.)
|
|
46
|
+
|
|
47
|
+
### Hooks
|
|
48
|
+
- Typed React hooks for each state slice
|
|
49
|
+
- `useWalletDispatch` - Typed dispatch hook
|
|
50
|
+
- `useWalletSelector` - Typed selector hook
|
|
51
|
+
|
|
52
|
+
## Migration Notes
|
|
53
|
+
|
|
54
|
+
The actual state structures and reducers are placeholders and will be populated by migrating the existing Redux logic from the extension and mobile applications.
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unisat/wallet-state",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Redux state management for UniSat wallet, shared between platforms",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"module": "lib/index.mjs",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./lib/index.mjs",
|
|
11
|
+
"require": "./lib/index.js",
|
|
12
|
+
"types": "./lib/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"lib",
|
|
17
|
+
"src"
|
|
18
|
+
],
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@reduxjs/toolkit": "^1.9.0",
|
|
21
|
+
"react": "^18.0.0",
|
|
22
|
+
"react-redux": "^8.0.0",
|
|
23
|
+
"@unisat/wallet-types": "1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/node": "^20.0.0",
|
|
27
|
+
"@types/react": "^18.0.0",
|
|
28
|
+
"eslint": "^8.0.0",
|
|
29
|
+
"tsup": "^7.0.0",
|
|
30
|
+
"typescript": "^5.0.0",
|
|
31
|
+
"vitest": "^0.34.0"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"build:cjs": "tsup --format cjs",
|
|
39
|
+
"build:esm": "tsup --format esm",
|
|
40
|
+
"build:typed": "tsc --declaration --declarationMap --emitDeclarationOnly --outDir lib",
|
|
41
|
+
"test": "vitest",
|
|
42
|
+
"lint": "eslint src"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
|
|
3
|
+
import { Account, AddressType } from '@/shared/types'
|
|
4
|
+
import { useWallet } from '@/ui/utils'
|
|
5
|
+
import { KeyringType } from '@unisat/keyring-service/types'
|
|
6
|
+
|
|
7
|
+
import { AppState } from '..'
|
|
8
|
+
import { useAppDispatch, useAppSelector } from '../hooks'
|
|
9
|
+
import { useCurrentKeyring } from '../keyrings/hooks'
|
|
10
|
+
import { keyringsActions } from '../keyrings/reducer'
|
|
11
|
+
import { settingsActions } from '../settings/reducer'
|
|
12
|
+
import { accountActions } from './reducer'
|
|
13
|
+
|
|
14
|
+
export function useAccountsState(): AppState['accounts'] {
|
|
15
|
+
return useAppSelector(state => state.accounts)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function useCurrentAccount() {
|
|
19
|
+
const accountsState = useAccountsState()
|
|
20
|
+
return accountsState.current
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useCurrentAddress() {
|
|
24
|
+
const accountsState = useAccountsState()
|
|
25
|
+
return accountsState.current.address
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useAccounts() {
|
|
29
|
+
const accountsState = useAccountsState()
|
|
30
|
+
return accountsState.accounts
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useAccountBalance() {
|
|
34
|
+
const accountsState = useAccountsState()
|
|
35
|
+
const currentAccount = useCurrentAccount()
|
|
36
|
+
return (
|
|
37
|
+
accountsState.balanceV2Map[currentAccount.address] || {
|
|
38
|
+
availableBalance: 0,
|
|
39
|
+
unavailableBalance: 0,
|
|
40
|
+
totalBalance: 0,
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function useAddressSummary() {
|
|
46
|
+
const accountsState = useAccountsState()
|
|
47
|
+
return accountsState.addressSummary
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function useAccountInscriptions() {
|
|
51
|
+
const accountsState = useAccountsState()
|
|
52
|
+
const currentAccount = useCurrentAccount()
|
|
53
|
+
return accountsState.inscriptionsMap[currentAccount.address] || { list: [], expired: true }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function useInscriptionSummary() {
|
|
57
|
+
const accountsState = useAccountsState()
|
|
58
|
+
return accountsState.inscriptionSummary
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function useAppSummary() {
|
|
62
|
+
const accountsState = useAccountsState()
|
|
63
|
+
return accountsState.appSummary
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function useUnreadAppSummary() {
|
|
67
|
+
const accountsState = useAccountsState()
|
|
68
|
+
const summary = accountsState.appSummary
|
|
69
|
+
return summary.apps.find(w => w.time && summary.readTabTime && w.time > summary.readTabTime)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function useReadTab() {
|
|
73
|
+
const wallet = useWallet()
|
|
74
|
+
const dispatch = useAppDispatch()
|
|
75
|
+
const appSummary = useAppSummary()
|
|
76
|
+
return useCallback(
|
|
77
|
+
async (name: 'app' | 'home' | 'settings') => {
|
|
78
|
+
await wallet.readTab(name)
|
|
79
|
+
if (name == 'app') {
|
|
80
|
+
const appSummary = await wallet.getAppSummary()
|
|
81
|
+
dispatch(accountActions.setAppSummary(appSummary))
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
[dispatch, wallet, appSummary]
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function useReadApp() {
|
|
89
|
+
const wallet = useWallet()
|
|
90
|
+
const dispatch = useAppDispatch()
|
|
91
|
+
const appSummary = useAppSummary()
|
|
92
|
+
return useCallback(
|
|
93
|
+
async (id: number) => {
|
|
94
|
+
await wallet.readApp(id)
|
|
95
|
+
const appSummary = await wallet.getAppSummary()
|
|
96
|
+
dispatch(accountActions.setAppSummary(appSummary))
|
|
97
|
+
},
|
|
98
|
+
[dispatch, wallet, appSummary]
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function useHistory() {
|
|
103
|
+
const accountsState = useAccountsState()
|
|
104
|
+
const address = useAccountAddress()
|
|
105
|
+
return accountsState.historyMap[address] || { list: [], expired: true }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function useAccountAddress() {
|
|
109
|
+
const currentAccount = useCurrentAccount()
|
|
110
|
+
return currentAccount.address
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function useSetCurrentAccountCallback() {
|
|
114
|
+
const dispatch = useAppDispatch()
|
|
115
|
+
return useCallback(
|
|
116
|
+
(account: Account) => {
|
|
117
|
+
dispatch(accountActions.setCurrent(account))
|
|
118
|
+
},
|
|
119
|
+
[dispatch]
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function useImportAccountCallback() {
|
|
124
|
+
const wallet = useWallet()
|
|
125
|
+
const dispatch = useAppDispatch()
|
|
126
|
+
const currentKeyring = useCurrentKeyring()
|
|
127
|
+
return useCallback(
|
|
128
|
+
async (privateKey: string, addressType: AddressType) => {
|
|
129
|
+
let success = false
|
|
130
|
+
let error
|
|
131
|
+
try {
|
|
132
|
+
const alianName = await wallet.getNextAlianName(currentKeyring)
|
|
133
|
+
await wallet.createKeyringWithPrivateKey(privateKey, addressType, alianName)
|
|
134
|
+
const currentAccount = await wallet.getCurrentAccount()
|
|
135
|
+
dispatch(accountActions.setCurrent(currentAccount))
|
|
136
|
+
|
|
137
|
+
success = true
|
|
138
|
+
} catch (e) {
|
|
139
|
+
console.log(e)
|
|
140
|
+
error = (e as any).message
|
|
141
|
+
}
|
|
142
|
+
return { success, error }
|
|
143
|
+
},
|
|
144
|
+
[dispatch, wallet, currentKeyring]
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function useChangeAddressFlagCallback() {
|
|
149
|
+
const dispatch = useAppDispatch()
|
|
150
|
+
const wallet = useWallet()
|
|
151
|
+
const currentAccount = useCurrentAccount()
|
|
152
|
+
return useCallback(
|
|
153
|
+
async (isAdd: boolean, flag: number) => {
|
|
154
|
+
const account = isAdd
|
|
155
|
+
? await wallet.addAddressFlag(currentAccount, flag)
|
|
156
|
+
: await wallet.removeAddressFlag(currentAccount, flag)
|
|
157
|
+
dispatch(accountActions.setCurrentAddressFlag(account.flag))
|
|
158
|
+
},
|
|
159
|
+
[dispatch, wallet, currentAccount]
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// export function useFetchHistoryCallback() {
|
|
164
|
+
// const dispatch = useAppDispatch();
|
|
165
|
+
// const wallet = useWallet();
|
|
166
|
+
// const address = useAccountAddress();
|
|
167
|
+
// return useCallback(async () => {
|
|
168
|
+
// const _accountHistory = await wallet.getAddressHistory(address);
|
|
169
|
+
// dispatch(
|
|
170
|
+
// accountActions.setHistory({
|
|
171
|
+
// address: address,
|
|
172
|
+
// list: _accountHistory
|
|
173
|
+
// })
|
|
174
|
+
// );
|
|
175
|
+
// }, [dispatch, wallet, address]);
|
|
176
|
+
// }
|
|
177
|
+
|
|
178
|
+
export function useFetchBalanceCallback() {
|
|
179
|
+
const dispatch = useAppDispatch()
|
|
180
|
+
const wallet = useWallet()
|
|
181
|
+
const currentAccount = useCurrentAccount()
|
|
182
|
+
const balance = useAccountBalance()
|
|
183
|
+
return useCallback(async () => {
|
|
184
|
+
if (!currentAccount.address) return
|
|
185
|
+
// const cachedBalance = await wallet.getAddressCacheBalance(currentAccount.address);
|
|
186
|
+
// const _accountBalance = await wallet.getAddressBalance(currentAccount.address);
|
|
187
|
+
// dispatch(
|
|
188
|
+
// accountActions.setBalance({
|
|
189
|
+
// address: currentAccount.address,
|
|
190
|
+
// amount: _accountBalance.amount,
|
|
191
|
+
// btc_amount: _accountBalance.btc_amount,
|
|
192
|
+
// inscription_amount: _accountBalance.inscription_amount,
|
|
193
|
+
// confirm_btc_amount: _accountBalance.confirm_btc_amount,
|
|
194
|
+
// pending_btc_amount: _accountBalance.pending_btc_amount
|
|
195
|
+
// })
|
|
196
|
+
// );
|
|
197
|
+
// if (cachedBalance.amount !== _accountBalance.amount) {
|
|
198
|
+
// wallet.expireUICachedData(currentAccount.address);
|
|
199
|
+
// dispatch(accountActions.expireHistory());
|
|
200
|
+
// }
|
|
201
|
+
|
|
202
|
+
const summary = await wallet.getAddressSummary(currentAccount.address)
|
|
203
|
+
summary.address = currentAccount.address
|
|
204
|
+
dispatch(accountActions.setAddressSummary(summary))
|
|
205
|
+
|
|
206
|
+
const balanceV2 = await wallet.getAddressBalanceV2(currentAccount.address)
|
|
207
|
+
dispatch(
|
|
208
|
+
accountActions.setBalanceV2({
|
|
209
|
+
address: currentAccount.address,
|
|
210
|
+
balance: balanceV2,
|
|
211
|
+
})
|
|
212
|
+
)
|
|
213
|
+
}, [dispatch, wallet, currentAccount, balance])
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function useReloadAccounts() {
|
|
217
|
+
const dispatch = useAppDispatch()
|
|
218
|
+
const wallet = useWallet()
|
|
219
|
+
return useCallback(async () => {
|
|
220
|
+
const keyrings = await wallet.getKeyrings()
|
|
221
|
+
dispatch(keyringsActions.setKeyrings(keyrings))
|
|
222
|
+
|
|
223
|
+
const currentKeyring = await wallet.getCurrentKeyring()
|
|
224
|
+
dispatch(keyringsActions.setCurrent(currentKeyring))
|
|
225
|
+
|
|
226
|
+
const _accounts = await wallet.getAccounts()
|
|
227
|
+
dispatch(accountActions.setAccounts(_accounts))
|
|
228
|
+
|
|
229
|
+
const account = await wallet.getCurrentAccount()
|
|
230
|
+
dispatch(accountActions.setCurrent(account))
|
|
231
|
+
|
|
232
|
+
dispatch(accountActions.expireBalance())
|
|
233
|
+
dispatch(accountActions.expireInscriptions())
|
|
234
|
+
|
|
235
|
+
wallet.getWalletConfig().then(data => {
|
|
236
|
+
dispatch(settingsActions.updateSettings({ walletConfig: data }))
|
|
237
|
+
})
|
|
238
|
+
}, [dispatch, wallet])
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function useIsKeystoneWallet() {
|
|
242
|
+
const currentKeyring = useCurrentKeyring()
|
|
243
|
+
return currentKeyring.type === KeyringType.KeystoneKeyring
|
|
244
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useDispatch, useSelector, TypedUseSelectorHook } from 'react-redux';
|
|
2
|
+
import type { WalletDispatch } from '../store';
|
|
3
|
+
import type { AppState } from '../types';
|
|
4
|
+
|
|
5
|
+
// Typed hooks for the wallet store
|
|
6
|
+
export const useWalletDispatch = () => useDispatch<WalletDispatch>();
|
|
7
|
+
export const useWalletSelector: TypedUseSelectorHook<AppState> = useSelector;
|
|
8
|
+
|
|
9
|
+
// Re-export common hooks that will be migrated from existing code
|
|
10
|
+
export * from './accounts';
|
|
11
|
+
export * from './transactions';
|
|
12
|
+
export * from './settings';
|
|
13
|
+
export * from './global';
|
|
14
|
+
export * from './keyrings';
|
|
15
|
+
export * from './ui';
|