@gibs/common 1.13.1 → 1.17.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/README.md CHANGED
@@ -48,11 +48,33 @@ A collection of essential blockchain utilities and helpers that provide foundati
48
48
  ## 📦 Installation
49
49
 
50
50
  ```sh
51
- npm install @gibs/common
51
+ npm install @gibs/common viem
52
52
  # or
53
- yarn add @gibs/common
53
+ yarn add @gibs/common viem
54
54
  ```
55
55
 
56
+ ## Ways to use the package
57
+
58
+ The package ships two builds of the same code. The `exports` map picks one, so
59
+ you need no configuration.
60
+
61
+ | Option | What you write | What loads |
62
+ |---|---|---|
63
+ | ECMAScript modules | `import { memoizeByKey } from '@gibs/common/cache'` | `dist/cache.js` |
64
+ | CommonJS | `const { memoizeByKey } = require('@gibs/common/cache')` | `dist/cjs/cache.js` |
65
+ | React Native (Metro) | either of the above | `import` gets `dist/`, `require` gets `dist/cjs/` |
66
+ | React Native (jest) | either of the above | `dist/cjs/` |
67
+
68
+ React Native 0.77 or later needs no change to `metro.config.js`, no
69
+ `resolveRequest` hook, no jest `transformIgnorePatterns` and no polyfill.
70
+ It runs on React Native's own `URL` and `URLSearchParams`, which React Native
71
+ 0.77 implements only in part: no code in the package reads them.
72
+ Metro's default configuration in React Native 0.79 or later reads the
73
+ `exports` map. Metro in React Native 0.77 and 0.78 ignores
74
+ `exports`: it reads the `react-native` field for the root, and a folder the
75
+ package ships for each subpath, such as `cache/package.json`, which points at
76
+ the CommonJS build.
77
+
56
78
  ## 📖 API Examples
57
79
 
58
80
  ### Client (`@gibs/common/client`)
@@ -445,6 +467,7 @@ console.log(defaultBatchConfig)
445
467
  | `@gibs/common/serialize` | JSON serialization with BigInt support |
446
468
  | `@gibs/common/multicall` | Batch contract call utilities |
447
469
  | `@gibs/common/types` | TypeScript type definitions |
470
+ | `@gibs/common/url` | Request addresses built and read without `URL` or `URLSearchParams` |
448
471
 
449
472
  ### Key Functions
450
473
 
@@ -493,6 +516,12 @@ function ttlMemoizeSingle<A extends unknown[], B>(
493
516
  fn: (...a: A) => B,
494
517
  ttl?: number
495
518
  ): (...a: A) => B
519
+
520
+ // One answer per resolver key, never expired; `cache` is a Map you can evict from
521
+ function memoizeByKey<A extends unknown[], B, K>(
522
+ fn: (...args: A) => B,
523
+ resolver: (...args: A) => K
524
+ ): ((...args: A) => B) & { cache: Map<K, B> }
496
525
  ```
497
526
 
498
527
  #### Serialization
@@ -560,8 +589,9 @@ interface SerializedBigInt {
560
589
 
561
590
  ## 🔗 Dependencies
562
591
 
563
- - `viem`: Type-safe Ethereum library for blockchain interactions
564
- - `lodash`: Utility functions for data manipulation and memoization
592
+ - `viem` (peer dependency): Type-safe Ethereum library for blockchain interactions
593
+
594
+ There are no other runtime dependencies.
565
595
 
566
596
  ## 📝 Best Practices
567
597
 
@@ -0,0 +1,6 @@
1
+ {
2
+ "main": "../dist/cjs/cache.js",
3
+ "module": "../dist/cache.js",
4
+ "types": "../dist/cache.d.ts",
5
+ "react-native": "../dist/cjs/cache.js"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "main": "../dist/cjs/client.js",
3
+ "module": "../dist/client.js",
4
+ "types": "../dist/client.d.ts",
5
+ "react-native": "../dist/cjs/client.js"
6
+ }
package/dist/cache.d.ts CHANGED
@@ -12,3 +12,28 @@ export declare const maxMemoize: <A extends unknown[], B>(fn: (...a: A) => B, ma
12
12
  * @returns the memoized function
13
13
  */
14
14
  export declare const ttlMemoizeSingle: <A extends unknown[], B>(fn: (...a: A) => B, ttl?: number) => (...a: A) => B;
15
+ /**
16
+ * A memoized function, with the cache it reads exposed so a caller can evict
17
+ * one answer or drop them all.
18
+ */
19
+ export type KeyedMemoized<A extends unknown[], B, K> = ((...args: A) => B) & {
20
+ /**
21
+ * The answers held so far, keyed by the resolver's output. Each call reads
22
+ * this property afresh, so assigning a new `Map` resets the cache.
23
+ */
24
+ cache: Map<K, B>;
25
+ };
26
+ /**
27
+ * Memoizes a function under a key the caller computes from its arguments.
28
+ *
29
+ * This is the subset of `lodash.memoize` the packages used: one answer per
30
+ * key, never expired, with `cache.delete` and `cache.clear` for eviction. As
31
+ * with lodash, the `cache` property may be replaced outright. It
32
+ * exists so the published packages carry no lodash-es, whose ECMAScript-module
33
+ * only build a React Native jest run cannot load from `node_modules`.
34
+ *
35
+ * @param fn - the function to memoize
36
+ * @param resolver - computes the cache key from the arguments
37
+ * @returns the memoized function, with its `cache`
38
+ */
39
+ export declare const memoizeByKey: <A extends unknown[], B, K>(fn: (...args: A) => B, resolver: (...args: A) => K) => KeyedMemoized<A, B, K>;
package/dist/cache.js CHANGED
@@ -42,3 +42,30 @@ export const ttlMemoizeSingle = (fn, ttl = hour1) => {
42
42
  return result;
43
43
  };
44
44
  };
45
+ /**
46
+ * Memoizes a function under a key the caller computes from its arguments.
47
+ *
48
+ * This is the subset of `lodash.memoize` the packages used: one answer per
49
+ * key, never expired, with `cache.delete` and `cache.clear` for eviction. As
50
+ * with lodash, the `cache` property may be replaced outright. It
51
+ * exists so the published packages carry no lodash-es, whose ECMAScript-module
52
+ * only build a React Native jest run cannot load from `node_modules`.
53
+ *
54
+ * @param fn - the function to memoize
55
+ * @param resolver - computes the cache key from the arguments
56
+ * @returns the memoized function, with its `cache`
57
+ */
58
+ export const memoizeByKey = (fn, resolver) => {
59
+ const memoized = Object.assign((...args) => {
60
+ const key = resolver(...args);
61
+ // Read the property on every call: a caller may have replaced the Map.
62
+ const { cache } = memoized;
63
+ if (cache.has(key)) {
64
+ return cache.get(key);
65
+ }
66
+ const result = fn(...args);
67
+ cache.set(key, result);
68
+ return result;
69
+ }, { cache: new Map() });
70
+ return memoized;
71
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Asserts that a value is defined (not null, undefined, or falsy)
3
+ * Throws a descriptive error if the value is falsy
4
+ *
5
+ * @param value - The value to check
6
+ * @param context - Context description for the error message
7
+ * @returns The value if defined
8
+ * @throws Error if value is falsy
9
+ */
10
+ export declare function ensureResult<T>(value: T | null | undefined | false | 0, context: string): T;
11
+ /**
12
+ * Type guard that asserts a value is defined
13
+ * Similar to ensureResult but uses TypeScript's asserts syntax
14
+ *
15
+ * @param value - The value to check
16
+ * @param message - Error message if assertion fails
17
+ */
18
+ export declare function assertDefined<T>(value: T | null | undefined, message: string): asserts value is T;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ensureResult = ensureResult;
4
+ exports.assertDefined = assertDefined;
5
+ /**
6
+ * Asserts that a value is defined (not null, undefined, or falsy)
7
+ * Throws a descriptive error if the value is falsy
8
+ *
9
+ * @param value - The value to check
10
+ * @param context - Context description for the error message
11
+ * @returns The value if defined
12
+ * @throws Error if value is falsy
13
+ */
14
+ function ensureResult(value, context) {
15
+ if (!value) {
16
+ throw new Error(`${context}: Expected result but got ${value}`);
17
+ }
18
+ return value;
19
+ }
20
+ /**
21
+ * Type guard that asserts a value is defined
22
+ * Similar to ensureResult but uses TypeScript's asserts syntax
23
+ *
24
+ * @param value - The value to check
25
+ * @param message - Error message if assertion fails
26
+ */
27
+ function assertDefined(value, message) {
28
+ if (value === null || value === undefined) {
29
+ throw new Error(message);
30
+ }
31
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Memoize a function result and return a single value
3
+ * @param fn the function to memoize
4
+ * @param max the maximum number of values to cache
5
+ * @returns the memoized function
6
+ */
7
+ export declare const maxMemoize: <A extends unknown[], B>(fn: (...a: A) => B, max?: number) => (...a: A) => B | undefined;
8
+ /**
9
+ * Memoize a function result and return a single value
10
+ * @param fn the function to memoize
11
+ * @param ttl the time to live for the cache
12
+ * @returns the memoized function
13
+ */
14
+ export declare const ttlMemoizeSingle: <A extends unknown[], B>(fn: (...a: A) => B, ttl?: number) => (...a: A) => B;
15
+ /**
16
+ * A memoized function, with the cache it reads exposed so a caller can evict
17
+ * one answer or drop them all.
18
+ */
19
+ export type KeyedMemoized<A extends unknown[], B, K> = ((...args: A) => B) & {
20
+ /**
21
+ * The answers held so far, keyed by the resolver's output. Each call reads
22
+ * this property afresh, so assigning a new `Map` resets the cache.
23
+ */
24
+ cache: Map<K, B>;
25
+ };
26
+ /**
27
+ * Memoizes a function under a key the caller computes from its arguments.
28
+ *
29
+ * This is the subset of `lodash.memoize` the packages used: one answer per
30
+ * key, never expired, with `cache.delete` and `cache.clear` for eviction. As
31
+ * with lodash, the `cache` property may be replaced outright. It
32
+ * exists so the published packages carry no lodash-es, whose ECMAScript-module
33
+ * only build a React Native jest run cannot load from `node_modules`.
34
+ *
35
+ * @param fn - the function to memoize
36
+ * @param resolver - computes the cache key from the arguments
37
+ * @returns the memoized function, with its `cache`
38
+ */
39
+ export declare const memoizeByKey: <A extends unknown[], B, K>(fn: (...args: A) => B, resolver: (...args: A) => K) => KeyedMemoized<A, B, K>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memoizeByKey = exports.ttlMemoizeSingle = exports.maxMemoize = void 0;
4
+ const serialize_js_1 = require("./serialize.js");
5
+ /**
6
+ * Memoize a function result and return a single value
7
+ * @param fn the function to memoize
8
+ * @param max the maximum number of values to cache
9
+ * @returns the memoized function
10
+ */
11
+ const maxMemoize = (fn, max = 1024) => {
12
+ const cache = new Map();
13
+ return (...a) => {
14
+ const key = JSON.stringify(a, serialize_js_1.jsonAnyStringify);
15
+ const existing = cache.get(key);
16
+ if (cache.has(key)) {
17
+ return existing;
18
+ }
19
+ for (const k of cache.keys()) {
20
+ if (cache.size < max)
21
+ break;
22
+ cache.delete(k);
23
+ }
24
+ const result = fn(...a);
25
+ cache.set(key, result);
26
+ return result;
27
+ };
28
+ };
29
+ exports.maxMemoize = maxMemoize;
30
+ const hour1 = 1000 * 60 * 60;
31
+ /**
32
+ * Memoize a function result and return a single value
33
+ * @param fn the function to memoize
34
+ * @param ttl the time to live for the cache
35
+ * @returns the memoized function
36
+ */
37
+ const ttlMemoizeSingle = (fn, ttl = hour1) => {
38
+ let cache = null;
39
+ return (...a) => {
40
+ const now = Date.now();
41
+ if (cache && cache.timestamp + ttl > now) {
42
+ return cache.result;
43
+ }
44
+ const result = fn(...a);
45
+ cache = { timestamp: now, result };
46
+ return result;
47
+ };
48
+ };
49
+ exports.ttlMemoizeSingle = ttlMemoizeSingle;
50
+ /**
51
+ * Memoizes a function under a key the caller computes from its arguments.
52
+ *
53
+ * This is the subset of `lodash.memoize` the packages used: one answer per
54
+ * key, never expired, with `cache.delete` and `cache.clear` for eviction. As
55
+ * with lodash, the `cache` property may be replaced outright. It
56
+ * exists so the published packages carry no lodash-es, whose ECMAScript-module
57
+ * only build a React Native jest run cannot load from `node_modules`.
58
+ *
59
+ * @param fn - the function to memoize
60
+ * @param resolver - computes the cache key from the arguments
61
+ * @returns the memoized function, with its `cache`
62
+ */
63
+ const memoizeByKey = (fn, resolver) => {
64
+ const memoized = Object.assign((...args) => {
65
+ const key = resolver(...args);
66
+ // Read the property on every call: a caller may have replaced the Map.
67
+ const { cache } = memoized;
68
+ if (cache.has(key)) {
69
+ return cache.get(key);
70
+ }
71
+ const result = fn(...args);
72
+ cache.set(key, result);
73
+ return result;
74
+ }, { cache: new Map() });
75
+ return memoized;
76
+ };
77
+ exports.memoizeByKey = memoizeByKey;
@@ -0,0 +1,48 @@
1
+ import { type Chain, type HttpTransportConfig, type PublicClient } from 'viem';
2
+ export { MAX_SAME_METHOD_CALLS_PER_SECOND } from './rpcPacer.js';
3
+ /**
4
+ * JSON-RPC request batching config. When enabled, viem coalesces requests made
5
+ * within `wait` milliseconds (up to `batchSize`) into ONE HTTP POST carrying a
6
+ * JSON-RPC array body. This is the default because it sharply cuts request
7
+ * volume on nodes that support it.
8
+ *
9
+ * Note: some public nodes (notably some Binance Smart Chain endpoints) reject the
10
+ * array-wrapped body — even for a single request — which makes every call fail
11
+ * and get retried, BURNING through requests. Such chains must construct their
12
+ * client with `batch: false` (see {@link clientFromChain}'s `batch` option) so
13
+ * requests are sent as plain JSON-RPC objects the node accepts.
14
+ */
15
+ export declare const defaultRpcBatch: {
16
+ readonly wait: 10;
17
+ readonly batchSize: 32;
18
+ };
19
+ /** The default batch config for the client */
20
+ export declare const defaultBatchConfig: {
21
+ batch: {
22
+ readonly wait: 10;
23
+ readonly batchSize: 32;
24
+ };
25
+ };
26
+ /**
27
+ * Returns the chain key for the given chain id and urls
28
+ * @param chainId - the chain id
29
+ * @param urls - the urls
30
+ * @returns the chain key
31
+ */
32
+ export declare const chainKey: (chainId: number, urls: string[]) => string;
33
+ /** The client cache for the given chain id */
34
+ export declare const clientCache: Map<number, {
35
+ key: string;
36
+ client: PublicClient;
37
+ }>;
38
+ export declare const clientFromChain: ({ chain, urls, batch, }: {
39
+ chain: Chain;
40
+ urls: string[];
41
+ /**
42
+ * JSON-RPC request batching for this client's transport. Defaults to
43
+ * {@link defaultRpcBatch}. Pass `false` for chains whose RPC nodes reject the
44
+ * array-wrapped batch body (some Binance Smart Chain endpoints), so requests
45
+ * are sent as plain JSON-RPC objects and are not failed-and-retried.
46
+ */
47
+ batch?: HttpTransportConfig["batch"];
48
+ }) => PublicClient;
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientFromChain = exports.clientCache = exports.chainKey = exports.defaultBatchConfig = exports.defaultRpcBatch = exports.MAX_SAME_METHOD_CALLS_PER_SECOND = void 0;
4
+ const viem_1 = require("viem");
5
+ const rpcPacer_js_1 = require("./rpcPacer.js");
6
+ const url_js_1 = require("./url.js");
7
+ var rpcPacer_js_2 = require("./rpcPacer.js");
8
+ Object.defineProperty(exports, "MAX_SAME_METHOD_CALLS_PER_SECOND", { enumerable: true, get: function () { return rpcPacer_js_2.MAX_SAME_METHOD_CALLS_PER_SECOND; } });
9
+ /**
10
+ * JSON-RPC request batching config. When enabled, viem coalesces requests made
11
+ * within `wait` milliseconds (up to `batchSize`) into ONE HTTP POST carrying a
12
+ * JSON-RPC array body. This is the default because it sharply cuts request
13
+ * volume on nodes that support it.
14
+ *
15
+ * Note: some public nodes (notably some Binance Smart Chain endpoints) reject the
16
+ * array-wrapped body — even for a single request — which makes every call fail
17
+ * and get retried, BURNING through requests. Such chains must construct their
18
+ * client with `batch: false` (see {@link clientFromChain}'s `batch` option) so
19
+ * requests are sent as plain JSON-RPC objects the node accepts.
20
+ */
21
+ exports.defaultRpcBatch = {
22
+ wait: 10,
23
+ batchSize: 32,
24
+ };
25
+ /** The default batch config for the client */
26
+ exports.defaultBatchConfig = {
27
+ batch: exports.defaultRpcBatch,
28
+ };
29
+ /**
30
+ * Returns the chain key for the given chain id and urls
31
+ * @param chainId - the chain id
32
+ * @param urls - the urls
33
+ * @returns the chain key
34
+ */
35
+ const chainKey = (chainId, urls) => {
36
+ return `${chainId},${urls.join(',')}`.toLowerCase();
37
+ };
38
+ exports.chainKey = chainKey;
39
+ /** The client cache for the given chain id */
40
+ exports.clientCache = new Map();
41
+ /**
42
+ * Returns the client for the given chain and urls
43
+ * @param chain - the chain
44
+ * @param urls - the urls
45
+ * @returns the client
46
+ */
47
+ /**
48
+ * The one pacer for the whole application.
49
+ *
50
+ * MODULE LEVEL, DELIBERATELY. The endpoint keys its budget on the METHOD, not
51
+ * the chain — six `eth_blockNumber` on PulseChain plus six on Ethereum were
52
+ * answered exactly eight times, the same as twelve on one chain. A pacer per
53
+ * client would let two chains spend one budget twice and neither would know it
54
+ * had.
55
+ *
56
+ * It is built with the same ceiling the batch size uses, so the two can never
57
+ * describe different limits.
58
+ */
59
+ const pacer = (0, rpcPacer_js_1.createRpcPacer)({ ceiling: rpcPacer_js_1.MAX_SAME_METHOD_CALLS_PER_SECOND });
60
+ /**
61
+ * Holds a request until its methods fit under the ceiling.
62
+ *
63
+ * WIRED HERE RATHER THAN AROUND THE CALLERS because this is the only place that
64
+ * sees the FINAL body: viem coalesces separate reads into one post, so a limiter
65
+ * upstream of the transport would count intentions and this counts what is
66
+ * actually sent.
67
+ *
68
+ * Returning nothing leaves the request untouched — the hook exists to delay, not
69
+ * to rewrite.
70
+ */
71
+ const paceRequest = async (request) => {
72
+ // The HOST, not the full url: one proxy serves every chain from one budget,
73
+ // so `/evm/1` and `/evm/369` must count against the same tally.
74
+ const { host } = (0, url_js_1.splitUrl)(request.url);
75
+ await pacer.reserve(host, (0, rpcPacer_js_1.countMethods)(await request.clone().text().catch(() => null)));
76
+ };
77
+ /**
78
+ * Spreads requests across a chain's endpoints instead of resting on the first.
79
+ *
80
+ * WHAT `fallback` ACTUALLY DOES, and why it is not this. With `rank: false` it
81
+ * sends every request to entry zero and moves on only when that entry ERRORS. So
82
+ * the spares behind a chain carry no load at all: on Ethereum, `valve.city` took
83
+ * one hundred percent of every read while two perfectly good nodes sat idle, and
84
+ * the only way traffic ever reached them was a refusal — a wasted round trip
85
+ * spent discovering a spare we could have used on purpose.
86
+ *
87
+ * That matters because the first entry is a SHARED proxy. Its key is published
88
+ * on chainlist.org, so its per-second budget is not ours alone: measured at a
89
+ * refusal, our own calls in the preceding second were seven against a ceiling of
90
+ * eight. We were not over the limit. Somebody else was using the rest of it, and
91
+ * no amount of pacing on our side fixes that — only using less of that host
92
+ * does.
93
+ *
94
+ * ROUND ROBIN, AND FALLBACK STILL INTACT. Each request starts at the next
95
+ * endpoint in rotation and walks the rest on failure, so a dead host costs one
96
+ * attempt exactly as it did before while a healthy one now carries its share.
97
+ *
98
+ * NOT `rank: true`, which is viem's own answer to this and is the wrong one
99
+ * here: ranking pings EVERY url on EVERY chain every few seconds forever, which
100
+ * on an idle page was once the entire outbound traffic and is what spent the
101
+ * shared budget in the first place. It also reorders a list this project curates
102
+ * deliberately.
103
+ */
104
+ const balanced = (transports) => {
105
+ if (transports.length === 1)
106
+ return transports[0];
107
+ return (config) => {
108
+ const instances = transports.map((transport) => transport(config));
109
+ // Module-level rotation per client, not per call site: every reader on the
110
+ // page shares one cursor, which is what makes the split even rather than
111
+ // each caller starting at zero and piling onto the same host.
112
+ let cursor = 0;
113
+ return (0, viem_1.createTransport)({
114
+ key: 'balanced',
115
+ name: 'Balanced',
116
+ type: 'balanced',
117
+ // CAST AT THE BOUNDARY, deliberately. `EIP1193RequestFn` is generic over
118
+ // the method being called and resolves its own return type; a rotation
119
+ // cannot preserve that relationship because it does not know which
120
+ // transport will answer until it has tried one. The delegates below are
121
+ // fully typed and the shape passing through is unchanged — only the
122
+ // compiler's ability to follow it across the loop is lost.
123
+ request: (async (args) => {
124
+ const start = cursor;
125
+ cursor = (cursor + 1) % instances.length;
126
+ let lastError;
127
+ for (let offset = 0; offset < instances.length; offset += 1) {
128
+ try {
129
+ return await instances[(start + offset) % instances.length].request(args);
130
+ }
131
+ catch (error) {
132
+ // KEPT AND RETHROWN AT THE END, not swallowed. If every endpoint
133
+ // refuses, the caller must see a real error — a rotation that
134
+ // returns undefined when all its hosts are down turns an outage
135
+ // into a silently empty read.
136
+ lastError = error;
137
+ }
138
+ }
139
+ throw lastError;
140
+ }),
141
+ });
142
+ };
143
+ };
144
+ const clientFromChain = ({ chain, urls, batch = exports.defaultRpcBatch, }) => {
145
+ const key = (0, exports.chainKey)(chain.id, urls);
146
+ const existing = exports.clientCache.get(chain.id);
147
+ if (existing && existing.key === key) {
148
+ return existing.client;
149
+ }
150
+ const transport = !urls?.length
151
+ ? (0, viem_1.http)()
152
+ : balanced(urls.map((rpc) => rpc.startsWith('http')
153
+ ? (0, viem_1.http)(rpc, { batch, onFetchRequest: paceRequest })
154
+ : (0, viem_1.webSocket)(rpc, {
155
+ keepAlive: true,
156
+ reconnect: true,
157
+ retryDelay: 250,
158
+ retryCount: 10,
159
+ timeout: 4_000,
160
+ })));
161
+ const client = (0, viem_1.createPublicClient)({
162
+ chain,
163
+ transport,
164
+ });
165
+ exports.clientCache.set(chain.id, {
166
+ key,
167
+ client,
168
+ });
169
+ return client;
170
+ };
171
+ exports.clientFromChain = clientFromChain;
@@ -0,0 +1,18 @@
1
+ import { type Chain, type Hex, type PublicClient } from 'viem';
2
+ import type { Erc20Metadata } from './types.js';
3
+ /** The erc20 metadata calls */
4
+ export declare const erc20MetadataCalls: {
5
+ functionName: string;
6
+ }[];
7
+ /**
8
+ * The multicall for the erc20 metadata.
9
+ *
10
+ * The annotation spells out the plain call signature, which keeps the
11
+ * memoization an implementation detail: no caller touches the `.cache`
12
+ * property it would otherwise publish.
13
+ */
14
+ export declare const multicallErc20: (inputs: {
15
+ client: PublicClient;
16
+ target: Hex;
17
+ chain: Chain;
18
+ }) => Promise<Erc20Metadata>;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.multicallErc20 = exports.erc20MetadataCalls = void 0;
4
+ const viem_1 = require("viem");
5
+ const cache_js_1 = require("./cache.js");
6
+ const multicall_js_1 = require("./multicall.js");
7
+ /** The erc20 metadata calls */
8
+ exports.erc20MetadataCalls = [
9
+ { functionName: 'name' },
10
+ { functionName: 'symbol' },
11
+ { functionName: 'decimals' },
12
+ ];
13
+ /**
14
+ * The multicall for the erc20 metadata.
15
+ *
16
+ * The annotation spells out the plain call signature, which keeps the
17
+ * memoization an implementation detail: no caller touches the `.cache`
18
+ * property it would otherwise publish.
19
+ */
20
+ exports.multicallErc20 = (0, cache_js_1.memoizeByKey)(async ({ client, target, chain }) => {
21
+ const options = {
22
+ chain: chain,
23
+ client: client,
24
+ abi: viem_1.erc20Abi,
25
+ target,
26
+ calls: exports.erc20MetadataCalls,
27
+ };
28
+ try {
29
+ return await (0, multicall_js_1.multicallRead)(options);
30
+ }
31
+ catch {
32
+ return await (0, multicall_js_1.multicallRead)({
33
+ ...options,
34
+ abi: viem_1.erc20Abi_bytes32,
35
+ });
36
+ }
37
+ }, ({ target, chain }) => {
38
+ return !target ? chain.id : (0, viem_1.getAddress)(target, chain.id);
39
+ });
@@ -0,0 +1,8 @@
1
+ export * from './assert.js';
2
+ export * from './cache.js';
3
+ export * from './client.js';
4
+ export * from './erc20.js';
5
+ export * from './multicall.js';
6
+ export * from './serialize.js';
7
+ export * from './types.js';
8
+ export * from './url.js';
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./assert.js"), exports);
18
+ __exportStar(require("./cache.js"), exports);
19
+ __exportStar(require("./client.js"), exports);
20
+ __exportStar(require("./erc20.js"), exports);
21
+ __exportStar(require("./multicall.js"), exports);
22
+ __exportStar(require("./serialize.js"), exports);
23
+ __exportStar(require("./types.js"), exports);
24
+ __exportStar(require("./url.js"), exports);