@naculus/connect-appkit-core 0.2.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 +21 -0
- package/dist/index.cjs +352 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +325 -0
- package/dist/index.d.ts +325 -0
- package/dist/index.js +301 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// src/chain-selection.ts
|
|
2
|
+
import { eip155Reference, namespaceOf } from "@naculus/connect-core";
|
|
3
|
+
function chainNumber(chain) {
|
|
4
|
+
return eip155Reference(chain.caip2);
|
|
5
|
+
}
|
|
6
|
+
function chainNamespace(chain) {
|
|
7
|
+
return namespaceOf(chain.caip2);
|
|
8
|
+
}
|
|
9
|
+
function resolveChain(chains, chainId) {
|
|
10
|
+
if (!chainId) return null;
|
|
11
|
+
return chains.find((c) => c.caip2 === chainId) ?? null;
|
|
12
|
+
}
|
|
13
|
+
function chainsForNamespace(chains, chainId) {
|
|
14
|
+
if (!chainId) return chains;
|
|
15
|
+
const namespace = namespaceOf(chainId);
|
|
16
|
+
if (!namespace) return chains;
|
|
17
|
+
return chains.filter((c) => chainNamespace(c) === namespace);
|
|
18
|
+
}
|
|
19
|
+
function describeChain(chains, chainId) {
|
|
20
|
+
if (!chainId) return null;
|
|
21
|
+
const namespace = namespaceOf(chainId);
|
|
22
|
+
if (!namespace) return null;
|
|
23
|
+
const known = resolveChain(chains, chainId);
|
|
24
|
+
if (known) {
|
|
25
|
+
return { namespace, chainId, name: known.name, selected: true };
|
|
26
|
+
}
|
|
27
|
+
const reference = chainId.slice(namespace.length + 1);
|
|
28
|
+
return {
|
|
29
|
+
namespace,
|
|
30
|
+
chainId,
|
|
31
|
+
name: namespace === "eip155" ? `Chain ${reference}` : reference,
|
|
32
|
+
selected: true
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/viem-chain.ts
|
|
37
|
+
import { CHAINS } from "@naculus/connect-core";
|
|
38
|
+
function toViemChain(chain, chainNumber2) {
|
|
39
|
+
if (chainNumber2 === null || !chain.rpcUrl) return null;
|
|
40
|
+
const symbol = chain.token ?? CHAINS[chainNumber2]?.nativeCurrency?.symbol ?? "";
|
|
41
|
+
return {
|
|
42
|
+
id: chainNumber2,
|
|
43
|
+
name: chain.name,
|
|
44
|
+
// Every EIP-155 native currency is 18 decimals by protocol, so this is a
|
|
45
|
+
// constant rather than an assumption. ERC-20 decimals are per-token and
|
|
46
|
+
// are never guessed anywhere in this codebase.
|
|
47
|
+
nativeCurrency: { name: symbol, symbol, decimals: 18 },
|
|
48
|
+
rpcUrls: {
|
|
49
|
+
default: { http: [chain.rpcUrl] },
|
|
50
|
+
public: { http: [chain.rpcUrl] }
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/aa-chain.ts
|
|
56
|
+
var EVM_CHAIN_ID = /^eip155:[1-9][0-9]*$/;
|
|
57
|
+
function isEvmChainId(value) {
|
|
58
|
+
return typeof value === "string" && EVM_CHAIN_ID.test(value);
|
|
59
|
+
}
|
|
60
|
+
function resolveEvmChainId(requested, connected) {
|
|
61
|
+
const candidate = requested ?? connected ?? void 0;
|
|
62
|
+
return isEvmChainId(candidate) ? candidate : void 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/token-chain.ts
|
|
66
|
+
import { WalletError } from "@naculus/connect-core";
|
|
67
|
+
function tokenChainMismatch(token, activeChainId) {
|
|
68
|
+
if (typeof token?.chainId !== "number" || !Number.isFinite(token.chainId)) {
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
71
|
+
if (typeof activeChainId !== "number" || !Number.isFinite(activeChainId)) {
|
|
72
|
+
return void 0;
|
|
73
|
+
}
|
|
74
|
+
if (token.chainId === activeChainId) return void 0;
|
|
75
|
+
return new WalletError(
|
|
76
|
+
"chain_mismatch",
|
|
77
|
+
`Token ${token.address} is configured for chain ${token.chainId}, but the wallet is on chain ${activeChainId}. Switch chains before continuing \u2014 the same address holds a different contract on each chain.`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/token-decimals.ts
|
|
82
|
+
function tokenKey(token) {
|
|
83
|
+
return `${token.chainId ?? "?"}:${token.address.toLowerCase()}`;
|
|
84
|
+
}
|
|
85
|
+
function createDecimalsCache(token, known) {
|
|
86
|
+
return { key: tokenKey(token), value: known };
|
|
87
|
+
}
|
|
88
|
+
function readDecimals(cache, token, known) {
|
|
89
|
+
const key = tokenKey(token);
|
|
90
|
+
if (cache.key !== key) {
|
|
91
|
+
cache.key = key;
|
|
92
|
+
cache.value = known;
|
|
93
|
+
}
|
|
94
|
+
return cache.value;
|
|
95
|
+
}
|
|
96
|
+
function writeDecimals(cache, token, value) {
|
|
97
|
+
cache.key = tokenKey(token);
|
|
98
|
+
cache.value = value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/provider-errors.ts
|
|
102
|
+
import { WalletError as WalletError2 } from "@naculus/connect-core";
|
|
103
|
+
var USER_REJECTED = 4001;
|
|
104
|
+
var UNRECOGNIZED_CHAIN = 4902;
|
|
105
|
+
function providerCode(error) {
|
|
106
|
+
if (!error || typeof error !== "object") return void 0;
|
|
107
|
+
const code = error.code;
|
|
108
|
+
if (typeof code === "number") return code;
|
|
109
|
+
if (typeof code === "string" && /^-?\d+$/.test(code)) return Number(code);
|
|
110
|
+
const nested = error.data?.originalError;
|
|
111
|
+
return nested ? providerCode(nested) : void 0;
|
|
112
|
+
}
|
|
113
|
+
function toChainSwitchError(error, fallback = "chain_unsupported") {
|
|
114
|
+
if (error instanceof WalletError2) return error;
|
|
115
|
+
const message = error instanceof Error ? error.message : "Unknown error during chain switch";
|
|
116
|
+
switch (providerCode(error)) {
|
|
117
|
+
case USER_REJECTED:
|
|
118
|
+
return new WalletError2("chain_switch_rejected", message, error);
|
|
119
|
+
case UNRECOGNIZED_CHAIN:
|
|
120
|
+
return new WalletError2(
|
|
121
|
+
"chain_unsupported",
|
|
122
|
+
`${message} (the wallet does not have this chain configured)`,
|
|
123
|
+
error
|
|
124
|
+
);
|
|
125
|
+
default:
|
|
126
|
+
return new WalletError2(fallback, message, error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/revert-reason.ts
|
|
131
|
+
var ERROR_STRING_SELECTOR = "08c379a0";
|
|
132
|
+
var PANIC_SELECTOR = "4e487b71";
|
|
133
|
+
var PANIC_REASONS = {
|
|
134
|
+
1: "assertion failed",
|
|
135
|
+
17: "arithmetic overflow or underflow",
|
|
136
|
+
18: "division or modulo by zero",
|
|
137
|
+
33: "invalid enum value",
|
|
138
|
+
49: "pop() on an empty array",
|
|
139
|
+
50: "array index out of bounds"
|
|
140
|
+
};
|
|
141
|
+
function hexToUtf8(hex) {
|
|
142
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
143
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
144
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
145
|
+
}
|
|
146
|
+
return new TextDecoder().decode(bytes);
|
|
147
|
+
}
|
|
148
|
+
function decodeRevertReason(data) {
|
|
149
|
+
if (typeof data !== "string" || data.length === 0) return void 0;
|
|
150
|
+
const clean = data.startsWith("0x") ? data.slice(2) : data;
|
|
151
|
+
if (!/^[0-9a-fA-F]*$/.test(clean)) return void 0;
|
|
152
|
+
if (clean.startsWith(ERROR_STRING_SELECTOR)) {
|
|
153
|
+
if (clean.length < 136) return void 0;
|
|
154
|
+
const declared = Number.parseInt(clean.slice(72, 136), 16);
|
|
155
|
+
if (!Number.isSafeInteger(declared) || declared <= 0) return void 0;
|
|
156
|
+
const available = (clean.length - 136) / 2;
|
|
157
|
+
if (declared > available) return void 0;
|
|
158
|
+
return hexToUtf8(clean.slice(136, 136 + declared * 2));
|
|
159
|
+
}
|
|
160
|
+
if (clean.startsWith(PANIC_SELECTOR)) {
|
|
161
|
+
if (clean.length < 8 + 64) return "Panic";
|
|
162
|
+
const code = Number.parseInt(clean.slice(8, 72), 16);
|
|
163
|
+
if (!Number.isSafeInteger(code)) return "Panic";
|
|
164
|
+
const known = PANIC_REASONS[code];
|
|
165
|
+
const hex = `0x${code.toString(16).padStart(2, "0")}`;
|
|
166
|
+
return known ? `Panic ${hex}: ${known}` : `Panic ${hex}`;
|
|
167
|
+
}
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
function resolveRevertReason(data, fallbackMessage) {
|
|
171
|
+
return decodeRevertReason(data) ?? (fallbackMessage.includes("revert") ? fallbackMessage : "Transaction reverted");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/name-resolver.ts
|
|
175
|
+
import { NameResolver } from "@naculus/connect-core";
|
|
176
|
+
var sharedResolver = null;
|
|
177
|
+
function getResolver(config) {
|
|
178
|
+
if (config) return new NameResolver(config);
|
|
179
|
+
if (!sharedResolver) sharedResolver = new NameResolver();
|
|
180
|
+
return sharedResolver;
|
|
181
|
+
}
|
|
182
|
+
function __resetResolverForTests() {
|
|
183
|
+
sharedResolver = null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/web3-store.ts
|
|
187
|
+
import { logger } from "@naculus/connect-core";
|
|
188
|
+
function withTimeout(promise, ms, label = "Operation") {
|
|
189
|
+
let timeoutId;
|
|
190
|
+
const timeout = new Promise((_, reject) => {
|
|
191
|
+
timeoutId = setTimeout(
|
|
192
|
+
() => reject(new Error(`${label} timed out after ${ms}ms`)),
|
|
193
|
+
ms
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
197
|
+
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async function withRetry(fn, options) {
|
|
201
|
+
let lastError;
|
|
202
|
+
for (let attempt = 0; attempt <= options.maxRetries; attempt++) {
|
|
203
|
+
try {
|
|
204
|
+
return await fn();
|
|
205
|
+
} catch (error) {
|
|
206
|
+
lastError = error;
|
|
207
|
+
if (attempt < options.maxRetries) {
|
|
208
|
+
const delay = options.baseDelay * 2 ** attempt;
|
|
209
|
+
logger.warn(
|
|
210
|
+
"appkit/core",
|
|
211
|
+
`Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`
|
|
212
|
+
);
|
|
213
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
throw lastError;
|
|
218
|
+
}
|
|
219
|
+
function normalizeEip155ChainId(value) {
|
|
220
|
+
if (typeof value !== "string") return void 0;
|
|
221
|
+
try {
|
|
222
|
+
if (value.startsWith("eip155:")) {
|
|
223
|
+
const reference = value.slice("eip155:".length);
|
|
224
|
+
if (!/^\d+$/.test(reference)) return void 0;
|
|
225
|
+
return `eip155:${BigInt(reference).toString(10)}`;
|
|
226
|
+
}
|
|
227
|
+
if (/^0x[0-9a-f]+$/i.test(value) || /^\d+$/.test(value)) {
|
|
228
|
+
return `eip155:${BigInt(value).toString(10)}`;
|
|
229
|
+
}
|
|
230
|
+
} catch {
|
|
231
|
+
}
|
|
232
|
+
return void 0;
|
|
233
|
+
}
|
|
234
|
+
function toEip155Accounts(accounts, chainId) {
|
|
235
|
+
const reference = chainId.split(":")[1];
|
|
236
|
+
if (!reference) return [];
|
|
237
|
+
return accounts.filter(
|
|
238
|
+
(account) => typeof account === "string" && account.length > 0
|
|
239
|
+
).map(
|
|
240
|
+
(account) => account.includes(":") ? account.split(":").pop() : account
|
|
241
|
+
).map((account) => `eip155:${reference}:${account}`);
|
|
242
|
+
}
|
|
243
|
+
function eip155ChainIdToNumber(chainId) {
|
|
244
|
+
const match = /^eip155:([1-9][0-9]*)$/.exec(chainId);
|
|
245
|
+
if (!match) return void 0;
|
|
246
|
+
const numeric = Number(match[1]);
|
|
247
|
+
return Number.isSafeInteger(numeric) ? numeric : void 0;
|
|
248
|
+
}
|
|
249
|
+
var initialWeb3State = {
|
|
250
|
+
status: "disconnected",
|
|
251
|
+
session: null,
|
|
252
|
+
accounts: [],
|
|
253
|
+
chainId: null,
|
|
254
|
+
error: null
|
|
255
|
+
};
|
|
256
|
+
function web3Reducer(state, action) {
|
|
257
|
+
switch (action.type) {
|
|
258
|
+
case "SET_STATUS":
|
|
259
|
+
return { ...state, status: action.payload };
|
|
260
|
+
case "SET_SESSION":
|
|
261
|
+
return { ...state, session: action.payload };
|
|
262
|
+
case "SET_ACCOUNTS":
|
|
263
|
+
return { ...state, accounts: action.payload };
|
|
264
|
+
case "SET_CHAIN":
|
|
265
|
+
return { ...state, chainId: action.payload };
|
|
266
|
+
case "SET_ERROR":
|
|
267
|
+
return { ...state, error: action.payload };
|
|
268
|
+
case "RESET":
|
|
269
|
+
return initialWeb3State;
|
|
270
|
+
default:
|
|
271
|
+
return state;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
export {
|
|
275
|
+
__resetResolverForTests,
|
|
276
|
+
chainNamespace,
|
|
277
|
+
chainNumber,
|
|
278
|
+
chainsForNamespace,
|
|
279
|
+
createDecimalsCache,
|
|
280
|
+
decodeRevertReason,
|
|
281
|
+
describeChain,
|
|
282
|
+
eip155ChainIdToNumber,
|
|
283
|
+
getResolver,
|
|
284
|
+
initialWeb3State,
|
|
285
|
+
isEvmChainId,
|
|
286
|
+
normalizeEip155ChainId,
|
|
287
|
+
readDecimals,
|
|
288
|
+
resolveChain,
|
|
289
|
+
resolveEvmChainId,
|
|
290
|
+
resolveRevertReason,
|
|
291
|
+
toChainSwitchError,
|
|
292
|
+
toEip155Accounts,
|
|
293
|
+
toViemChain,
|
|
294
|
+
tokenChainMismatch,
|
|
295
|
+
tokenKey,
|
|
296
|
+
web3Reducer,
|
|
297
|
+
withRetry,
|
|
298
|
+
withTimeout,
|
|
299
|
+
writeDecimals
|
|
300
|
+
};
|
|
301
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chain-selection.ts","../src/viem-chain.ts","../src/aa-chain.ts","../src/token-chain.ts","../src/token-decimals.ts","../src/provider-errors.ts","../src/revert-reason.ts","../src/name-resolver.ts","../src/web3-store.ts"],"sourcesContent":["/**\n * Which chains a session can actually switch to, and what the current one is.\n *\n * Framework-neutral, and deliberately built on `parseChainId` from\n * `@naculus/connect-core` rather than on another `startsWith(\"eip155:\")`.\n */\n\nimport { eip155Reference, namespaceOf } from \"@naculus/connect-core\";\nimport type { ChainInfo, WalletChain } from \"./types\";\n\n/**\n * The EIP-155 chain number, or null when this is not an EVM chain.\n *\n * Callers that need a number — a viem client, an ERC-20 read — must handle\n * the null rather than defaulting, because there is no number that means\n * \"Solana\" and any stand-in would address a real EVM chain.\n */\nexport function chainNumber(chain: WalletChain): number | null {\n return eip155Reference(chain.caip2);\n}\n\n/** The namespace a chain belongs to, read from its CAIP-2 id. */\nexport function chainNamespace(chain: WalletChain): string | null {\n return namespaceOf(chain.caip2);\n}\n\n/**\n * The configured chain for a CAIP-2 id, or null.\n *\n * A string comparison now that `WalletChain` is keyed by CAIP-2. It used to\n * pull an integer out of the id and compare that, which no non-EVM chain\n * could ever match.\n */\nexport function resolveChain(\n chains: WalletChain[],\n chainId: string | null | undefined,\n): WalletChain | null {\n if (!chainId) return null;\n return chains.find((c) => c.caip2 === chainId) ?? null;\n}\n\n/**\n * The chains worth offering for the session's namespace.\n *\n * This used to return every configured chain regardless of what was\n * connected, so a Solana wallet was offered Ethereum and Polygon in the\n * switcher. Clicking one asked a wallet that has no concept of EIP-155 to\n * switch to chain 137 — an action the interface presented as available and\n * that could never work.\n *\n * With no connected chain, everything is offered: nothing has been ruled out\n * yet, and hiding the list would leave a user unable to pick.\n */\nexport function chainsForNamespace(\n chains: WalletChain[],\n chainId: string | null | undefined,\n): WalletChain[] {\n if (!chainId) return chains;\n const namespace = namespaceOf(chainId);\n if (!namespace) return chains;\n return chains.filter((c) => chainNamespace(c) === namespace);\n}\n\n/**\n * A description of the connected chain for display.\n *\n * Returns something for every namespace. It used to return null for anything\n * that was not EIP-155, so a connected Solana wallet had no chain to show at\n * all and the interface fell back to \"Unknown Chain\".\n */\nexport function describeChain(\n chains: WalletChain[],\n chainId: string | null | undefined,\n): ChainInfo | null {\n if (!chainId) return null;\n const namespace = namespaceOf(chainId);\n if (!namespace) return null;\n\n const known = resolveChain(chains, chainId);\n if (known) {\n return { namespace, chainId, name: known.name, selected: true };\n }\n\n // No configured entry. Name it by its CAIP-2 reference rather than\n // inventing one: \"Chain 5\" for a Solana cluster would be a fabrication, and\n // the reference is at least something a user can look up.\n const reference = chainId.slice(namespace.length + 1);\n return {\n namespace,\n chainId,\n name: namespace === \"eip155\" ? `Chain ${reference}` : reference,\n selected: true,\n };\n}\n","/**\n * The viem `Chain` shape for a configured EVM chain.\n *\n * Three hooks each built this inline — `useBalance`, `useTokenBalance` and\n * `useViemClient` — with identical bodies and the same `?? \"ETH\"` in each.\n * Three copies of a fallback is three places for it to be wrong.\n *\n * Returns a plain object rather than importing viem, so this package stays\n * free of a dependency only the React bindings need. The shape satisfies\n * viem's `Chain` structurally.\n */\n\nimport { CHAINS } from \"@naculus/connect-core\";\nimport type { WalletChain } from \"./types\";\n\nexport interface ViemChainShape {\n id: number;\n name: string;\n nativeCurrency: { name: string; symbol: string; decimals: number };\n rpcUrls: {\n default: { http: string[] };\n public: { http: string[] };\n };\n}\n\n/**\n * Build the chain descriptor a viem client needs, or null when this chain is\n * not one viem can talk to.\n *\n * Null for a non-EVM chain rather than a stand-in number: viem speaks to EVM\n * nodes, and any number chosen to fill the gap addresses a real chain that is\n * not the one connected.\n *\n * The native symbol comes from the chain's own `token`, then from the shared\n * chain registry. For an unlisted chain it stays empty rather than claiming\n * the asset is ETH. viem requires a string here; the user-facing symbol comes\n * from `useBalance().symbol`, which stays null when it is unknown.\n */\nexport function toViemChain(\n chain: WalletChain,\n chainNumber: number | null,\n): ViemChainShape | null {\n if (chainNumber === null || !chain.rpcUrl) return null;\n\n const symbol =\n chain.token ?? CHAINS[chainNumber]?.nativeCurrency?.symbol ?? \"\";\n\n return {\n id: chainNumber,\n name: chain.name,\n // Every EIP-155 native currency is 18 decimals by protocol, so this is a\n // constant rather than an assumption. ERC-20 decimals are per-token and\n // are never guessed anywhere in this codebase.\n nativeCurrency: { name: symbol, symbol, decimals: 18 },\n rpcUrls: {\n default: { http: [chain.rpcUrl] },\n public: { http: [chain.rpcUrl] },\n },\n };\n}\n","/**\n * Which EVM chain does an account-abstraction operation belong to?\n *\n * The smart-account hooks each resolved this as\n * `options.chainId ?? connectedChainId ?? \"eip155:1\"`, and each then guarded\n * with `if (connectedChainId && connectedChainId !== target)`. The guard is\n * skipped precisely when the mainnet default is used, so the one branch that\n * assumes a chain is the one branch that never checks it.\n *\n * That branch is reachable: a caller passing its own `signer` needs no\n * session, so `connectedChainId` is legitimately absent. It would then build\n * and sign a UserOperation for chain 1 — with chain 1's EntryPoint — while its\n * configured RPC and bundler point somewhere else. The chain ID is part of the\n * UserOperation hash, so the user approves a commitment to a chain they were\n * never shown.\n *\n * Resolving to undefined instead lets each caller refuse in whatever way suits\n * it. Framework-agnostic on purpose: it must not import React.\n */\n\n/** CAIP-2 for an EVM chain. The reference is a decimal chain ID with no leading zero. */\nconst EVM_CHAIN_ID = /^eip155:[1-9][0-9]*$/;\n\nexport function isEvmChainId(value: string | null | undefined): boolean {\n return typeof value === \"string\" && EVM_CHAIN_ID.test(value);\n}\n\n/**\n * The chain to operate on, or undefined when it cannot be known.\n *\n * An explicitly requested chain wins over the connected one; a malformed value\n * from either source resolves to undefined rather than being replaced by a\n * guess, because the caller asked for something specific and got it wrong.\n */\nexport function resolveEvmChainId(\n requested: string | null | undefined,\n connected: string | null | undefined,\n): string | undefined {\n const candidate = requested ?? connected ?? undefined;\n return isEvmChainId(candidate) ? candidate : undefined;\n}\n","/**\n * Does this token belong to the chain the wallet is pointed at?\n *\n * `TokenConfig.chainId` existed but was only ever read as a display label and\n * a cache key. Nothing compared it to the connected chain, so a hook handed a\n * mainnet token config while the wallet sat on Polygon would read — or\n * approve — whatever contract happens to occupy that address on Polygon.\n * Usually that address holds nothing and the call reverts, which is merely\n * confusing. When it holds a different token, `allowance()` returns a\n * plausible number for the wrong asset, and `approve()` grants a spender\n * rights over something the user never looked at.\n *\n * Framework-agnostic on purpose: it must not import React.\n */\n\nimport type { TokenConfig } from \"@naculus/connect-core\";\nimport { WalletError } from \"@naculus/connect-core\";\n\n/**\n * A mismatch, or undefined when the token is on the active chain — or when\n * there is not enough information to tell.\n *\n * Silence on \"cannot tell\" is deliberate. A token config without a chainId, or\n * a session with no resolved chain, is a gap in what the caller supplied; a\n * guess in either direction would be worse than letting the call proceed and\n * fail on its own terms.\n */\nexport function tokenChainMismatch(\n token: Pick<TokenConfig, \"address\" | \"chainId\">,\n activeChainId: number | undefined,\n): WalletError | undefined {\n if (typeof token?.chainId !== \"number\" || !Number.isFinite(token.chainId)) {\n return undefined;\n }\n if (typeof activeChainId !== \"number\" || !Number.isFinite(activeChainId)) {\n return undefined;\n }\n if (token.chainId === activeChainId) return undefined;\n\n return new WalletError(\n \"chain_mismatch\",\n `Token ${token.address} is configured for chain ${token.chainId}, but the ` +\n `wallet is on chain ${activeChainId}. Switch chains before continuing — ` +\n `the same address holds a different contract on each chain.`,\n );\n}\n","/**\n * Decimals cache keyed by the token it belongs to.\n *\n * The ERC-20 hooks cached decimals in a bare `useRef` seeded from the token\n * prop. `useRef` only takes its initial value on mount, and nothing reset it,\n * so a component that lets the user switch tokens kept the first token's\n * precision: picking USDC (6) and then DAI (18) converted \"100\" with 6\n * decimals and transferred 0.0000000001 DAI. The transaction succeeded, so\n * nothing surfaced the mistake.\n *\n * Keying the cache by the token makes a stale hit impossible without needing\n * an effect to fire first.\n */\n\nexport interface TokenIdentity {\n chainId?: number;\n address: string;\n}\n\nexport interface DecimalsCache {\n key: string;\n value: number | undefined;\n}\n\nexport function tokenKey(token: TokenIdentity): string {\n return `${token.chainId ?? \"?\"}:${token.address.toLowerCase()}`;\n}\n\nexport function createDecimalsCache(\n token: TokenIdentity,\n known?: number,\n): DecimalsCache {\n return { key: tokenKey(token), value: known };\n}\n\n/**\n * Cached decimals for `token`, or undefined when the cache holds another\n * token's value. Resets the cache as a side effect so the next write lands\n * against the right key.\n */\nexport function readDecimals(\n cache: DecimalsCache,\n token: TokenIdentity,\n known?: number,\n): number | undefined {\n const key = tokenKey(token);\n if (cache.key !== key) {\n cache.key = key;\n cache.value = known;\n }\n return cache.value;\n}\n\nexport function writeDecimals(\n cache: DecimalsCache,\n token: TokenIdentity,\n value: number,\n): void {\n cache.key = tokenKey(token);\n cache.value = value;\n}\n","/**\n * Normalize an EIP-1193 provider error into a WalletError.\n *\n * Hooks were collapsing every non-WalletError into one code — `useSwitchChain`\n * labelled a user pressing Cancel as `chain_unsupported`, so the UI told them\n * the chain was unavailable when they had simply declined. The codes below are\n * the ones wallets actually send, and they mean different things to a caller:\n * one is retryable by asking again, the other is not retryable at all until\n * the chain is added.\n *\n * Framework-agnostic on purpose: it must not import React.\n */\n\nimport type { WalletErrorCode } from \"@naculus/connect-core\";\nimport { WalletError } from \"@naculus/connect-core\";\n\n/** EIP-1193: the user rejected the request. */\nconst USER_REJECTED = 4001;\n/** EIP-3326: the wallet does not recognize the chain and must add it first. */\nconst UNRECOGNIZED_CHAIN = 4902;\n\nfunction providerCode(error: unknown): number | undefined {\n if (!error || typeof error !== \"object\") return undefined;\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"number\") return code;\n // Some wallets stringify it, and some nest the original under `data`.\n if (typeof code === \"string\" && /^-?\\d+$/.test(code)) return Number(code);\n const nested = (error as { data?: { originalError?: unknown } }).data\n ?.originalError;\n return nested ? providerCode(nested) : undefined;\n}\n\n/**\n * Map a chain-switch failure onto the code that describes it.\n *\n * `fallback` is used when the wallet gave nothing to go on, so the caller\n * still decides what an unexplained failure means in its own context.\n */\nexport function toChainSwitchError(\n error: unknown,\n fallback: WalletErrorCode = \"chain_unsupported\",\n): WalletError {\n if (error instanceof WalletError) return error;\n\n const message =\n error instanceof Error\n ? error.message\n : \"Unknown error during chain switch\";\n\n switch (providerCode(error)) {\n case USER_REJECTED:\n return new WalletError(\"chain_switch_rejected\", message, error);\n case UNRECOGNIZED_CHAIN:\n return new WalletError(\n \"chain_unsupported\",\n `${message} (the wallet does not have this chain configured)`,\n error,\n );\n default:\n return new WalletError(fallback, message, error);\n }\n}\n","/**\n * Decode an EVM revert payload into something a user can act on.\n *\n * This text is what a wallet shows when a simulation says a transaction would\n * fail, so it is worth getting right and worth sharing: the logic is pure and\n * every binding needs the same answer.\n *\n * Two things are handled that the inlined version did not. The ABI length\n * word is attacker-controlled, so a payload can declare a longer string than\n * it carries; decoding that produced a run of NUL bytes rather than an honest\n * \"could not decode\". And a Panic was reported as \"Built-in failure\" with the\n * code discarded, which is the one piece of information that distinguishes an\n * overflow from a division by zero.\n */\n\n/** keccak256(\"Error(string)\")[0:4] */\nconst ERROR_STRING_SELECTOR = \"08c379a0\";\n/** keccak256(\"Panic(uint256)\")[0:4] */\nconst PANIC_SELECTOR = \"4e487b71\";\n\n/**\n * Panic codes defined by Solidity. Unlisted codes still surface their raw\n * value rather than being flattened into a generic message.\n */\nconst PANIC_REASONS: Record<number, string> = {\n 0x01: \"assertion failed\",\n 0x11: \"arithmetic overflow or underflow\",\n 0x12: \"division or modulo by zero\",\n 0x21: \"invalid enum value\",\n 0x31: \"pop() on an empty array\",\n 0x32: \"array index out of bounds\",\n};\n\nfunction hexToUtf8(hex: string): string {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * @param data Raw revert data from the node, with or without the 0x prefix.\n * @returns The decoded reason, or undefined when the payload is not a shape\n * this understands — callers should fall back to the RPC error text rather\n * than presenting a guess.\n */\nexport function decodeRevertReason(data: unknown): string | undefined {\n if (typeof data !== \"string\" || data.length === 0) return undefined;\n const clean = data.startsWith(\"0x\") ? data.slice(2) : data;\n if (!/^[0-9a-fA-F]*$/.test(clean)) return undefined;\n\n if (clean.startsWith(ERROR_STRING_SELECTOR)) {\n // selector(8) + offset(64) + length(64) + payload\n if (clean.length < 136) return undefined;\n const declared = Number.parseInt(clean.slice(72, 136), 16);\n if (!Number.isSafeInteger(declared) || declared <= 0) return undefined;\n const available = (clean.length - 136) / 2;\n // Refuse a payload that promises more than it carries instead of padding\n // the difference with NULs and calling it a revert reason.\n if (declared > available) return undefined;\n return hexToUtf8(clean.slice(136, 136 + declared * 2));\n }\n\n if (clean.startsWith(PANIC_SELECTOR)) {\n if (clean.length < 8 + 64) return \"Panic\";\n const code = Number.parseInt(clean.slice(8, 72), 16);\n if (!Number.isSafeInteger(code)) return \"Panic\";\n const known = PANIC_REASONS[code];\n const hex = `0x${code.toString(16).padStart(2, \"0\")}`;\n return known ? `Panic ${hex}: ${known}` : `Panic ${hex}`;\n }\n\n return undefined;\n}\n\n/** Decoded reason if available, otherwise the node's own message. */\nexport function resolveRevertReason(\n data: unknown,\n fallbackMessage: string,\n): string {\n return (\n decodeRevertReason(data) ??\n (fallbackMessage.includes(\"revert\")\n ? fallbackMessage\n : \"Transaction reverted\")\n );\n}\n","/**\n * Shared NameResolver instance for the name-resolution hooks.\n *\n * useResolveName and useLookupAddress each carried an identical getResolver\n * with its own module-level singleton, so the two directions of the same\n * lookup ran against separate resolvers and separate caches. One definition,\n * one instance.\n */\nimport { NameResolver } from \"@naculus/connect-core\";\nimport type { NameResolverConfig } from \"@naculus/connect-core\";\n\nlet sharedResolver: NameResolver | null = null;\n\n/**\n * @param config When supplied, returns a dedicated resolver rather than the\n * shared one — a caller asking for specific settings must not be handed an\n * instance configured by someone else.\n */\nexport function getResolver(config?: NameResolverConfig): NameResolver {\n if (config) return new NameResolver(config);\n if (!sharedResolver) sharedResolver = new NameResolver();\n return sharedResolver;\n}\n\n/** Test seam: drop the shared instance. */\nexport function __resetResolverForTests(): void {\n sharedResolver = null;\n}\n","/**\n * Framework-agnostic core of the connect provider.\n *\n * appkit's stated shape is \"write the Stencil components once, generate the\n * React and Vue wrappers\". In practice `react/` carries ~8.5k hand-written\n * lines against `vue/`'s ~280, and only two files in `react/src` contain JSX —\n * the rest is logic wearing React clothes. Web Components also cannot serve\n * React Native or Flutter, so the presentation layer was never going to be the\n * thing worth sharing.\n *\n * This module is the first piece moved out: the state machine and the pure\n * helpers around it, with no React import. Everything here is consumable from\n * Vue, Svelte, or a native binding as-is, and `web3-store.test.ts` asserts the\n * absence of a framework import so the boundary cannot rot back.\n */\nimport { logger } from \"@naculus/connect-core\";\nimport type { ConnectionStatus, Web3State } from \"./types\";\n\n// ── Async helpers ──────────────────────────────────────────────────────\n\nexport function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n label = \"Operation\",\n): Promise<T> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<T>((_, reject) => {\n timeoutId = setTimeout(\n () => reject(new Error(`${label} timed out after ${ms}ms`)),\n ms,\n );\n });\n return Promise.race([promise, timeout]).finally(() => {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n });\n}\n\nexport interface RetryOptions {\n maxRetries: number;\n baseDelay: number;\n label?: string;\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions,\n): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= options.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (attempt < options.maxRetries) {\n const delay = options.baseDelay * 2 ** attempt;\n logger.warn(\n \"appkit/core\",\n `Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n throw lastError;\n}\n\n// ── CAIP normalisation ─────────────────────────────────────────────────\n\n/** Convert EIP-1193 chainChanged values into the CAIP-2 form used by sessions. */\nexport function normalizeEip155ChainId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n try {\n if (value.startsWith(\"eip155:\")) {\n const reference = value.slice(\"eip155:\".length);\n if (!/^\\d+$/.test(reference)) return undefined;\n return `eip155:${BigInt(reference).toString(10)}`;\n }\n if (/^0x[0-9a-f]+$/i.test(value) || /^\\d+$/.test(value)) {\n return `eip155:${BigInt(value).toString(10)}`;\n }\n } catch {\n // Ignore malformed wallet events rather than corrupting session state.\n }\n return undefined;\n}\n\nexport function toEip155Accounts(\n accounts: unknown[],\n chainId: string,\n): string[] {\n const reference = chainId.split(\":\")[1];\n if (!reference) return [];\n return accounts\n .filter(\n (account): account is string =>\n typeof account === \"string\" && account.length > 0,\n )\n .map((account) =>\n account.includes(\":\") ? (account.split(\":\").pop() as string) : account,\n )\n .map((account) => `eip155:${reference}:${account}`);\n}\n\n/**\n * Numeric EIP-155 chain id, or undefined for any other namespace.\n *\n * The previous implementation took the last CAIP segment and ran parseInt over\n * it, which stops at the first non-digit: `solana:5eykt4Us…` became 5 — an\n * EVM chain id — so asking for Solana mainnet's token list returned Goerli's,\n * and `xrpl:0` became chain 0. Anchor the whole reference instead.\n */\nexport function eip155ChainIdToNumber(chainId: string): number | undefined {\n const match = /^eip155:([1-9][0-9]*)$/.exec(chainId);\n if (!match) return undefined;\n const numeric = Number(match[1]);\n return Number.isSafeInteger(numeric) ? numeric : undefined;\n}\n\n// ── State machine ──────────────────────────────────────────────────────\n\nexport type Web3Action =\n | { type: \"SET_STATUS\"; payload: ConnectionStatus }\n | { type: \"SET_SESSION\"; payload: Web3State[\"session\"] }\n | { type: \"SET_ACCOUNTS\"; payload: string[] }\n | { type: \"SET_CHAIN\"; payload: string | null }\n | { type: \"SET_ERROR\"; payload: Error | null }\n | { type: \"RESET\" };\n\nexport const initialWeb3State: Web3State = {\n status: \"disconnected\",\n session: null,\n accounts: [],\n chainId: null,\n error: null,\n};\n\nexport function web3Reducer(state: Web3State, action: Web3Action): Web3State {\n switch (action.type) {\n case \"SET_STATUS\":\n return { ...state, status: action.payload };\n case \"SET_SESSION\":\n return { ...state, session: action.payload };\n case \"SET_ACCOUNTS\":\n return { ...state, accounts: action.payload };\n case \"SET_CHAIN\":\n return { ...state, chainId: action.payload };\n case \"SET_ERROR\":\n return { ...state, error: action.payload };\n case \"RESET\":\n return initialWeb3State;\n default:\n return state;\n }\n}\n"],"mappings":"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","names":["chainNumber","WalletError"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@naculus/connect-appkit-core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@naculus/connect-core": "^0.2.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@naculus/connect-core": "^0.2.0",
|
|
23
|
+
"tsup": "^8.3.6",
|
|
24
|
+
"typescript": "^5.9.3"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/naculus-official/connect-appkit.git"
|
|
34
|
+
},
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"description": "Naculus Connect AppKit — framework-neutral state, chain and token logic shared by the React and Vue bindings",
|
|
37
|
+
"homepage": "https://github.com/naculus-official/connect-appkit#readme",
|
|
38
|
+
"bugs": "https://github.com/naculus-official/connect-appkit/issues",
|
|
39
|
+
"keywords": [
|
|
40
|
+
"web3",
|
|
41
|
+
"wallet",
|
|
42
|
+
"connect",
|
|
43
|
+
"caip-2",
|
|
44
|
+
"framework-agnostic"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"clean": "rm -rf dist",
|
|
49
|
+
"test:run": "vitest run",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|