@usebutr/core 0.4.2 → 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/dist/index.d.ts +400 -340
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +202 -131
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/chain.ts","../src/types/account.ts","../src/types/capabilities.ts","../src/types/platform.ts","../src/types/chains-by-platform.ts","../src/types/connector.ts","../src/types/wallet.ts","../src/types/discoverer.ts","../src/types/errors.ts","../src/storage/persistence.ts","../src/storage/snapshot.ts","../src/types/manager.ts","../src/types/signer.ts","../src/wallet-source.ts","../src/store/reducer.ts","../src/store/shadow-adapter.ts","../src/storage/browser-storage-driver.ts","../src/storage/cookie-storage-driver.ts","../src/storage/wallet-storage.ts","../src/store/wallet-store.ts","../src/wallet-equal.ts","../src/logger.ts","../src/sanitize-icon.ts","../src/encoding/bytes.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { createStore } from "zustand/vanilla";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
+
//#region src/types/account.ts
|
|
5
|
+
/**
|
|
6
|
+
* Build butr's `Account` shape from a wallet address and a resolved
|
|
7
|
+
* `ChainBase`. The composite id (`<chain>:<address>`) is what the
|
|
8
|
+
* reducer uses to compare accounts across refreshes, so every adapter
|
|
9
|
+
* must build accounts through this helper (or keep the format
|
|
10
|
+
* byte-identical).
|
|
11
|
+
*/
|
|
12
|
+
const buildAccount = (address, chain) => ({
|
|
13
|
+
chain,
|
|
14
|
+
id: `${chain.id}:${address}`,
|
|
15
|
+
walletAddress: address
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
4
19
|
//#region src/types/chains-by-platform.ts
|
|
5
20
|
/**
|
|
6
21
|
* Build a fully-populated `ChainsByPlatform` from a partial. Platforms
|
|
@@ -106,7 +121,7 @@ const mapConnectionError = (raw) => {
|
|
|
106
121
|
};
|
|
107
122
|
|
|
108
123
|
//#endregion
|
|
109
|
-
//#region src/types/
|
|
124
|
+
//#region src/types/platform.ts
|
|
110
125
|
/**
|
|
111
126
|
* Canonical list of supported chain platforms. The single runtime source
|
|
112
127
|
* of truth: `ChainPlatform` is derived from it, and storage validators
|
|
@@ -121,18 +136,6 @@ const CHAIN_PLATFORMS = [
|
|
|
121
136
|
"bitcoin",
|
|
122
137
|
"polkadot"
|
|
123
138
|
];
|
|
124
|
-
/**
|
|
125
|
-
* Build butr's `Account` shape from a wallet address and a resolved
|
|
126
|
-
* `ChainBase`. The composite id (`<chain>:<address>`) is what the
|
|
127
|
-
* reducer uses to compare accounts across refreshes, so every adapter
|
|
128
|
-
* must build accounts through this helper (or keep the format
|
|
129
|
-
* byte-identical).
|
|
130
|
-
*/
|
|
131
|
-
const buildAccount = (address, chain) => ({
|
|
132
|
-
chain,
|
|
133
|
-
id: `${chain.id}:${address}`,
|
|
134
|
-
walletAddress: address
|
|
135
|
-
});
|
|
136
139
|
|
|
137
140
|
//#endregion
|
|
138
141
|
//#region src/wallet-source.ts
|
|
@@ -145,6 +148,134 @@ const buildAccount = (address, chain) => ({
|
|
|
145
148
|
*/
|
|
146
149
|
const createWalletSource = (subscribe) => ({ subscribe });
|
|
147
150
|
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/store/shadow-adapter.ts
|
|
153
|
+
/**
|
|
154
|
+
* Error thrown when a method is called on a shadow adapter; the
|
|
155
|
+
* placeholder `WalletAdapter` that the store seeds into the pool when
|
|
156
|
+
* an `initialState` is provided (e.g. from a server-rendered cookie
|
|
157
|
+
* snapshot). Shadow adapters carry the identity and account data of a
|
|
158
|
+
* previously-connected wallet, but the live wallet extension hasn't
|
|
159
|
+
* been verified yet; the silent reconnect happens asynchronously
|
|
160
|
+
* after mount.
|
|
161
|
+
*
|
|
162
|
+
* UI code that gates affordances on `wallet.connector.capabilities.*`
|
|
163
|
+
* never reaches a shadow method (capabilities are all `false`). Code
|
|
164
|
+
* that calls through anyway hits this typed error, which is the
|
|
165
|
+
* correct loud failure: the consumer ignored the capability gate.
|
|
166
|
+
*
|
|
167
|
+
* Consumers wanting to wait out the reconnecting window should branch
|
|
168
|
+
* on whether `connectorId` is in `state.reconnectingIds`.
|
|
169
|
+
*/
|
|
170
|
+
var ShadowConnectorError = class extends Error {
|
|
171
|
+
code = "BUTR_RECONNECTING";
|
|
172
|
+
connectorId;
|
|
173
|
+
method;
|
|
174
|
+
constructor(method, connectorId) {
|
|
175
|
+
super(`[butr] ${method} called on shadow connector "${connectorId}". Wait for silent reconnect to complete (check reconnectingIds.has(id) before calling).`);
|
|
176
|
+
this.name = "ShadowConnectorError";
|
|
177
|
+
this.connectorId = connectorId;
|
|
178
|
+
this.method = method;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const ALL_FALSE_CAPABILITIES = Object.freeze({
|
|
182
|
+
getBalance: false,
|
|
183
|
+
getTransactionReceipt: false,
|
|
184
|
+
requestAccounts: false,
|
|
185
|
+
sendTransaction: false,
|
|
186
|
+
signIn: false,
|
|
187
|
+
signMessage: false,
|
|
188
|
+
signTransaction: false,
|
|
189
|
+
subscribe: false,
|
|
190
|
+
switchAccount: false,
|
|
191
|
+
switchChain: false
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Builds a placeholder `WalletAdapter` from a persisted pool entry.
|
|
195
|
+
*
|
|
196
|
+
* Used by `createWalletStore` when `WalletManagerConfig.initialState`
|
|
197
|
+
* is provided: each stored entry becomes a `ConnectedWallet` whose
|
|
198
|
+
* `connector` is one of these. The store flips `isHydrated` true
|
|
199
|
+
* synchronously and exposes the data through the usual hooks
|
|
200
|
+
* (`useActiveWallet`, `useConnectedWallets`, …), but the connector
|
|
201
|
+
* can't actually talk to a wallet yet, so its capabilities are all
|
|
202
|
+
* `false` and its methods throw `ShadowConnectorError` if called.
|
|
203
|
+
*
|
|
204
|
+
* The hydration coordinator's silent-reconnect pass upgrades each
|
|
205
|
+
* shadow to a live `WalletAdapter` by calling `createConnector(id)`
|
|
206
|
+
* (which only succeeds once the live adapter has been announced via
|
|
207
|
+
* discovery or registered explicitly) and replacing the pool entry.
|
|
208
|
+
* On success the connector id is removed from `reconnectingIds`; on
|
|
209
|
+
* failure the entry is dropped from the pool and storage.
|
|
210
|
+
*
|
|
211
|
+
* The entry's `name` is required (the storage validator rejects
|
|
212
|
+
* entries without it); `icon` is optional only because some live
|
|
213
|
+
* adapters genuinely have no icon to begin with.
|
|
214
|
+
*/
|
|
215
|
+
const createShadowAdapter = (entry) => {
|
|
216
|
+
const id = entry.connectorId;
|
|
217
|
+
const name = entry.name;
|
|
218
|
+
const icon = entry.icon;
|
|
219
|
+
const reject = (method) => Promise.reject(new ShadowConnectorError(method, id));
|
|
220
|
+
const base = {
|
|
221
|
+
capabilities: ALL_FALSE_CAPABILITIES,
|
|
222
|
+
connect: () => reject("connect"),
|
|
223
|
+
disconnect: () => reject("disconnect"),
|
|
224
|
+
getAccount: () => reject("getAccount"),
|
|
225
|
+
getBalance: () => reject("getBalance"),
|
|
226
|
+
getSigner: () => reject("getSigner"),
|
|
227
|
+
getTransactionReceipt: () => reject("getTransactionReceipt"),
|
|
228
|
+
icon,
|
|
229
|
+
id,
|
|
230
|
+
name,
|
|
231
|
+
sendTx: () => reject("sendTx"),
|
|
232
|
+
sendTxToChain: () => reject("sendTxToChain"),
|
|
233
|
+
signMessage: () => reject("signMessage"),
|
|
234
|
+
switchChain: () => reject("switchChain")
|
|
235
|
+
};
|
|
236
|
+
switch (entry.chainPlatform) {
|
|
237
|
+
case "bitcoin": return {
|
|
238
|
+
...base,
|
|
239
|
+
chainPlatform: "bitcoin"
|
|
240
|
+
};
|
|
241
|
+
case "evm": return {
|
|
242
|
+
...base,
|
|
243
|
+
chainPlatform: "evm"
|
|
244
|
+
};
|
|
245
|
+
case "sui": return {
|
|
246
|
+
...base,
|
|
247
|
+
chainPlatform: "sui"
|
|
248
|
+
};
|
|
249
|
+
case "svm": return {
|
|
250
|
+
...base,
|
|
251
|
+
chainPlatform: "svm"
|
|
252
|
+
};
|
|
253
|
+
case "polkadot": return {
|
|
254
|
+
...base,
|
|
255
|
+
chainPlatform: "polkadot"
|
|
256
|
+
};
|
|
257
|
+
default:
|
|
258
|
+
entry.chainPlatform;
|
|
259
|
+
throw new Error(`[butr] unknown chainPlatform: ${entry.chainPlatform}`);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Type guard. Returns true when an adapter is a placeholder created
|
|
264
|
+
* by `createShadowAdapter`. Useful for the hydration coordinator
|
|
265
|
+
* (which needs to know which pool entries still need upgrading) and
|
|
266
|
+
* for consumers writing wagmi-style "is this connection verified yet"
|
|
267
|
+
* checks without subscribing to `reconnectingIds` directly.
|
|
268
|
+
*
|
|
269
|
+
* Detection is structural: a shadow has all capabilities set to false.
|
|
270
|
+
* Live adapters always advertise at least one capability (every wallet
|
|
271
|
+
* surface includes `getBalance`, `signMessage`, `switchChain` as
|
|
272
|
+
* required methods, and adapter constructors set their flags
|
|
273
|
+
* accordingly).
|
|
274
|
+
*/
|
|
275
|
+
const isShadowAdapter = (adapter) => {
|
|
276
|
+
return Object.values(adapter.capabilities).every((flag) => !flag);
|
|
277
|
+
};
|
|
278
|
+
|
|
148
279
|
//#endregion
|
|
149
280
|
//#region src/logger.ts
|
|
150
281
|
const logWarn = (...args) => {
|
|
@@ -749,118 +880,6 @@ const reducer = (state, event) => {
|
|
|
749
880
|
}
|
|
750
881
|
};
|
|
751
882
|
|
|
752
|
-
//#endregion
|
|
753
|
-
//#region src/store/shadow-adapter.ts
|
|
754
|
-
/**
|
|
755
|
-
* Error thrown when a method is called on a shadow adapter; the
|
|
756
|
-
* placeholder `WalletAdapter` that the store seeds into the pool when
|
|
757
|
-
* an `initialState` is provided (e.g. from a server-rendered cookie
|
|
758
|
-
* snapshot). Shadow adapters carry the identity and account data of a
|
|
759
|
-
* previously-connected wallet, but the live wallet extension hasn't
|
|
760
|
-
* been verified yet; the silent reconnect happens asynchronously
|
|
761
|
-
* after mount.
|
|
762
|
-
*
|
|
763
|
-
* UI code that gates affordances on `wallet.connector.capabilities.*`
|
|
764
|
-
* never reaches a shadow method (capabilities are all `false`). Code
|
|
765
|
-
* that calls through anyway hits this typed error, which is the
|
|
766
|
-
* correct loud failure: the consumer ignored the capability gate.
|
|
767
|
-
*
|
|
768
|
-
* Consumers wanting to wait out the reconnecting window should branch
|
|
769
|
-
* on whether `connectorId` is in `state.reconnectingIds`.
|
|
770
|
-
*/
|
|
771
|
-
var ShadowConnectorError = class extends Error {
|
|
772
|
-
code = "BUTR_RECONNECTING";
|
|
773
|
-
connectorId;
|
|
774
|
-
method;
|
|
775
|
-
constructor(method, connectorId) {
|
|
776
|
-
super(`[butr] ${method} called on shadow connector "${connectorId}" — wait for silent reconnect to complete (check reconnectingIds.has(id) before calling).`);
|
|
777
|
-
this.name = "ShadowConnectorError";
|
|
778
|
-
this.connectorId = connectorId;
|
|
779
|
-
this.method = method;
|
|
780
|
-
}
|
|
781
|
-
};
|
|
782
|
-
const ALL_FALSE_CAPABILITIES = Object.freeze({
|
|
783
|
-
getBalance: false,
|
|
784
|
-
getTransactionReceipt: false,
|
|
785
|
-
requestAccounts: false,
|
|
786
|
-
sendTransaction: false,
|
|
787
|
-
signIn: false,
|
|
788
|
-
signMessage: false,
|
|
789
|
-
signTransaction: false,
|
|
790
|
-
subscribe: false,
|
|
791
|
-
switchAccount: false,
|
|
792
|
-
switchChain: false
|
|
793
|
-
});
|
|
794
|
-
/**
|
|
795
|
-
* Builds a placeholder `WalletAdapter` from a persisted pool entry.
|
|
796
|
-
*
|
|
797
|
-
* Used by `createWalletStore` when `WalletManagerConfig.initialState`
|
|
798
|
-
* is provided: each stored entry becomes a `ConnectedWallet` whose
|
|
799
|
-
* `connector` is one of these. The store flips `isHydrated` true
|
|
800
|
-
* synchronously and exposes the data through the usual hooks
|
|
801
|
-
* (`useActiveWallet`, `useConnectedWallets`, …), but the connector
|
|
802
|
-
* can't actually talk to a wallet yet, so its capabilities are all
|
|
803
|
-
* `false` and its methods throw `ShadowConnectorError` if called.
|
|
804
|
-
*
|
|
805
|
-
* The hydration coordinator's silent-reconnect pass upgrades each
|
|
806
|
-
* shadow to a live `WalletAdapter` by calling `createConnector(id)`
|
|
807
|
-
* (which only succeeds once the live adapter has been announced via
|
|
808
|
-
* discovery or registered explicitly) and replacing the pool entry.
|
|
809
|
-
* On success the connector id is removed from `reconnectingIds`; on
|
|
810
|
-
* failure the entry is dropped from the pool and storage.
|
|
811
|
-
*
|
|
812
|
-
* The entry's `name` is required (the storage validator rejects
|
|
813
|
-
* entries without it); `icon` is optional only because some live
|
|
814
|
-
* adapters genuinely have no icon to begin with.
|
|
815
|
-
*/
|
|
816
|
-
const createShadowAdapter = (entry) => {
|
|
817
|
-
const id = entry.connectorId;
|
|
818
|
-
const name = entry.name;
|
|
819
|
-
const icon = entry.icon;
|
|
820
|
-
const reject = (method) => Promise.reject(new ShadowConnectorError(method, id));
|
|
821
|
-
const base = {
|
|
822
|
-
capabilities: ALL_FALSE_CAPABILITIES,
|
|
823
|
-
connect: () => reject("connect"),
|
|
824
|
-
disconnect: () => reject("disconnect"),
|
|
825
|
-
getAccount: () => reject("getAccount"),
|
|
826
|
-
getBalance: () => reject("getBalance"),
|
|
827
|
-
getSigner: () => reject("getSigner"),
|
|
828
|
-
getTransactionReceipt: () => reject("getTransactionReceipt"),
|
|
829
|
-
icon,
|
|
830
|
-
id,
|
|
831
|
-
name,
|
|
832
|
-
sendTx: () => reject("sendTx"),
|
|
833
|
-
sendTxToChain: () => reject("sendTxToChain"),
|
|
834
|
-
signMessage: () => reject("signMessage"),
|
|
835
|
-
switchChain: () => reject("switchChain")
|
|
836
|
-
};
|
|
837
|
-
switch (entry.chainPlatform) {
|
|
838
|
-
case "bitcoin": return {
|
|
839
|
-
...base,
|
|
840
|
-
chainPlatform: "bitcoin"
|
|
841
|
-
};
|
|
842
|
-
case "evm": return {
|
|
843
|
-
...base,
|
|
844
|
-
chainPlatform: "evm"
|
|
845
|
-
};
|
|
846
|
-
case "sui": return {
|
|
847
|
-
...base,
|
|
848
|
-
chainPlatform: "sui"
|
|
849
|
-
};
|
|
850
|
-
case "svm": return {
|
|
851
|
-
...base,
|
|
852
|
-
chainPlatform: "svm"
|
|
853
|
-
};
|
|
854
|
-
case "polkadot": return {
|
|
855
|
-
...base,
|
|
856
|
-
chainPlatform: "polkadot"
|
|
857
|
-
};
|
|
858
|
-
default:
|
|
859
|
-
entry.chainPlatform;
|
|
860
|
-
throw new Error(`[butr] unknown chainPlatform: ${entry.chainPlatform}`);
|
|
861
|
-
}
|
|
862
|
-
};
|
|
863
|
-
|
|
864
883
|
//#endregion
|
|
865
884
|
//#region src/store/wallet-store-helpers.ts
|
|
866
885
|
/** Run an async operation fire-and-forget, calling onError if it throws. */
|
|
@@ -1370,10 +1389,16 @@ const readWalletSnapshot = (source, options = {}) => {
|
|
|
1370
1389
|
//#region src/wallet-equal.ts
|
|
1371
1390
|
/**
|
|
1372
1391
|
* Two wallet snapshots are equivalent for selector purposes iff they
|
|
1373
|
-
* share
|
|
1374
|
-
* id. Used by `useStoreWithEqualityFn` consumers
|
|
1375
|
-
* selected-wallet, useWalletEntry) to suppress spurious
|
|
1376
|
-
* when the underlying Map churns but the resolved entry
|
|
1392
|
+
* share the same adapter instance, active account address, and active
|
|
1393
|
+
* account chain id. Used by `useStoreWithEqualityFn` consumers
|
|
1394
|
+
* (active-wallet, selected-wallet, useWalletEntry) to suppress spurious
|
|
1395
|
+
* re-renders when the underlying Map churns but the resolved entry
|
|
1396
|
+
* hasn't changed.
|
|
1397
|
+
*
|
|
1398
|
+
* The adapter is compared by reference, not by `connector.id`: hydration
|
|
1399
|
+
* replaces a shadow adapter with the live one under an unchanged id and
|
|
1400
|
+
* address, so an id comparison reports "equal" and leaves consumers
|
|
1401
|
+
* holding a placeholder whose every method throws ShadowConnectorError.
|
|
1377
1402
|
*
|
|
1378
1403
|
* Hoisted to its own module so the equivalence rule lives in one place;
|
|
1379
1404
|
* if we ever extend the snapshot (e.g. to consider `accounts.length`),
|
|
@@ -1382,7 +1407,7 @@ const readWalletSnapshot = (source, options = {}) => {
|
|
|
1382
1407
|
const walletEqual = (a, b) => {
|
|
1383
1408
|
if (a === b) return true;
|
|
1384
1409
|
if (!a || !b) return false;
|
|
1385
|
-
return a.connector
|
|
1410
|
+
return a.connector === b.connector && a.account.walletAddress === b.account.walletAddress && a.account.chain.id === b.account.chain.id;
|
|
1386
1411
|
};
|
|
1387
1412
|
|
|
1388
1413
|
//#endregion
|
|
@@ -1426,6 +1451,10 @@ const sanitizeIcon = (icon) => {
|
|
|
1426
1451
|
* - {@link bytesToHexPrefixed} returns `0x`-prefixed hex (EVM, Polkadot).
|
|
1427
1452
|
* - {@link hexToBytes} tolerantly strips an optional `0x` (all callers).
|
|
1428
1453
|
*/
|
|
1454
|
+
/** Bitcoin/Solana alphabet; omits the visually ambiguous `0`, `O`, `I`, `l`. */
|
|
1455
|
+
const BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
1456
|
+
const BASE58_INDEX = /* @__PURE__ */ new Map();
|
|
1457
|
+
for (let i = 0; i < 58; i += 1) BASE58_INDEX.set(BASE58_ALPHABET[i] ?? "", i);
|
|
1429
1458
|
/** Bare lowercase hex, no `0x` prefix (Bitcoin, Ledger). */
|
|
1430
1459
|
const bytesToHex = (bytes) => {
|
|
1431
1460
|
let hex = "";
|
|
@@ -1466,7 +1495,49 @@ const bytesToBase64 = (bytes) => {
|
|
|
1466
1495
|
for (const byte of bytes) binary += String.fromCodePoint(byte);
|
|
1467
1496
|
return btoa(binary);
|
|
1468
1497
|
};
|
|
1498
|
+
/**
|
|
1499
|
+
* `Uint8Array` → base58 (Solana addresses and signatures). Leading zero
|
|
1500
|
+
* bytes are significant in base58 and survive the BigInt round-trip only
|
|
1501
|
+
* because they're re-prefixed as `1`s afterwards.
|
|
1502
|
+
*/
|
|
1503
|
+
const bytesToBase58 = (bytes) => {
|
|
1504
|
+
let intVal = 0n;
|
|
1505
|
+
for (const byte of bytes) intVal = intVal << 8n | BigInt(byte);
|
|
1506
|
+
let out = "";
|
|
1507
|
+
while (intVal > 0n) {
|
|
1508
|
+
const remainder = intVal % 58n;
|
|
1509
|
+
intVal /= 58n;
|
|
1510
|
+
out = BASE58_ALPHABET[Number(remainder)] + out;
|
|
1511
|
+
}
|
|
1512
|
+
for (const byte of bytes) {
|
|
1513
|
+
if (byte !== 0) break;
|
|
1514
|
+
out = `1${out}`;
|
|
1515
|
+
}
|
|
1516
|
+
return out;
|
|
1517
|
+
};
|
|
1518
|
+
/** Decode base58 into raw bytes. Throws on characters outside the alphabet
|
|
1519
|
+
* rather than silently dropping them. */
|
|
1520
|
+
const base58ToBytes = (input) => {
|
|
1521
|
+
let intVal = 0n;
|
|
1522
|
+
let leadingZeros = 0;
|
|
1523
|
+
let stillLeading = true;
|
|
1524
|
+
for (const char of input) {
|
|
1525
|
+
if (stillLeading && char === "1") leadingZeros += 1;
|
|
1526
|
+
else stillLeading = false;
|
|
1527
|
+
const digit = BASE58_INDEX.get(char);
|
|
1528
|
+
if (digit === void 0) throw new Error(`Invalid base58 character "${char}"`);
|
|
1529
|
+
intVal = intVal * 58n + BigInt(digit);
|
|
1530
|
+
}
|
|
1531
|
+
const bytes = [];
|
|
1532
|
+
const byteMask = 255n;
|
|
1533
|
+
while (intVal > 0n) {
|
|
1534
|
+
bytes.unshift(Number(intVal & byteMask));
|
|
1535
|
+
intVal >>= 8n;
|
|
1536
|
+
}
|
|
1537
|
+
for (let i = 0; i < leadingZeros; i += 1) bytes.unshift(0);
|
|
1538
|
+
return Uint8Array.from(bytes);
|
|
1539
|
+
};
|
|
1469
1540
|
|
|
1470
1541
|
//#endregion
|
|
1471
|
-
export { CHAIN_PLATFORMS, EMPTY_SNAPSHOT, WalletStorage, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createWalletSource, createWalletStore, hexToBytes, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
1542
|
+
export { CHAIN_PLATFORMS, EMPTY_SNAPSHOT, ShadowConnectorError, WalletStorage, base58ToBytes, base64ToBytes, buildAccount, buildChainsByPlatform, bytesToBase58, bytesToBase64, bytesToHex, bytesToHexPrefixed, createBrowserStorageDriver, createCookieStorageDriver, createMemoryStorageDriver, createWalletSource, createWalletStore, hexToBytes, isShadowAdapter, logError, logWarn, mapConnectionError, readWalletSnapshot, sanitizeIcon, walletEqual };
|
|
1472
1543
|
//# sourceMappingURL=index.js.map
|