@alchemy/common 0.0.0-alpha.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/esm/actions/addBreadCrumb.d.ts +14 -0
- package/dist/esm/actions/addBreadCrumb.js +27 -0
- package/dist/esm/actions/addBreadCrumb.js.map +1 -0
- package/dist/esm/chains.d.ts +234 -0
- package/dist/esm/chains.js +113 -0
- package/dist/esm/chains.js.map +1 -0
- package/dist/esm/errors/AccountNotFoundError.d.ts +10 -0
- package/dist/esm/errors/AccountNotFoundError.js +19 -0
- package/dist/esm/errors/AccountNotFoundError.js.map +1 -0
- package/dist/esm/errors/BaseError.d.ts +23 -0
- package/dist/esm/errors/BaseError.js +40 -0
- package/dist/esm/errors/BaseError.js.map +1 -0
- package/dist/esm/errors/ChainNotFoundError.d.ts +11 -0
- package/dist/esm/errors/ChainNotFoundError.js +19 -0
- package/dist/esm/errors/ChainNotFoundError.js.map +1 -0
- package/dist/esm/errors/ConnectionConfigError.d.ts +13 -0
- package/dist/esm/errors/ConnectionConfigError.js +25 -0
- package/dist/esm/errors/ConnectionConfigError.js.map +1 -0
- package/dist/esm/errors/FetchError.d.ts +15 -0
- package/dist/esm/errors/FetchError.js +25 -0
- package/dist/esm/errors/FetchError.js.map +1 -0
- package/dist/esm/errors/InvalidRequestError.d.ts +13 -0
- package/dist/esm/errors/InvalidRequestError.js +22 -0
- package/dist/esm/errors/InvalidRequestError.js.map +1 -0
- package/dist/esm/errors/MethodUnsupportedError.d.ts +13 -0
- package/dist/esm/errors/MethodUnsupportedError.js +21 -0
- package/dist/esm/errors/MethodUnsupportedError.js.map +1 -0
- package/dist/esm/errors/ServerError.d.ts +15 -0
- package/dist/esm/errors/ServerError.js +25 -0
- package/dist/esm/errors/ServerError.js.map +1 -0
- package/dist/esm/index.d.ts +29 -0
- package/dist/esm/index.js +27 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logging/config.d.ts +190 -0
- package/dist/esm/logging/config.js +279 -0
- package/dist/esm/logging/config.js.map +1 -0
- package/dist/esm/logging/index.d.ts +6 -0
- package/dist/esm/logging/index.js +5 -0
- package/dist/esm/logging/index.js.map +1 -0
- package/dist/esm/logging/local.d.ts +10 -0
- package/dist/esm/logging/local.js +35 -0
- package/dist/esm/logging/local.js.map +1 -0
- package/dist/esm/logging/logger.d.ts +80 -0
- package/dist/esm/logging/logger.js +111 -0
- package/dist/esm/logging/logger.js.map +1 -0
- package/dist/esm/logging/noop.d.ts +6 -0
- package/dist/esm/logging/noop.js +12 -0
- package/dist/esm/logging/noop.js.map +1 -0
- package/dist/esm/logging/sinks.d.ts +90 -0
- package/dist/esm/logging/sinks.js +111 -0
- package/dist/esm/logging/sinks.js.map +1 -0
- package/dist/esm/logging/types.d.ts +96 -0
- package/dist/esm/logging/types.js +2 -0
- package/dist/esm/logging/types.js.map +1 -0
- package/dist/esm/logging/utils.d.ts +7 -0
- package/dist/esm/logging/utils.js +21 -0
- package/dist/esm/logging/utils.js.map +1 -0
- package/dist/esm/rest/restClient.d.ts +34 -0
- package/dist/esm/rest/restClient.js +55 -0
- package/dist/esm/rest/restClient.js.map +1 -0
- package/dist/esm/rest/types.d.ts +24 -0
- package/dist/esm/rest/types.js +2 -0
- package/dist/esm/rest/types.js.map +1 -0
- package/dist/esm/tracing/traceHeader.d.ts +82 -0
- package/dist/esm/tracing/traceHeader.js +145 -0
- package/dist/esm/tracing/traceHeader.js.map +1 -0
- package/dist/esm/tracing/updateHeaders.d.ts +24 -0
- package/dist/esm/tracing/updateHeaders.js +61 -0
- package/dist/esm/tracing/updateHeaders.js.map +1 -0
- package/dist/esm/transport/alchemy.d.ts +110 -0
- package/dist/esm/transport/alchemy.js +164 -0
- package/dist/esm/transport/alchemy.js.map +1 -0
- package/dist/esm/transport/chainRegistry.d.ts +31 -0
- package/dist/esm/transport/chainRegistry.js +95 -0
- package/dist/esm/transport/chainRegistry.js.map +1 -0
- package/dist/esm/transport/connection.d.ts +20 -0
- package/dist/esm/transport/connection.js +2 -0
- package/dist/esm/transport/connection.js.map +1 -0
- package/dist/esm/transport/connectionSchema.d.ts +124 -0
- package/dist/esm/transport/connectionSchema.js +121 -0
- package/dist/esm/transport/connectionSchema.js.map +1 -0
- package/dist/esm/utils/assertNever.d.ts +8 -0
- package/dist/esm/utils/assertNever.js +12 -0
- package/dist/esm/utils/assertNever.js.map +1 -0
- package/dist/esm/utils/bigint.d.ts +24 -0
- package/dist/esm/utils/bigint.js +37 -0
- package/dist/esm/utils/bigint.js.map +1 -0
- package/dist/esm/utils/createEip1193HandlerFactory.d.ts +18 -0
- package/dist/esm/utils/createEip1193HandlerFactory.js +11 -0
- package/dist/esm/utils/createEip1193HandlerFactory.js.map +1 -0
- package/dist/esm/utils/headers.d.ts +7 -0
- package/dist/esm/utils/headers.js +29 -0
- package/dist/esm/utils/headers.js.map +1 -0
- package/dist/esm/utils/lowerAddress.d.ts +8 -0
- package/dist/esm/utils/lowerAddress.js +9 -0
- package/dist/esm/utils/lowerAddress.js.map +1 -0
- package/dist/esm/utils/raise.d.ts +8 -0
- package/dist/esm/utils/raise.js +14 -0
- package/dist/esm/utils/raise.js.map +1 -0
- package/dist/esm/utils/types.d.ts +10 -0
- package/dist/esm/utils/types.js +2 -0
- package/dist/esm/utils/types.js.map +1 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +4 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/types/actions/addBreadCrumb.d.ts +15 -0
- package/dist/types/actions/addBreadCrumb.d.ts.map +1 -0
- package/dist/types/chains.d.ts +235 -0
- package/dist/types/chains.d.ts.map +1 -0
- package/dist/types/errors/AccountNotFoundError.d.ts +11 -0
- package/dist/types/errors/AccountNotFoundError.d.ts.map +1 -0
- package/dist/types/errors/BaseError.d.ts +24 -0
- package/dist/types/errors/BaseError.d.ts.map +1 -0
- package/dist/types/errors/ChainNotFoundError.d.ts +12 -0
- package/dist/types/errors/ChainNotFoundError.d.ts.map +1 -0
- package/dist/types/errors/ConnectionConfigError.d.ts +14 -0
- package/dist/types/errors/ConnectionConfigError.d.ts.map +1 -0
- package/dist/types/errors/FetchError.d.ts +16 -0
- package/dist/types/errors/FetchError.d.ts.map +1 -0
- package/dist/types/errors/InvalidRequestError.d.ts +14 -0
- package/dist/types/errors/InvalidRequestError.d.ts.map +1 -0
- package/dist/types/errors/MethodUnsupportedError.d.ts +14 -0
- package/dist/types/errors/MethodUnsupportedError.d.ts.map +1 -0
- package/dist/types/errors/ServerError.d.ts +16 -0
- package/dist/types/errors/ServerError.d.ts.map +1 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/logging/config.d.ts +191 -0
- package/dist/types/logging/config.d.ts.map +1 -0
- package/dist/types/logging/index.d.ts +7 -0
- package/dist/types/logging/index.d.ts.map +1 -0
- package/dist/types/logging/local.d.ts +11 -0
- package/dist/types/logging/local.d.ts.map +1 -0
- package/dist/types/logging/logger.d.ts +81 -0
- package/dist/types/logging/logger.d.ts.map +1 -0
- package/dist/types/logging/noop.d.ts +7 -0
- package/dist/types/logging/noop.d.ts.map +1 -0
- package/dist/types/logging/sinks.d.ts +91 -0
- package/dist/types/logging/sinks.d.ts.map +1 -0
- package/dist/types/logging/types.d.ts +97 -0
- package/dist/types/logging/types.d.ts.map +1 -0
- package/dist/types/logging/utils.d.ts +8 -0
- package/dist/types/logging/utils.d.ts.map +1 -0
- package/dist/types/rest/restClient.d.ts +35 -0
- package/dist/types/rest/restClient.d.ts.map +1 -0
- package/dist/types/rest/types.d.ts +25 -0
- package/dist/types/rest/types.d.ts.map +1 -0
- package/dist/types/tracing/traceHeader.d.ts +83 -0
- package/dist/types/tracing/traceHeader.d.ts.map +1 -0
- package/dist/types/tracing/updateHeaders.d.ts +25 -0
- package/dist/types/tracing/updateHeaders.d.ts.map +1 -0
- package/dist/types/transport/alchemy.d.ts +111 -0
- package/dist/types/transport/alchemy.d.ts.map +1 -0
- package/dist/types/transport/chainRegistry.d.ts +32 -0
- package/dist/types/transport/chainRegistry.d.ts.map +1 -0
- package/dist/types/transport/connection.d.ts +21 -0
- package/dist/types/transport/connection.d.ts.map +1 -0
- package/dist/types/transport/connectionSchema.d.ts +125 -0
- package/dist/types/transport/connectionSchema.d.ts.map +1 -0
- package/dist/types/utils/assertNever.d.ts +9 -0
- package/dist/types/utils/assertNever.d.ts.map +1 -0
- package/dist/types/utils/bigint.d.ts +25 -0
- package/dist/types/utils/bigint.d.ts.map +1 -0
- package/dist/types/utils/createEip1193HandlerFactory.d.ts +19 -0
- package/dist/types/utils/createEip1193HandlerFactory.d.ts.map +1 -0
- package/dist/types/utils/headers.d.ts +8 -0
- package/dist/types/utils/headers.d.ts.map +1 -0
- package/dist/types/utils/lowerAddress.d.ts +9 -0
- package/dist/types/utils/lowerAddress.d.ts.map +1 -0
- package/dist/types/utils/raise.d.ts +9 -0
- package/dist/types/utils/raise.d.ts.map +1 -0
- package/dist/types/utils/types.d.ts +11 -0
- package/dist/types/utils/types.d.ts.map +1 -0
- package/dist/types/version.d.ts +2 -0
- package/dist/types/version.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/actions/addBreadCrumb.ts +38 -0
- package/src/chains.ts +118 -0
- package/src/errors/AccountNotFoundError.ts +16 -0
- package/src/errors/BaseError.ts +51 -0
- package/src/errors/ChainNotFoundError.ts +15 -0
- package/src/errors/ConnectionConfigError.ts +22 -0
- package/src/errors/FetchError.ts +21 -0
- package/src/errors/InvalidRequestError.ts +19 -0
- package/src/errors/MethodUnsupportedError.ts +17 -0
- package/src/errors/ServerError.ts +21 -0
- package/src/index.ts +60 -0
- package/src/logging/config.ts +365 -0
- package/src/logging/index.ts +20 -0
- package/src/logging/local.ts +39 -0
- package/src/logging/logger.ts +194 -0
- package/src/logging/noop.ts +13 -0
- package/src/logging/sinks.ts +115 -0
- package/src/logging/types.ts +111 -0
- package/src/logging/utils.ts +31 -0
- package/src/rest/restClient.ts +64 -0
- package/src/rest/types.ts +42 -0
- package/src/tracing/traceHeader.ts +154 -0
- package/src/tracing/updateHeaders.ts +66 -0
- package/src/transport/alchemy.ts +242 -0
- package/src/transport/chainRegistry.ts +115 -0
- package/src/transport/connection.ts +19 -0
- package/src/transport/connectionSchema.ts +145 -0
- package/src/utils/assertNever.ts +12 -0
- package/src/utils/bigint.ts +58 -0
- package/src/utils/createEip1193HandlerFactory.ts +25 -0
- package/src/utils/headers.ts +48 -0
- package/src/utils/lowerAddress.ts +10 -0
- package/src/utils/raise.ts +14 -0
- package/src/utils/types.ts +14 -0
- package/src/version.ts +3 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createTransport,
|
|
3
|
+
http,
|
|
4
|
+
type Chain,
|
|
5
|
+
type EIP1193RequestFn,
|
|
6
|
+
type HttpTransportConfig,
|
|
7
|
+
type RpcSchema,
|
|
8
|
+
type Transport,
|
|
9
|
+
} from "viem";
|
|
10
|
+
import { BaseError } from "../errors/BaseError.js";
|
|
11
|
+
import { mutateRemoveTrackingHeaders } from "../tracing/updateHeaders.js";
|
|
12
|
+
import { ChainNotFoundError } from "../errors/ChainNotFoundError.js";
|
|
13
|
+
import { getAlchemyRpcUrl } from "./chainRegistry.js";
|
|
14
|
+
import {
|
|
15
|
+
convertHeadersToObject,
|
|
16
|
+
withAlchemyHeaders,
|
|
17
|
+
} from "../utils/headers.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration options for the Alchemy transport.
|
|
21
|
+
* Extends viem's HttpTransportConfig with Alchemy-specific options while omitting
|
|
22
|
+
* options that are not relevant or supported by Alchemy.
|
|
23
|
+
*/
|
|
24
|
+
export interface AlchemyTransportConfig
|
|
25
|
+
extends Omit<
|
|
26
|
+
HttpTransportConfig,
|
|
27
|
+
"batch" | "key" | "methods" | "name" | "raw"
|
|
28
|
+
> {
|
|
29
|
+
/** API key for Alchemy authentication */
|
|
30
|
+
apiKey?: string;
|
|
31
|
+
/** JWT token for authentication */
|
|
32
|
+
jwt?: string;
|
|
33
|
+
/** Custom RPC URL (optional - defaults to chain's Alchemy URL, but can be used to override the chain's Alchemy URL) */
|
|
34
|
+
url?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type AlchemyTransportBase<rpcSchema extends RpcSchema | undefined = undefined> =
|
|
38
|
+
Transport<
|
|
39
|
+
"alchemyHttp",
|
|
40
|
+
{
|
|
41
|
+
alchemyRpcUrl: string;
|
|
42
|
+
fetchOptions: AlchemyTransportConfig["fetchOptions"];
|
|
43
|
+
config: AlchemyTransportConfig;
|
|
44
|
+
},
|
|
45
|
+
EIP1193RequestFn<rpcSchema>
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
export type AlchemyTransport<
|
|
49
|
+
rpcSchema extends RpcSchema | undefined = undefined,
|
|
50
|
+
> = AlchemyTransportBase<rpcSchema> & {
|
|
51
|
+
updateHeaders(newHeaders: HeadersInit): void;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A type guard for the transport to determine if it is an Alchemy transport.
|
|
56
|
+
* Used in cases where we would like to do switching depending on the transport.
|
|
57
|
+
*
|
|
58
|
+
* @param {Transport} transport The transport to check
|
|
59
|
+
* @param {Chain} chain Chain for the transport to run its function to return the transport config
|
|
60
|
+
* @returns {boolean} `true` if the transport is an Alchemy transport, otherwise `false`
|
|
61
|
+
*/
|
|
62
|
+
export function isAlchemyTransport(
|
|
63
|
+
transport: Transport,
|
|
64
|
+
chain: Chain,
|
|
65
|
+
): transport is AlchemyTransport {
|
|
66
|
+
return transport({ chain }).config.type === "alchemyHttp";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Creates an Alchemy HTTP transport for connecting to Alchemy's services.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* Using API Key:
|
|
74
|
+
* ```ts
|
|
75
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
76
|
+
*
|
|
77
|
+
* const transport = alchemyTransport({ apiKey: "your-api-key" });
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* Using JWT:
|
|
82
|
+
* ```ts
|
|
83
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
84
|
+
*
|
|
85
|
+
* const transport = alchemyTransport({ jwt: "your-jwt-token" });
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* Using URL directly:
|
|
90
|
+
* ```ts
|
|
91
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
92
|
+
*
|
|
93
|
+
* const transport = alchemyTransport({ url: "https://eth-mainnet.g.alchemy.com/v2/your-key" });
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* Using custom URL with API key:
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
100
|
+
*
|
|
101
|
+
* const transport = alchemyTransport({
|
|
102
|
+
* url: "https://custom-alchemy.com/v2",
|
|
103
|
+
* apiKey: "your-api-key"
|
|
104
|
+
* });
|
|
105
|
+
* ```
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* Using custom URL with JWT:
|
|
109
|
+
* ```ts
|
|
110
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
111
|
+
*
|
|
112
|
+
* const transport = alchemyTransport({
|
|
113
|
+
* url: "https://custom-alchemy.com/v2",
|
|
114
|
+
* jwt: "your-jwt-token"
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* Using HTTP debugging options:
|
|
120
|
+
* ```ts
|
|
121
|
+
* import { alchemyTransport } from "@alchemy/common";
|
|
122
|
+
*
|
|
123
|
+
* const transport = alchemyTransport({
|
|
124
|
+
* apiKey: "your-api-key",
|
|
125
|
+
* onFetchRequest: (request) => console.log("Request:", request),
|
|
126
|
+
* onFetchResponse: (response) => console.log("Response:", response),
|
|
127
|
+
* timeout: 30000,
|
|
128
|
+
* retryCount: 3,
|
|
129
|
+
* retryDelay: 1000
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @param {AlchemyTransportConfig} config - The configuration object for the Alchemy transport (extends viem's HttpTransportConfig)
|
|
134
|
+
* @param {string} [config.apiKey] - API key for Alchemy authentication
|
|
135
|
+
* @param {string} [config.jwt] - JWT token for authentication
|
|
136
|
+
* @param {string} [config.url] - Direct URL to Alchemy endpoint or a proxy URL
|
|
137
|
+
* @param {Function} [config.onFetchRequest] - Callback for debugging outgoing requests
|
|
138
|
+
* @param {Function} [config.onFetchResponse] - Callback for debugging responses
|
|
139
|
+
* @param {number} [config.timeout] - Request timeout in milliseconds
|
|
140
|
+
* @param {number} [config.retryCount] - The number of retry attempts
|
|
141
|
+
* @param {number} [config.retryDelay] - The delay between retries, in milliseconds
|
|
142
|
+
* @param {object} [config.fetchOptions] - Optional fetch options for HTTP requests
|
|
143
|
+
* @param {object} [config.httpOptions] - HTTP transport options for debugging (onFetchRequest, onFetchResponse, timeout, batch)
|
|
144
|
+
* @returns {AlchemyTransport} The configured Alchemy transport function
|
|
145
|
+
*/
|
|
146
|
+
export function alchemyTransport<
|
|
147
|
+
rpcSchema extends RpcSchema | undefined = undefined,
|
|
148
|
+
>(config: AlchemyTransportConfig): AlchemyTransport<rpcSchema> {
|
|
149
|
+
const {
|
|
150
|
+
apiKey,
|
|
151
|
+
jwt,
|
|
152
|
+
url,
|
|
153
|
+
fetchOptions: fetchOptions_,
|
|
154
|
+
retryCount,
|
|
155
|
+
retryDelay,
|
|
156
|
+
...httpTransportConfig
|
|
157
|
+
} = config;
|
|
158
|
+
|
|
159
|
+
// Create a copy of fetch options for modification
|
|
160
|
+
const fetchOptions = { ...fetchOptions_ };
|
|
161
|
+
|
|
162
|
+
fetchOptions.headers = withAlchemyHeaders({
|
|
163
|
+
headers: fetchOptions.headers,
|
|
164
|
+
apiKey,
|
|
165
|
+
jwt,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const transport: AlchemyTransportBase = (opts) => {
|
|
169
|
+
const { chain } = opts;
|
|
170
|
+
|
|
171
|
+
mutateRemoveTrackingHeaders(config?.fetchOptions?.headers);
|
|
172
|
+
|
|
173
|
+
const rpcUrl = (() => {
|
|
174
|
+
if (url) {
|
|
175
|
+
return url;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!chain) {
|
|
179
|
+
throw new ChainNotFoundError();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const alchemyUrl = getAlchemyRpcUrl(chain.id);
|
|
183
|
+
if (alchemyUrl) {
|
|
184
|
+
return alchemyUrl;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Fallback: check for legacy alchemy RPC URLs in chain definition
|
|
188
|
+
if (chain.rpcUrls?.alchemy?.http?.[0]) {
|
|
189
|
+
return chain.rpcUrls.alchemy.http[0];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
throw new BaseError(
|
|
193
|
+
`Chain ${chain.id} (${chain.name}) is not supported by Alchemy. To use this chain:\n\n` +
|
|
194
|
+
`1. Use a direct RPC URL:\n` +
|
|
195
|
+
` alchemyTransport({ url: "https://your-alchemy-endpoint.com/v2/your-key" })\n\n` +
|
|
196
|
+
`2. Add alchemy RPC to your chain definition:\n` +
|
|
197
|
+
` defineChain({ rpcUrls: { alchemy: { http: ["https://your-alchemy-url/v2"] }}})\n\n` +
|
|
198
|
+
`3. Or use a standard RPC provider:\n` +
|
|
199
|
+
` import { http } from "viem";\n` +
|
|
200
|
+
` http("https://your-standard-rpc.com")`,
|
|
201
|
+
);
|
|
202
|
+
})();
|
|
203
|
+
|
|
204
|
+
const innerTransport = http(rpcUrl, {
|
|
205
|
+
// Standard viem options are passed through to the underlying transport, with
|
|
206
|
+
// the exception of retryCount and retryDelay because those are handled by
|
|
207
|
+
// the outer Alchemy transport.
|
|
208
|
+
...httpTransportConfig,
|
|
209
|
+
fetchOptions,
|
|
210
|
+
// Retry count must be 0 here in order to respect the retry
|
|
211
|
+
// count that is already specified on the underlying transport.
|
|
212
|
+
retryCount: 0,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return createTransport(
|
|
216
|
+
{
|
|
217
|
+
key: "alchemyHttp",
|
|
218
|
+
name: "Alchemy HTTP Transport",
|
|
219
|
+
request: innerTransport(opts).request,
|
|
220
|
+
retryCount: retryCount ?? opts?.retryCount,
|
|
221
|
+
retryDelay,
|
|
222
|
+
type: "alchemyHttp",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
alchemyRpcUrl: rpcUrl,
|
|
226
|
+
fetchOptions,
|
|
227
|
+
config,
|
|
228
|
+
},
|
|
229
|
+
);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return Object.assign(transport, {
|
|
233
|
+
updateHeaders(newHeaders_: HeadersInit) {
|
|
234
|
+
const newHeaders = convertHeadersToObject(newHeaders_);
|
|
235
|
+
|
|
236
|
+
fetchOptions.headers = {
|
|
237
|
+
...fetchOptions.headers,
|
|
238
|
+
...newHeaders,
|
|
239
|
+
};
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal registry mapping chain IDs to Alchemy RPC base URLs.
|
|
3
|
+
* This replaces the need for custom chain exports with embedded Alchemy URLs.
|
|
4
|
+
*/
|
|
5
|
+
export const ALCHEMY_RPC_MAPPING: Record<number, string> = {
|
|
6
|
+
// Ethereum networks
|
|
7
|
+
1: "https://eth-mainnet.g.alchemy.com/v2", // mainnet
|
|
8
|
+
11155111: "https://eth-sepolia.g.alchemy.com/v2", // sepolia
|
|
9
|
+
5: "https://eth-goerli.g.alchemy.com/v2", // goerli
|
|
10
|
+
|
|
11
|
+
// Arbitrum networks
|
|
12
|
+
42161: "https://arb-mainnet.g.alchemy.com/v2", // arbitrum
|
|
13
|
+
421613: "https://arb-goerli.g.alchemy.com/v2", // arbitrumGoerli
|
|
14
|
+
421614: "https://arb-sepolia.g.alchemy.com/v2", // arbitrumSepolia
|
|
15
|
+
|
|
16
|
+
// Optimism networks
|
|
17
|
+
10: "https://opt-mainnet.g.alchemy.com/v2", // optimism
|
|
18
|
+
420: "https://opt-goerli.g.alchemy.com/v2", // optimismGoerli
|
|
19
|
+
11155420: "https://opt-sepolia.g.alchemy.com/v2", // optimismSepolia
|
|
20
|
+
|
|
21
|
+
// Base networks
|
|
22
|
+
8453: "https://base-mainnet.g.alchemy.com/v2", // base
|
|
23
|
+
84531: "https://base-goerli.g.alchemy.com/v2", // baseGoerli
|
|
24
|
+
84532: "https://base-sepolia.g.alchemy.com/v2", // baseSepolia
|
|
25
|
+
|
|
26
|
+
// Polygon networks
|
|
27
|
+
137: "https://polygon-mainnet.g.alchemy.com/v2", // polygon
|
|
28
|
+
80001: "https://polygon-mumbai.g.alchemy.com/v2", // polygonMumbai
|
|
29
|
+
80002: "https://polygon-amoy.g.alchemy.com/v2", // polygonAmoy
|
|
30
|
+
|
|
31
|
+
// World Chain networks
|
|
32
|
+
480: "https://worldchain-mainnet.g.alchemy.com/v2", // worldChain
|
|
33
|
+
4801: "https://worldchain-sepolia.g.alchemy.com/v2", // worldChainSepolia
|
|
34
|
+
|
|
35
|
+
// Shape networks
|
|
36
|
+
360: "https://shape-mainnet.g.alchemy.com/v2", // shape
|
|
37
|
+
11011: "https://shape-sepolia.g.alchemy.com/v2", // shapeSepolia
|
|
38
|
+
|
|
39
|
+
// Unichain networks
|
|
40
|
+
130: "https://unichain-mainnet.g.alchemy.com/v2", // unichainMainnet
|
|
41
|
+
1301: "https://unichain-sepolia.g.alchemy.com/v2", // unichainSepolia
|
|
42
|
+
|
|
43
|
+
// Soneium networks
|
|
44
|
+
1868: "https://soneium-mainnet.g.alchemy.com/v2", // soneiumMainnet
|
|
45
|
+
1946: "https://soneium-minato.g.alchemy.com/v2", // soneiumMinato
|
|
46
|
+
|
|
47
|
+
// OPBNB networks
|
|
48
|
+
204: "https://opbnb-mainnet.g.alchemy.com/v2", // opbnbMainnet
|
|
49
|
+
5611: "https://opbnb-testnet.g.alchemy.com/v2", // opbnbTestnet
|
|
50
|
+
|
|
51
|
+
// BeraChain networks
|
|
52
|
+
80084: "https://berachain-bartio.g.alchemy.com/v2", // beraChainBartio
|
|
53
|
+
|
|
54
|
+
// Ink networks
|
|
55
|
+
57073: "https://ink-mainnet.g.alchemy.com/v2", // inkMainnet
|
|
56
|
+
763373: "https://ink-sepolia.g.alchemy.com/v2", // inkSepolia
|
|
57
|
+
|
|
58
|
+
// Monad networks
|
|
59
|
+
10143: "https://monad-testnet.g.alchemy.com/v2", // monadTestnet
|
|
60
|
+
|
|
61
|
+
// Openloot networks
|
|
62
|
+
905905: "https://openloot-sepolia.g.alchemy.com/v2", // openlootSepolia
|
|
63
|
+
|
|
64
|
+
// Gensyn networks
|
|
65
|
+
685685: "https://gensyn-testnet.g.alchemy.com/v2", // gensynTestnet
|
|
66
|
+
|
|
67
|
+
// Rise networks
|
|
68
|
+
11155931: "https://rise-testnet.g.alchemy.com/v2", // riseTestnet
|
|
69
|
+
|
|
70
|
+
// Story networks
|
|
71
|
+
1514: "https://story-mainnet.g.alchemy.com/v2", // storyMainnet
|
|
72
|
+
1315: "https://story-aeneid.g.alchemy.com/v2", // storyAeneid
|
|
73
|
+
|
|
74
|
+
// Celo networks
|
|
75
|
+
42220: "https://celo-mainnet.g.alchemy.com/v2", // celoMainnet
|
|
76
|
+
44787: "https://celo-alfajores.g.alchemy.com/v2", // celoAlfajores
|
|
77
|
+
|
|
78
|
+
// Tea networks
|
|
79
|
+
10218: "https://tea-sepolia.g.alchemy.com/v2", // teaSepolia
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Gets the Alchemy RPC base URL for a given chain ID.
|
|
84
|
+
*
|
|
85
|
+
* @param {number} chainId The chain ID to lookup
|
|
86
|
+
* @returns {string | undefined} The Alchemy RPC base URL or undefined if not supported
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const rpcUrl = getAlchemyRpcUrl(1); // "https://eth-mainnet.g.alchemy.com/v2"
|
|
91
|
+
* const customUrl = getAlchemyRpcUrl(999); // undefined
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function getAlchemyRpcUrl(chainId: number): string | undefined {
|
|
95
|
+
return ALCHEMY_RPC_MAPPING[chainId];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Checks if a chain ID is supported by the Alchemy RPC registry.
|
|
100
|
+
*
|
|
101
|
+
* @param {number} chainId The chain ID to check
|
|
102
|
+
* @returns {boolean} True if the chain is supported, false otherwise
|
|
103
|
+
*/
|
|
104
|
+
export function isChainSupported(chainId: number): boolean {
|
|
105
|
+
return chainId in ALCHEMY_RPC_MAPPING;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets all supported chain IDs from the registry.
|
|
110
|
+
*
|
|
111
|
+
* @returns {number[]} Array of supported chain IDs
|
|
112
|
+
*/
|
|
113
|
+
export function getSupportedChainIds(): number[] {
|
|
114
|
+
return Object.keys(ALCHEMY_RPC_MAPPING).map(Number);
|
|
115
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Never } from "../utils/types";
|
|
2
|
+
|
|
3
|
+
// TODO(v5): remove this file and use connectionSchema.ts instead once other packages are migrated over
|
|
4
|
+
type AlchemyConnectionBaseConfig =
|
|
5
|
+
// TODO(v5): is this really the best devex? can we do better?
|
|
6
|
+
// basic configuration for connecting to alchemy.
|
|
7
|
+
// proxyUrl is used when making calls to the developer backend.
|
|
8
|
+
| { proxyUrl: string; apiKey?: never; jwt?: never }
|
|
9
|
+
| { proxyUrl?: never; apiKey: string; jwt?: never }
|
|
10
|
+
| { proxyUrl?: never; apiKey?: never; jwt: string };
|
|
11
|
+
|
|
12
|
+
type AAOnlyChainConfig = {
|
|
13
|
+
alchemyConnection: AlchemyConnectionBaseConfig;
|
|
14
|
+
nodeRpcUrl: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type AlchemyConnectionConfig =
|
|
18
|
+
| (AlchemyConnectionBaseConfig & Never<AAOnlyChainConfig>)
|
|
19
|
+
| (AAOnlyChainConfig & Never<AlchemyConnectionBaseConfig>);
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ConnectionConfigError } from "../errors/ConnectionConfigError.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Alchemy Connection Configuration Schema
|
|
6
|
+
*
|
|
7
|
+
* Provides three authentication options for connecting to Alchemy services:
|
|
8
|
+
*
|
|
9
|
+
* 1. **API Key**: Authenticate using your Alchemy API key
|
|
10
|
+
* 2. **JWT**: Authenticate using a JWT token
|
|
11
|
+
* 3. **URL**: Connect directly using a full RPC URL
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* Using API Key (uses chain's Alchemy URL):
|
|
15
|
+
* ```ts
|
|
16
|
+
* { apiKey: 'abc123' }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* Using JWT (uses chain's Alchemy URL):
|
|
21
|
+
* ```ts
|
|
22
|
+
* { jwt: 'eyJhbGc...' }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* Using direct URL only:
|
|
27
|
+
* ```ts
|
|
28
|
+
* { url: 'https://eth-mainnet.g.alchemy.com/v2/your-key' }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* Using custom URL with API key:
|
|
33
|
+
* ```ts
|
|
34
|
+
* { url: 'https://custom-alchemy.com/v2', apiKey: 'abc123' }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* Using custom URL with JWT:
|
|
39
|
+
* ```ts
|
|
40
|
+
* { url: 'https://custom-alchemy.com/v2', jwt: 'eyJhbGc...' }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Main connection configuration allowing flexible combinations.
|
|
46
|
+
* Can specify URL, auth method, or both together.
|
|
47
|
+
*/
|
|
48
|
+
export const AlchemyConnectionConfigSchema = z
|
|
49
|
+
.object({
|
|
50
|
+
/** API key for Alchemy authentication */
|
|
51
|
+
apiKey: z.string().min(1, "API key cannot be empty").optional(),
|
|
52
|
+
/** JWT token for authentication */
|
|
53
|
+
jwt: z.string().min(1, "JWT cannot be empty").optional(),
|
|
54
|
+
/** Custom RPC URL (optional - defaults to chain's Alchemy URL) */
|
|
55
|
+
url: z.string().url("Invalid URL format").optional(),
|
|
56
|
+
})
|
|
57
|
+
.strict()
|
|
58
|
+
.refine(
|
|
59
|
+
(data) => {
|
|
60
|
+
// Must have at least one field
|
|
61
|
+
return data.apiKey || data.jwt || data.url;
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
message: "Must specify at least one of: apiKey, jwt, or url",
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
.refine(
|
|
68
|
+
(data) => {
|
|
69
|
+
// Cannot have both apiKey and jwt
|
|
70
|
+
return !(data.apiKey && data.jwt);
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
message:
|
|
74
|
+
"Cannot specify both apiKey and jwt - choose only one authentication method",
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* TypeScript type derived from the schema for external consumption.
|
|
80
|
+
* This provides clean type inference without exposing Zod implementation details.
|
|
81
|
+
*/
|
|
82
|
+
export type AlchemyConnectionConfig = z.infer<
|
|
83
|
+
typeof AlchemyConnectionConfigSchema
|
|
84
|
+
>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Validates an Alchemy connection configuration object.
|
|
88
|
+
*
|
|
89
|
+
* @param {unknown} config - The configuration object to validate
|
|
90
|
+
* @returns {AlchemyConnectionConfig} The validated configuration object
|
|
91
|
+
* @throws {ConnectionConfigError} If the configuration is invalid
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* try {
|
|
96
|
+
* const config = validateAlchemyConnectionConfig({
|
|
97
|
+
* apiKey: 'your-api-key'
|
|
98
|
+
* });
|
|
99
|
+
* // config is now typed as AlchemyConnectionConfig
|
|
100
|
+
* } catch (error) {
|
|
101
|
+
* if (error instanceof ConnectionConfigError) {
|
|
102
|
+
* console.error('Invalid config:', error.message);
|
|
103
|
+
* }
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export function validateAlchemyConnectionConfig(
|
|
108
|
+
config: unknown,
|
|
109
|
+
): AlchemyConnectionConfig {
|
|
110
|
+
const result = AlchemyConnectionConfigSchema.safeParse(config);
|
|
111
|
+
|
|
112
|
+
if (!result.success) {
|
|
113
|
+
const firstError = result.error.issues[0];
|
|
114
|
+
const details = firstError?.message || "Invalid connection configuration";
|
|
115
|
+
throw new ConnectionConfigError(details);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return result.data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Type guard to check if a value is a valid Alchemy connection config.
|
|
123
|
+
*
|
|
124
|
+
* @param {unknown} value - The value to check for validity
|
|
125
|
+
* @returns {boolean} True if the value is a valid Alchemy connection config
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```ts
|
|
129
|
+
* const maybeConfig: unknown = { apiKey: 'test' };
|
|
130
|
+
* if (isAlchemyConnectionConfig(maybeConfig)) {
|
|
131
|
+
* // TypeScript knows maybeConfig is AlchemyConnectionConfig here
|
|
132
|
+
* if (maybeConfig.apiKey) {
|
|
133
|
+
* console.log('Using API key:', maybeConfig.apiKey);
|
|
134
|
+
* }
|
|
135
|
+
* if (maybeConfig.url) {
|
|
136
|
+
* console.log('Using custom URL:', maybeConfig.url);
|
|
137
|
+
* }
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
export function isAlchemyConnectionConfig(
|
|
142
|
+
value: unknown,
|
|
143
|
+
): value is AlchemyConnectionConfig {
|
|
144
|
+
return AlchemyConnectionConfigSchema.safeParse(value).success;
|
|
145
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseError } from "../errors/BaseError.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Asserts that a value is never.
|
|
5
|
+
*
|
|
6
|
+
* @param {never} _x - The value to assert.
|
|
7
|
+
* @param {string} msg - The message to throw if the value is not never.
|
|
8
|
+
* @returns {never} Always throws an error.
|
|
9
|
+
*/
|
|
10
|
+
export const assertNever = (_x: never, msg: string): never => {
|
|
11
|
+
throw new BaseError(msg);
|
|
12
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BigNumberish represents values that can be converted to BigInt
|
|
3
|
+
*/
|
|
4
|
+
export type BigNumberish = string | number | bigint;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Multiplier configuration for bigint multiplication
|
|
8
|
+
*/
|
|
9
|
+
export type Multiplier = {
|
|
10
|
+
multiplier: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export enum RoundingMode {
|
|
14
|
+
ROUND_DOWN = 0,
|
|
15
|
+
ROUND_UP = 1,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates if a multiplier has acceptable precision (max 4 decimal places)
|
|
20
|
+
*
|
|
21
|
+
* @param {Multiplier} multiplier - the multiplier to validate
|
|
22
|
+
* @returns {boolean} true if valid, false otherwise
|
|
23
|
+
*/
|
|
24
|
+
function isValidMultiplier(multiplier: Multiplier): boolean {
|
|
25
|
+
const decimalPlaces =
|
|
26
|
+
multiplier.multiplier.toString().split(".")[1]?.length ?? 0;
|
|
27
|
+
return decimalPlaces <= 4;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Given a bigint and a number (which can be a float), returns the bigint value.
|
|
32
|
+
* Note: this function has loss and will round down to the nearest integer.
|
|
33
|
+
*
|
|
34
|
+
* @param {BigNumberish} base - the number to be multiplied
|
|
35
|
+
* @param {number} multiplier - the amount to multiply by
|
|
36
|
+
* @param {RoundingMode} roundingMode - the rounding mode to use when calculating the percent. defaults to ROUND_UP
|
|
37
|
+
* @returns {bigint} the bigint value of the multiplication with the number rounded by the rounding mode
|
|
38
|
+
*/
|
|
39
|
+
export const bigIntMultiply = (
|
|
40
|
+
base: BigNumberish,
|
|
41
|
+
multiplier: Multiplier["multiplier"],
|
|
42
|
+
roundingMode: RoundingMode = RoundingMode.ROUND_UP,
|
|
43
|
+
) => {
|
|
44
|
+
if (!isValidMultiplier({ multiplier })) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
"bigIntMultiply requires a multiplier validated number as the second argument (max 4 decimal places)",
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Get decimal places of b. Max decimal places is defined by the validation above.
|
|
51
|
+
const decimalPlaces = multiplier.toString().split(".")[1]?.length ?? 0;
|
|
52
|
+
const result =
|
|
53
|
+
BigInt(base) * BigInt(Math.round(multiplier * 10 ** decimalPlaces));
|
|
54
|
+
return roundingMode === RoundingMode.ROUND_UP &&
|
|
55
|
+
result % BigInt(10 ** decimalPlaces) > 0
|
|
56
|
+
? result / BigInt(10 ** decimalPlaces) + 1n
|
|
57
|
+
: result / BigInt(10 ** decimalPlaces);
|
|
58
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a typed handler factory for EIP1193 request methods.
|
|
3
|
+
* This helps with Viem's typing within custom EIP1193 request functions by
|
|
4
|
+
* automatically casting input params and ensuring the result matches what is required.
|
|
5
|
+
*
|
|
6
|
+
* @returns {(params: unknown) => unknown} A function that creates a handler factory for specific methods
|
|
7
|
+
*/
|
|
8
|
+
export const createEip1193HandlerFactory =
|
|
9
|
+
<
|
|
10
|
+
TMethods extends readonly {
|
|
11
|
+
Method: string;
|
|
12
|
+
Parameters?: unknown;
|
|
13
|
+
ReturnType?: unknown;
|
|
14
|
+
}[],
|
|
15
|
+
>() =>
|
|
16
|
+
<TMethod extends TMethods[number]["Method"]>(
|
|
17
|
+
handle: (
|
|
18
|
+
params: Extract<TMethods[number], { Method: TMethod }>["Parameters"],
|
|
19
|
+
) => Promise<Extract<TMethods[number], { Method: TMethod }>["ReturnType"]>,
|
|
20
|
+
) =>
|
|
21
|
+
(params: unknown) => {
|
|
22
|
+
return handle(
|
|
23
|
+
params as Extract<TMethods[number], { Method: TMethod }>["Parameters"],
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { VERSION } from "../version.js";
|
|
2
|
+
|
|
3
|
+
export type WithAlchemyHeadersParams = {
|
|
4
|
+
headers?: HeadersInit;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
jwt?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function withAlchemyHeaders({
|
|
10
|
+
headers,
|
|
11
|
+
apiKey,
|
|
12
|
+
jwt,
|
|
13
|
+
}: WithAlchemyHeadersParams): Record<string, string> {
|
|
14
|
+
const bearerToken = jwt ?? apiKey;
|
|
15
|
+
return {
|
|
16
|
+
...convertHeadersToObject(headers),
|
|
17
|
+
"Alchemy-AA-Sdk-Version": VERSION,
|
|
18
|
+
...(bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function convertHeadersToObject(
|
|
23
|
+
headers?: HeadersInit,
|
|
24
|
+
): Record<string, string> {
|
|
25
|
+
if (!headers) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (headers instanceof Headers) {
|
|
30
|
+
const headersObject = {} as Record<string, string>;
|
|
31
|
+
headers.forEach((value, key) => {
|
|
32
|
+
headersObject[key] = value;
|
|
33
|
+
});
|
|
34
|
+
return headersObject;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(headers)) {
|
|
38
|
+
return headers.reduce(
|
|
39
|
+
(acc, header) => {
|
|
40
|
+
acc[header[0]] = header[1];
|
|
41
|
+
return acc;
|
|
42
|
+
},
|
|
43
|
+
{} as Record<string, string>,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return headers;
|
|
48
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Lowercase an address
|
|
5
|
+
*
|
|
6
|
+
* @param {Address} addr - The address to lowercase
|
|
7
|
+
* @returns {Address} The lowercase address
|
|
8
|
+
*/
|
|
9
|
+
export const lowerAddress = (addr: Address): Address =>
|
|
10
|
+
addr.toLowerCase() as Address;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseError } from "viem";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Raises an error.
|
|
5
|
+
*
|
|
6
|
+
* @param {string | BaseError} err - The error to raise.
|
|
7
|
+
* @returns {never} Always throws an error.
|
|
8
|
+
*/
|
|
9
|
+
export const raise = (err: string | BaseError): never => {
|
|
10
|
+
if (typeof err === "string") {
|
|
11
|
+
throw new BaseError(err);
|
|
12
|
+
}
|
|
13
|
+
throw err;
|
|
14
|
+
};
|