@interchain-kit/store 0.3.47
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 +21 -0
- package/README.md +70 -0
- package/esm/index.js +3 -0
- package/esm/proxied-wallets/cosmos-wallet.js +51 -0
- package/esm/proxied-wallets/create-proxied-wallet.js +30 -0
- package/esm/proxied-wallets/ethereum-wallet.js +24 -0
- package/esm/proxied-wallets/index.js +5 -0
- package/esm/proxied-wallets/multi-chain-wallet.js +27 -0
- package/esm/store/index.js +125 -0
- package/esm/types/index.js +1 -0
- package/esm/types/store.js +1 -0
- package/esm/utils/aop.js +172 -0
- package/esm/utils/index.js +1 -0
- package/esm/utils/local-storage.js +9 -0
- package/esm/wallet-manager/chain-wallet-store.js +111 -0
- package/esm/wallet-manager/index.js +3 -0
- package/esm/wallet-manager/wallet-manager-store.js +230 -0
- package/esm/wallet-manager/wallet-store.js +99 -0
- package/index.d.ts +3 -0
- package/index.js +19 -0
- package/package.json +35 -0
- package/proxied-wallets/cosmos-wallet.d.ts +3 -0
- package/proxied-wallets/cosmos-wallet.js +55 -0
- package/proxied-wallets/create-proxied-wallet.d.ts +2 -0
- package/proxied-wallets/create-proxied-wallet.js +34 -0
- package/proxied-wallets/ethereum-wallet.d.ts +3 -0
- package/proxied-wallets/ethereum-wallet.js +28 -0
- package/proxied-wallets/index.d.ts +4 -0
- package/proxied-wallets/index.js +21 -0
- package/proxied-wallets/multi-chain-wallet.d.ts +3 -0
- package/proxied-wallets/multi-chain-wallet.js +31 -0
- package/store/index.d.ts +21 -0
- package/store/index.js +129 -0
- package/types/index.d.ts +1 -0
- package/types/index.js +17 -0
- package/types/store.d.ts +17 -0
- package/types/store.js +2 -0
- package/utils/aop.d.ts +58 -0
- package/utils/aop.js +178 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +17 -0
- package/utils/local-storage.d.ts +5 -0
- package/utils/local-storage.js +13 -0
- package/wallet-manager/chain-wallet-store.d.ts +22 -0
- package/wallet-manager/chain-wallet-store.js +115 -0
- package/wallet-manager/index.d.ts +3 -0
- package/wallet-manager/index.js +19 -0
- package/wallet-manager/wallet-manager-store.d.ts +58 -0
- package/wallet-manager/wallet-manager-store.js +234 -0
- package/wallet-manager/wallet-store.d.ts +21 -0
- package/wallet-manager/wallet-store.js +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Cosmology Developers <developers@hyperweb.io>
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
> **⚠️ UPGRADE TO 2.0**
|
|
2
|
+
>
|
|
3
|
+
> **Create Cosmos App 2.0 is here!** This package has been superseded by the new version.
|
|
4
|
+
>
|
|
5
|
+
> Please upgrade to [**Create Interchain App**](https://github.com/hyperweb-io/create-interchain-app) (Create Cosmos App 2.0), featuring enhanced capabilities and expanded Interchain ecosystem support.
|
|
6
|
+
|
|
7
|
+
# **MODULENAME**
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<img src="https://user-images.githubusercontent.com/545047/188804067-28e67e5e-0214-4449-ab04-2e0c564a6885.svg" width="80"><br />
|
|
11
|
+
interchain-kit wallet connector store package
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
## install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install store
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Table of contents
|
|
21
|
+
|
|
22
|
+
- [**MODULENAME**](#store)
|
|
23
|
+
- [Install](#install)
|
|
24
|
+
- [Table of contents](#table-of-contents)
|
|
25
|
+
- [Developing](#developing)
|
|
26
|
+
- [Credits](#credits)
|
|
27
|
+
|
|
28
|
+
## Developing
|
|
29
|
+
|
|
30
|
+
When first cloning the repo:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
yarn
|
|
34
|
+
# build the prod packages. When devs would like to navigate to the source code, this will only navigate from references to their definitions (.d.ts files) between packages.
|
|
35
|
+
yarn build
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or if you want to make your dev process smoother, you can run:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
yarn
|
|
42
|
+
# build the dev packages with .map files, this enables navigation from references to their source code between packages.
|
|
43
|
+
yarn build:dev
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Interchain JavaScript Stack
|
|
47
|
+
|
|
48
|
+
A unified toolkit for building applications and smart contracts in the Interchain ecosystem ⚛️
|
|
49
|
+
|
|
50
|
+
| Category | Tools | Description |
|
|
51
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| **Chain Information** | [**Chain Registry**](https://github.com/hyperweb-io/chain-registry), [**Utils**](https://www.npmjs.com/package/@chain-registry/utils), [**Client**](https://www.npmjs.com/package/@chain-registry/client) | Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application. |
|
|
53
|
+
| **Wallet Connectors** | [**Interchain Kit**](https://github.com/hyperweb-io/interchain-kit)<sup>beta</sup>, [**Cosmos Kit**](https://github.com/hyperweb-io/cosmos-kit) | Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface. |
|
|
54
|
+
| **Signing Clients** | [**InterchainJS**](https://github.com/hyperweb-io/interchainjs)<sup>beta</sup>, [**CosmJS**](https://github.com/cosmos/cosmjs) | A single, universal signing interface for any network |
|
|
55
|
+
| **SDK Clients** | [**Telescope**](https://github.com/hyperweb-io/telescope) | Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules. |
|
|
56
|
+
| **Starter Kits** | [**Create Interchain App**](https://github.com/hyperweb-io/create-interchain-app)<sup>beta</sup>, [**Create Cosmos App**](https://github.com/hyperweb-io/create-cosmos-app) | Set up a modern Interchain app by running one command. |
|
|
57
|
+
| **UI Kits** | [**Interchain UI**](https://github.com/hyperweb-io/interchain-ui) | The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit. |
|
|
58
|
+
| **Testing Frameworks** | [**Starship**](https://github.com/hyperweb-io/starship) | Unified Testing and Development for the Interchain. |
|
|
59
|
+
| **TypeScript Smart Contracts** | [**Create Hyperweb App**](https://github.com/hyperweb-io/create-hyperweb-app) | Build and deploy full-stack blockchain applications with TypeScript |
|
|
60
|
+
| **CosmWasm Contracts** | [**CosmWasm TS Codegen**](https://github.com/CosmWasm/ts-codegen) | Convert your CosmWasm smart contracts into dev-friendly TypeScript classes. |
|
|
61
|
+
|
|
62
|
+
## Credits
|
|
63
|
+
|
|
64
|
+
🛠 Built by Hyperweb (formerly Cosmology) — if you like our tools, please checkout and contribute to [our github ⚛️](https://github.com/hyperweb-io)
|
|
65
|
+
|
|
66
|
+
## Disclaimer
|
|
67
|
+
|
|
68
|
+
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
|
|
69
|
+
|
|
70
|
+
No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createAOPProxy } from '../utils';
|
|
2
|
+
export const createCosmosWallet = (target, store) => {
|
|
3
|
+
return createAOPProxy({
|
|
4
|
+
target,
|
|
5
|
+
advice: {
|
|
6
|
+
signAmino: {
|
|
7
|
+
before(methodName, target, chainId, signer, signDoc, signOptions) {
|
|
8
|
+
console.log('signAmino before - AOP proxy is working!', methodName, chainId);
|
|
9
|
+
},
|
|
10
|
+
onError(methodName, target, error, chainId, signer, signDoc, signOptions) {
|
|
11
|
+
console.log('signAmino onError - AOP caught error!', error, chainId);
|
|
12
|
+
const chain = target.getChainById(chainId);
|
|
13
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { errorMessage: error.message });
|
|
14
|
+
throw error; // 重新抛出错误
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
signDirect: {
|
|
18
|
+
async around(methodName, target, originalMethod, chainId, signer, signDoc, signOptions) {
|
|
19
|
+
console.log('signDirect around - AOP is working!', methodName, chainId);
|
|
20
|
+
try {
|
|
21
|
+
const result = await originalMethod(chainId, signer, signDoc, signOptions);
|
|
22
|
+
console.log('signDirect success - AOP is working!', methodName, chainId);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.log('signDirect error - AOP caught the error!', error, chainId);
|
|
27
|
+
const chain = target.getChainById(chainId);
|
|
28
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { errorMessage: error.message });
|
|
29
|
+
throw error; // 重新抛出错误
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
signArbitrary: {
|
|
34
|
+
async around(methodName, target, originalMethod, chainId, signer, data) {
|
|
35
|
+
console.log('signArbitrary around - AOP is working!', methodName, chainId);
|
|
36
|
+
try {
|
|
37
|
+
const result = await originalMethod(chainId, signer, data);
|
|
38
|
+
console.log('signArbitrary success - AOP is working!', methodName, chainId);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.log('signArbitrary error - AOP caught the error!', error, chainId);
|
|
43
|
+
const chain = target.getChainById(chainId);
|
|
44
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { errorMessage: error.message });
|
|
45
|
+
throw error; // 重新抛出错误
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isInstanceOf } from '@interchain-kit/core';
|
|
2
|
+
import { CosmosWallet, EthereumWallet, MultiChainWallet } from '@interchain-kit/core';
|
|
3
|
+
import { createCosmosWallet } from './cosmos-wallet';
|
|
4
|
+
import { createEthereumWallet } from './ethereum-wallet';
|
|
5
|
+
import { createMultiChainWallet } from './multi-chain-wallet';
|
|
6
|
+
// import { createWCWallet } from './wc-wallet';
|
|
7
|
+
export const createProxiedWallet = (wallet, store) => {
|
|
8
|
+
// WalletConnect wallets are now handled by the generic AOP system
|
|
9
|
+
// No need for special handling
|
|
10
|
+
if (isInstanceOf(wallet, CosmosWallet)) {
|
|
11
|
+
return createCosmosWallet(wallet, store);
|
|
12
|
+
}
|
|
13
|
+
if (isInstanceOf(wallet, EthereumWallet)) {
|
|
14
|
+
return createEthereumWallet(wallet, store);
|
|
15
|
+
}
|
|
16
|
+
if (isInstanceOf(wallet, MultiChainWallet)) {
|
|
17
|
+
Array.from(wallet.networkWalletMap.keys()).forEach(chainType => {
|
|
18
|
+
const chainWallet = wallet.networkWalletMap.get(chainType);
|
|
19
|
+
if (isInstanceOf(chainWallet, CosmosWallet)) {
|
|
20
|
+
wallet.setNetworkWallet(chainType, createCosmosWallet(chainWallet, store));
|
|
21
|
+
}
|
|
22
|
+
if (isInstanceOf(chainWallet, EthereumWallet)) {
|
|
23
|
+
wallet.setNetworkWallet(chainType, createEthereumWallet(chainWallet, store));
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return createMultiChainWallet(wallet, store);
|
|
27
|
+
}
|
|
28
|
+
// Return original wallet if no specific type matches
|
|
29
|
+
return wallet;
|
|
30
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createAOPProxy } from '../utils';
|
|
2
|
+
export const createEthereumWallet = (target, store) => {
|
|
3
|
+
return createAOPProxy({
|
|
4
|
+
target,
|
|
5
|
+
advice: {
|
|
6
|
+
sendTransaction: {
|
|
7
|
+
onError(methodName, target, error, transactionParameters) {
|
|
8
|
+
const chain = target.getChainById(transactionParameters.chainId);
|
|
9
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { errorMessage: error.message });
|
|
10
|
+
throw error; // 重新抛出错误
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
signMessage: {
|
|
14
|
+
onError(methodName, target, error, message) {
|
|
15
|
+
target.getCurrentChainId().then(chainId => {
|
|
16
|
+
const chain = target.getChainById(chainId);
|
|
17
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { errorMessage: error.message });
|
|
18
|
+
});
|
|
19
|
+
throw error; // 重新抛出错误
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { WalletState } from '@interchain-kit/core';
|
|
2
|
+
import { createAOPProxy } from '../utils/aop';
|
|
3
|
+
export const createMultiChainWallet = (target, store) => {
|
|
4
|
+
return createAOPProxy({
|
|
5
|
+
target,
|
|
6
|
+
advice: {
|
|
7
|
+
connect: {
|
|
8
|
+
async around(methodName, target, originalMethod, chainId) {
|
|
9
|
+
const chain = target.getChainById(chainId);
|
|
10
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { walletState: WalletState.Connecting });
|
|
11
|
+
await originalMethod(chainId);
|
|
12
|
+
const account = await target.getAccount(chainId);
|
|
13
|
+
store.updateChainWalletState(target.info.name, chain.chainName, {
|
|
14
|
+
walletState: WalletState.Connected,
|
|
15
|
+
account
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
disconnect: {
|
|
20
|
+
after(methodName, target, result, chainId) {
|
|
21
|
+
const chain = target.getChainById(chainId);
|
|
22
|
+
store.updateChainWalletState(target.info.name, chain.chainName, { walletState: WalletState.Disconnected });
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { WalletState } from '@interchain-kit/core';
|
|
2
|
+
export class InterchainStore {
|
|
3
|
+
state;
|
|
4
|
+
listeners = new Set();
|
|
5
|
+
// 快速查找索引的 Map: walletName-chainName -> index
|
|
6
|
+
chainWalletIndexMap = new Map();
|
|
7
|
+
constructor() {
|
|
8
|
+
this.state = {
|
|
9
|
+
currentWalletName: '',
|
|
10
|
+
currentChainName: '',
|
|
11
|
+
chainWalletStates: [],
|
|
12
|
+
isReady: false,
|
|
13
|
+
modalIsOpen: false,
|
|
14
|
+
walletConnectQRCodeUri: '',
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// Get current state
|
|
18
|
+
getState() {
|
|
19
|
+
return this.state;
|
|
20
|
+
}
|
|
21
|
+
// Subscribe to state changes
|
|
22
|
+
subscribe(listener) {
|
|
23
|
+
this.listeners.add(listener);
|
|
24
|
+
// Return unsubscribe function
|
|
25
|
+
return () => {
|
|
26
|
+
this.listeners.delete(listener);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Emit state changes to all listeners
|
|
30
|
+
emit() {
|
|
31
|
+
this.listeners.forEach(listener => {
|
|
32
|
+
try {
|
|
33
|
+
listener(this.state);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error('Error in store listener:', error);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Update state and emit changes
|
|
41
|
+
setState(newState) {
|
|
42
|
+
this.state = { ...this.state, ...newState };
|
|
43
|
+
this.emit();
|
|
44
|
+
}
|
|
45
|
+
// Update partial state and emit changes
|
|
46
|
+
updateState(partialState) {
|
|
47
|
+
this.state = { ...this.state, ...partialState };
|
|
48
|
+
this.emit();
|
|
49
|
+
}
|
|
50
|
+
setCurrentChainName(chainName) {
|
|
51
|
+
this.setState({ ...this.state, currentChainName: chainName });
|
|
52
|
+
}
|
|
53
|
+
setCurrentWalletName(walletName) {
|
|
54
|
+
this.setState({ ...this.state, currentWalletName: walletName });
|
|
55
|
+
}
|
|
56
|
+
updateChainWalletState(walletName, chainName, state) {
|
|
57
|
+
const key = `${walletName}-${chainName}`;
|
|
58
|
+
const index = this.chainWalletIndexMap.get(key);
|
|
59
|
+
if (index !== undefined) {
|
|
60
|
+
// 直接通过索引更新,避免遍历
|
|
61
|
+
const newChainWalletStates = [...this.state.chainWalletStates];
|
|
62
|
+
newChainWalletStates[index] = { ...newChainWalletStates[index], ...state };
|
|
63
|
+
this.setState({ ...this.state, chainWalletStates: newChainWalletStates });
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.addChainWalletState(walletName, chainName, state);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// 添加新的 chain wallet state
|
|
70
|
+
addChainWalletState(walletName, chainName, state) {
|
|
71
|
+
const newChainWalletState = [...this.state.chainWalletStates];
|
|
72
|
+
const newIndex = newChainWalletState.length;
|
|
73
|
+
newChainWalletState.push({
|
|
74
|
+
chainName,
|
|
75
|
+
walletName,
|
|
76
|
+
walletState: WalletState.Disconnected,
|
|
77
|
+
rpcEndpoint: '', errorMessage: '', account: undefined, ...state
|
|
78
|
+
});
|
|
79
|
+
// 更新索引映射
|
|
80
|
+
const key = `${walletName}-${chainName}`;
|
|
81
|
+
this.chainWalletIndexMap.set(key, newIndex);
|
|
82
|
+
this.setState({ ...this.state, chainWalletStates: newChainWalletState });
|
|
83
|
+
}
|
|
84
|
+
// 移除 chain wallet state
|
|
85
|
+
removeChainWalletState(walletName, chainName) {
|
|
86
|
+
const key = `${walletName}-${chainName}`;
|
|
87
|
+
const index = this.chainWalletIndexMap.get(key);
|
|
88
|
+
if (index !== undefined) {
|
|
89
|
+
const newChainWalletState = this.state.chainWalletStates.filter((_, i) => i !== index);
|
|
90
|
+
// 重新构建索引映射
|
|
91
|
+
this.chainWalletIndexMap.clear();
|
|
92
|
+
newChainWalletState.forEach((item, i) => {
|
|
93
|
+
const itemKey = `${item.walletName}-${item.chainName}`;
|
|
94
|
+
this.chainWalletIndexMap.set(itemKey, i);
|
|
95
|
+
});
|
|
96
|
+
this.setState({ ...this.state, chainWalletStates: newChainWalletState });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// 获取指定 chain 的 wallet state
|
|
100
|
+
getChainWalletState(walletName, chainName) {
|
|
101
|
+
const key = `${walletName}-${chainName}`;
|
|
102
|
+
const index = this.chainWalletIndexMap.get(key);
|
|
103
|
+
return index !== undefined ? this.state.chainWalletStates[index] : undefined;
|
|
104
|
+
}
|
|
105
|
+
// 恢复索引映射(用于从localStorage恢复数据后重建索引)
|
|
106
|
+
buildIndexMap() {
|
|
107
|
+
this.chainWalletIndexMap.clear();
|
|
108
|
+
this.state.chainWalletStates.forEach((item, index) => {
|
|
109
|
+
const key = `${item.walletName}-${item.chainName}`;
|
|
110
|
+
this.chainWalletIndexMap.set(key, index);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
updateWalletState(walletName, state) {
|
|
114
|
+
const newChainWalletStates = this.state.chainWalletStates.map(cws => {
|
|
115
|
+
if (cws.walletName === walletName) {
|
|
116
|
+
return { ...cws, ...state };
|
|
117
|
+
}
|
|
118
|
+
return cws;
|
|
119
|
+
});
|
|
120
|
+
this.setState({ chainWalletStates: newChainWalletStates });
|
|
121
|
+
}
|
|
122
|
+
isChainWalletStateExisted(walletName, chainName) {
|
|
123
|
+
return this.chainWalletIndexMap.get(`${walletName}-${chainName}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './store';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/esm/utils/aop.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AOP (Aspect-Oriented Programming) implementation similar to Java AOP
|
|
3
|
+
* Using Object.create, Object.getOwnPropertyNames, and Object.getPrototypeOf
|
|
4
|
+
*/
|
|
5
|
+
export class AOPProxy {
|
|
6
|
+
target;
|
|
7
|
+
advice;
|
|
8
|
+
defaultAdvice;
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.target = config.target;
|
|
11
|
+
this.advice = config.advice;
|
|
12
|
+
this.defaultAdvice = config.defaultAdvice;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get advice for a specific method
|
|
16
|
+
*/
|
|
17
|
+
getMethodAdvice(methodName) {
|
|
18
|
+
return this.advice[methodName] || this.defaultAdvice;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Collect all property names from the instance and its prototype chain
|
|
22
|
+
* (excluding Object.prototype). This allows intercepting prototype methods
|
|
23
|
+
* in addition to own instance methods.
|
|
24
|
+
*/
|
|
25
|
+
getAllMemberNames() {
|
|
26
|
+
const names = new Set();
|
|
27
|
+
// Own properties (instance fields and own methods)
|
|
28
|
+
Object.getOwnPropertyNames(this.target).forEach((name) => {
|
|
29
|
+
names.add(name);
|
|
30
|
+
});
|
|
31
|
+
// Prototype chain methods
|
|
32
|
+
let proto = Object.getPrototypeOf(this.target);
|
|
33
|
+
while (proto && proto !== Object.prototype) {
|
|
34
|
+
Object.getOwnPropertyNames(proto).forEach((name) => {
|
|
35
|
+
if (name !== 'constructor') {
|
|
36
|
+
names.add(name);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
proto = Object.getPrototypeOf(proto);
|
|
40
|
+
}
|
|
41
|
+
return Array.from(names);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a proxy object with AOP capabilities
|
|
45
|
+
*/
|
|
46
|
+
createProxy() {
|
|
47
|
+
const proxy = Object.create(Object.getPrototypeOf(this.target));
|
|
48
|
+
// Gather members from the instance and its prototype chain
|
|
49
|
+
const memberNames = this.getAllMemberNames();
|
|
50
|
+
memberNames.forEach((name) => {
|
|
51
|
+
const value = this.target[name];
|
|
52
|
+
const isFunction = typeof value === 'function';
|
|
53
|
+
if (isFunction) {
|
|
54
|
+
const methodAdvice = this.getMethodAdvice(name);
|
|
55
|
+
if (methodAdvice) {
|
|
56
|
+
// 只拦截有 advice 的方法,其他方法保持原型链结构
|
|
57
|
+
this.interceptMethod(proxy, name, methodAdvice);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// 对于没有 advice 的方法,创建一个委托到原始实例的包装器
|
|
61
|
+
Object.defineProperty(proxy, name, {
|
|
62
|
+
value: (...args) => {
|
|
63
|
+
return value.apply(this.target, args);
|
|
64
|
+
},
|
|
65
|
+
writable: true,
|
|
66
|
+
enumerable: true,
|
|
67
|
+
configurable: true
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// 对于非函数属性,创建 getter/setter 来委托到原始实例
|
|
73
|
+
Object.defineProperty(proxy, name, {
|
|
74
|
+
get: () => this.target[name],
|
|
75
|
+
set: (newValue) => {
|
|
76
|
+
this.target[name] = newValue;
|
|
77
|
+
},
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return proxy;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Intercept a specific method with AOP advice
|
|
87
|
+
*/
|
|
88
|
+
interceptMethod(proxy, methodName, methodAdvice) {
|
|
89
|
+
const originalMethod = this.target[methodName];
|
|
90
|
+
Object.defineProperty(proxy, methodName, {
|
|
91
|
+
value: (...args) => {
|
|
92
|
+
try {
|
|
93
|
+
// Before advice - 传递 proxy 作为 target 参数
|
|
94
|
+
if (methodAdvice.before) {
|
|
95
|
+
methodAdvice.before(methodName, proxy, ...args);
|
|
96
|
+
}
|
|
97
|
+
let result;
|
|
98
|
+
// Around advice - 传递绑定了原始目标上下文的原始方法
|
|
99
|
+
if (methodAdvice.around) {
|
|
100
|
+
// 创建一个包装函数,确保 originalMethod 使用 target 作为 this 上下文
|
|
101
|
+
// 使用 bind 来确保 this 上下文正确绑定
|
|
102
|
+
const wrappedOriginalMethod = originalMethod.bind(this.target);
|
|
103
|
+
result = methodAdvice.around(methodName, proxy, wrappedOriginalMethod, ...args);
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Execute original method with target as this context to ensure state consistency
|
|
108
|
+
result = originalMethod.apply(this.target, args);
|
|
109
|
+
}
|
|
110
|
+
// 检查结果是否是 Promise
|
|
111
|
+
if (result && typeof result.then === 'function') {
|
|
112
|
+
// 异步方法 - 使用 Promise 链处理
|
|
113
|
+
return result
|
|
114
|
+
.then((resolvedResult) => {
|
|
115
|
+
// After advice - 传递 proxy 作为 target 参数
|
|
116
|
+
if (methodAdvice.after) {
|
|
117
|
+
methodAdvice.after(methodName, proxy, resolvedResult, ...args);
|
|
118
|
+
}
|
|
119
|
+
// AfterReturn advice - 在方法返回之前执行
|
|
120
|
+
if (methodAdvice.afterReturn) {
|
|
121
|
+
methodAdvice.afterReturn(methodName, proxy, resolvedResult, ...args);
|
|
122
|
+
}
|
|
123
|
+
return resolvedResult;
|
|
124
|
+
})
|
|
125
|
+
.catch((error) => {
|
|
126
|
+
// Error advice - 传递 proxy 作为 target 参数
|
|
127
|
+
if (methodAdvice.onError) {
|
|
128
|
+
methodAdvice.onError(methodName, proxy, error, ...args);
|
|
129
|
+
}
|
|
130
|
+
throw error;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// 同步方法
|
|
135
|
+
// After advice - 传递 proxy 作为 target 参数
|
|
136
|
+
if (methodAdvice.after) {
|
|
137
|
+
methodAdvice.after(methodName, proxy, result, ...args);
|
|
138
|
+
}
|
|
139
|
+
// AfterReturn advice - 在方法返回之前执行
|
|
140
|
+
if (methodAdvice.afterReturn) {
|
|
141
|
+
methodAdvice.afterReturn(methodName, proxy, result, ...args);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
// Error advice - 传递 proxy 作为 target 参数
|
|
148
|
+
if (methodAdvice.onError) {
|
|
149
|
+
methodAdvice.onError(methodName, proxy, error, ...args);
|
|
150
|
+
}
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
writable: true,
|
|
155
|
+
enumerable: true,
|
|
156
|
+
configurable: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Utility function to create AOP proxy with type safety
|
|
162
|
+
*/
|
|
163
|
+
export function createAOPProxy(config) {
|
|
164
|
+
const aopProxy = new AOPProxy(config);
|
|
165
|
+
return aopProxy.createProxy();
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Utility function to apply advice to an existing object
|
|
169
|
+
*/
|
|
170
|
+
export function applyAdvice(target, advice, defaultAdvice) {
|
|
171
|
+
return createAOPProxy({ target, advice, defaultAdvice });
|
|
172
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './aop';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const INTERCHAIN_KIT_STORAGE_KEY = 'interchain-kit-store';
|
|
2
|
+
export class LocalStorage {
|
|
3
|
+
save(value) {
|
|
4
|
+
localStorage.setItem(INTERCHAIN_KIT_STORAGE_KEY, JSON.stringify(value));
|
|
5
|
+
}
|
|
6
|
+
load() {
|
|
7
|
+
return JSON.parse(localStorage.getItem(INTERCHAIN_KIT_STORAGE_KEY) || '{}');
|
|
8
|
+
}
|
|
9
|
+
}
|