@hub3js/evm 0.1.1-next.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/CHANGELOG.md +0 -0
- package/dist/actions.d.ts +8 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/after.d.ts +2 -0
- package/dist/after.d.ts.map +1 -0
- package/dist/and.d.ts +3 -0
- package/dist/and.d.ts.map +1 -0
- package/dist/before.d.ts +2 -0
- package/dist/before.d.ts.map +1 -0
- package/dist/builders.d.ts +9 -0
- package/dist/builders.d.ts.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/eip1193.d.ts +1229 -0
- package/dist/eip1193.d.ts.map +1 -0
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/mod.d.ts +10 -0
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +2 -0
- package/dist/mod.js.map +7 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +1 -0
- package/readme.md +3 -0
- package/src/actions.ts +136 -0
- package/src/after.ts +3 -0
- package/src/and.ts +5 -0
- package/src/before.ts +3 -0
- package/src/builders.ts +52 -0
- package/src/constants.ts +2 -0
- package/src/eip1193.ts +1415 -0
- package/src/hooks.ts +43 -0
- package/src/mod.ts +10 -0
- package/src/types.ts +36 -0
- package/src/utils.ts +106 -0
package/src/hooks.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { EIP1193EventMap } from './eip1193.js';
|
|
2
|
+
import type { EvmActions, ProviderAPI } from './types.js';
|
|
3
|
+
import type { Subscriber, SubscriberCleanUp } from '@hub3js/core';
|
|
4
|
+
|
|
5
|
+
import { builders } from './mod.js';
|
|
6
|
+
|
|
7
|
+
export function changeAccountSubscriber(
|
|
8
|
+
instance: () => ProviderAPI,
|
|
9
|
+
): [Subscriber<EvmActions>, SubscriberCleanUp<EvmActions>] {
|
|
10
|
+
return builders.changeAccountSubscriber(instance).build();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function changeChainSubscriber(
|
|
14
|
+
instance: () => ProviderAPI,
|
|
15
|
+
): [Subscriber<EvmActions>, SubscriberCleanUp<EvmActions>] {
|
|
16
|
+
let eventCallback: EIP1193EventMap['chainChanged'];
|
|
17
|
+
|
|
18
|
+
return [
|
|
19
|
+
(context) => {
|
|
20
|
+
const evmInstance = instance();
|
|
21
|
+
|
|
22
|
+
if (!evmInstance) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'Trying to subscribe to your EVM wallet, but seems its instance is not available.',
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const [, setState] = context.state();
|
|
29
|
+
|
|
30
|
+
eventCallback = async (chainId: string) => {
|
|
31
|
+
setState('network', chainId);
|
|
32
|
+
};
|
|
33
|
+
evmInstance.on('chainChanged', eventCallback);
|
|
34
|
+
},
|
|
35
|
+
() => {
|
|
36
|
+
const evmInstance = instance();
|
|
37
|
+
|
|
38
|
+
if (eventCallback && evmInstance) {
|
|
39
|
+
evmInstance.removeListener('chainChanged', eventCallback);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
}
|
package/src/mod.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * as actions from './actions.js';
|
|
2
|
+
export * as hooks from './hooks.js';
|
|
3
|
+
export * as after from './after.js';
|
|
4
|
+
export * as and from './and.js';
|
|
5
|
+
export * as before from './before.js';
|
|
6
|
+
export * as utils from './utils.js';
|
|
7
|
+
export * as builders from './builders.js';
|
|
8
|
+
|
|
9
|
+
export type { EvmActions, ProviderAPI, Chain, ChainId } from './types.js';
|
|
10
|
+
export { CAIP_NAMESPACE, CAIP_ETHEREUM_CHAIN_ID } from './constants.js';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AddEthereumChainParameter, EIP1193Provider } from './eip1193.js';
|
|
2
|
+
import type {
|
|
3
|
+
AccountsWithActiveChain,
|
|
4
|
+
AutoImplementedActionsByRecommended,
|
|
5
|
+
CommonActions,
|
|
6
|
+
} from '@hub3js/std/types';
|
|
7
|
+
import type { BlockchainMeta } from 'rango-types';
|
|
8
|
+
|
|
9
|
+
export interface EvmActions
|
|
10
|
+
extends AutoImplementedActionsByRecommended, CommonActions {
|
|
11
|
+
connect: (
|
|
12
|
+
chain?: Chain | ChainId,
|
|
13
|
+
options?: ConnectOptions,
|
|
14
|
+
) => Promise<AccountsWithActiveChain>;
|
|
15
|
+
canEagerConnect: () => Promise<boolean>;
|
|
16
|
+
canSwitchNetwork: (params: CanSwitchNetworkParams) => boolean;
|
|
17
|
+
getChainId: () => Promise<`0x${string}`>;
|
|
18
|
+
}
|
|
19
|
+
type CanSwitchNetworkParams = {
|
|
20
|
+
network: string;
|
|
21
|
+
supportedChains: BlockchainMeta[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ProviderAPI = EIP1193Provider;
|
|
25
|
+
// A 0x-prefixed hexadecimal string
|
|
26
|
+
export type ChainId = string;
|
|
27
|
+
export type Chain = AddEthereumChainParameter;
|
|
28
|
+
export type ProviderAccounts = {
|
|
29
|
+
accounts: string[];
|
|
30
|
+
chainId: ChainId;
|
|
31
|
+
};
|
|
32
|
+
export type ConnectOptions = {
|
|
33
|
+
switchOrAddNetwork?: (instance: ProviderAPI, chain: ChainId | Chain) => void;
|
|
34
|
+
getAccounts?: (provider: ProviderAPI) => Promise<ProviderAccounts>;
|
|
35
|
+
derivationPath?: string;
|
|
36
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Chain, ChainId, ProviderAPI } from './types.js';
|
|
2
|
+
import type { CaipAccount } from '@hub3js/std/types';
|
|
3
|
+
|
|
4
|
+
import { AccountId } from 'caip';
|
|
5
|
+
import { type BlockchainMeta, evmBlockchains } from 'rango-types';
|
|
6
|
+
|
|
7
|
+
import { CAIP_NAMESPACE } from './constants.js';
|
|
8
|
+
|
|
9
|
+
const CHAIN_ID_RADIX = 16;
|
|
10
|
+
|
|
11
|
+
export async function getAccounts(provider: ProviderAPI) {
|
|
12
|
+
const [accounts, chainId] = await Promise.all([
|
|
13
|
+
provider.request({ method: 'eth_requestAccounts' }),
|
|
14
|
+
provider.request({ method: 'eth_chainId' }),
|
|
15
|
+
]);
|
|
16
|
+
/*
|
|
17
|
+
* Trust Wallet Compatibility Fix:
|
|
18
|
+
* Trust Wallet's in-app browser has been observed to return the `chainId` as a
|
|
19
|
+
* number (e.g., 1) rather than the standard hexadecimal string (e.g., "0x1").
|
|
20
|
+
* This code block standardizes the `chainId` to the required hex format to
|
|
21
|
+
* prevent downstream errors.
|
|
22
|
+
*/
|
|
23
|
+
let standardChainId = chainId;
|
|
24
|
+
if (typeof standardChainId === 'number') {
|
|
25
|
+
standardChainId = `0x${Number(chainId).toString(CHAIN_ID_RADIX)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
accounts,
|
|
30
|
+
chainId: standardChainId,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function suggestNetwork(instance: ProviderAPI, chain: Chain) {
|
|
35
|
+
return await instance.request({
|
|
36
|
+
method: 'wallet_addEthereumChain',
|
|
37
|
+
params: [chain],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function switchNetwork(instance: ProviderAPI, chainId: ChainId) {
|
|
42
|
+
return await instance.request({
|
|
43
|
+
method: 'wallet_switchEthereumChain',
|
|
44
|
+
params: [{ chainId: chainId }],
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function filterAndGetEvmBlockchainNames(meta: BlockchainMeta[]) {
|
|
48
|
+
return evmBlockchains(meta).map((blockchain) => blockchain.name);
|
|
49
|
+
}
|
|
50
|
+
export async function switchOrAddNetwork(
|
|
51
|
+
instance: ProviderAPI,
|
|
52
|
+
chain: ChainId | Chain,
|
|
53
|
+
) {
|
|
54
|
+
try {
|
|
55
|
+
const chainId = typeof chain === 'string' ? chain : chain.chainId;
|
|
56
|
+
await switchNetwork(instance, chainId);
|
|
57
|
+
} catch (switchError) {
|
|
58
|
+
const error = switchError as { code: number };
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
* Error code 4902 is used by MetaMask to indicate that the requested chain has not been added to the wallet.
|
|
62
|
+
* This code is not part of the official EIP-1193 spec (https://eips.ethereum.org/EIPS/eip-1193#supported-rpc-methods),
|
|
63
|
+
* so other providers may use a different code or behavior for the same condition.
|
|
64
|
+
*/
|
|
65
|
+
const NOT_FOUND_CHAIN_ERROR_CODE = 4902;
|
|
66
|
+
if (
|
|
67
|
+
typeof chain !== 'string' &&
|
|
68
|
+
(error.code === NOT_FOUND_CHAIN_ERROR_CODE || !error.code)
|
|
69
|
+
) {
|
|
70
|
+
/*
|
|
71
|
+
* Note: on WalletConnect `code` is undefined so we have to use !switchError.code as fallback.
|
|
72
|
+
* This error code indicates that the chain has not been added to wallet.
|
|
73
|
+
*/
|
|
74
|
+
await suggestNetwork(instance, chain);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
throw switchError;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const EIP_1193_USER_REJECTION_ERROR_CODE = 4001;
|
|
82
|
+
export function isUserRejectionError(error: unknown): boolean {
|
|
83
|
+
// EIP-1193 user rejection error can be in error.code or error.cause.code
|
|
84
|
+
if (typeof error === 'object' && error !== null) {
|
|
85
|
+
const code = (error as { code?: number }).code;
|
|
86
|
+
const causeCode = (error as { cause?: { code?: number } }).cause?.code;
|
|
87
|
+
return (
|
|
88
|
+
code === EIP_1193_USER_REJECTION_ERROR_CODE ||
|
|
89
|
+
causeCode === EIP_1193_USER_REJECTION_ERROR_CODE
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function formatAccountsToCAIP(accounts: string[], chainId: string) {
|
|
96
|
+
return accounts.map(
|
|
97
|
+
(account) =>
|
|
98
|
+
AccountId.format({
|
|
99
|
+
address: account,
|
|
100
|
+
chainId: {
|
|
101
|
+
namespace: CAIP_NAMESPACE,
|
|
102
|
+
reference: chainId,
|
|
103
|
+
},
|
|
104
|
+
}) as CaipAccount,
|
|
105
|
+
);
|
|
106
|
+
}
|