@awarizon/web3 1.0.0 → 1.0.2

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.mts CHANGED
@@ -1,7 +1,8 @@
1
- import { Chain, WalletClient, Address, Abi, PublicClient } from 'viem';
1
+ import { Chain, WalletClient, Address, Abi, PublicClient, Hex } from 'viem';
2
2
  export { Abi, Address, Chain, Hash, TransactionReceipt, WalletClient } from 'viem';
3
- import { WalletEngine } from '@awarizon/wallet-engine';
3
+ import { WalletEngine, CreatedWallet, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, ExternalWalletClient } from '@awarizon/wallet-engine';
4
4
  export { ChainSwitchError, InvalidMnemonicError, InvalidPrivateKeyError, WalletEngine, WalletNotConnectedError } from '@awarizon/wallet-engine';
5
+ import { TransactionResult } from '@awarizon/tx-engine';
5
6
  export { ContractExecutionError, GasEstimationError, SimulationError, TransactionEngine, TransactionResult, TransactionTimeoutError } from '@awarizon/tx-engine';
6
7
  export { DuplicateFunctionError, InvalidABIError, UnsupportedABIItemError, generateAllMethodSignatures, generateMethodSignature, isPayableFunction, isWriteFunction, parseABI } from '@awarizon/abi-engine';
7
8
 
@@ -12,6 +13,12 @@ interface AwarizonConfig {
12
13
  * - a viem Chain object: `import { base } from "viem/chains"`
13
14
  */
14
15
  chain: Chain | string;
16
+ /**
17
+ * Awarizon API key (required).
18
+ * Generate one at https://awarizon.com/dashboard/api-keys
19
+ * Format: "awz_live_..."
20
+ */
21
+ apiKey: string;
15
22
  /**
16
23
  * Optional RPC URL override.
17
24
  * If omitted, the chain's default public RPC endpoint is used.
@@ -19,9 +26,14 @@ interface AwarizonConfig {
19
26
  rpcUrl?: string;
20
27
  /**
21
28
  * Optional pre-connected external signer.
22
- * Equivalent to calling `sdk.connectWallet(signer)` after construction.
29
+ * Equivalent to calling `awarizon.connectWallet(signer)` after construction.
23
30
  */
24
31
  signer?: WalletClient;
32
+ /**
33
+ * Base URL of the Awarizon API. Defaults to "https://awarizon.com".
34
+ * Override for local development or staging environments.
35
+ */
36
+ baseUrl?: string;
25
37
  }
26
38
  interface ContractConfig<TAbi extends Abi = Abi> {
27
39
  /** The deployed contract address */
@@ -39,7 +51,7 @@ interface PayableOptions {
39
51
  gas?: bigint;
40
52
  }
41
53
  /**
42
- * The dynamically-generated contract instance returned by sdk.contract().
54
+ * The dynamically-generated contract instance returned by awarizon.contract().
43
55
  *
44
56
  * Every function in the ABI is exposed as a method:
45
57
  * - read functions (view/pure) → return decoded values
@@ -85,79 +97,163 @@ declare class UnsupportedChainError extends Error {
85
97
  readonly chain: string;
86
98
  constructor(chain: string);
87
99
  }
100
+ declare class ApiKeyRequiredError extends Error {
101
+ readonly code: "API_KEY_REQUIRED";
102
+ constructor();
103
+ }
104
+ declare class InvalidApiKeyError extends Error {
105
+ readonly code: "INVALID_API_KEY";
106
+ constructor(message?: string);
107
+ }
88
108
 
89
109
  /**
90
- * The primary entry point for the Awarizon Web3 SDK.
110
+ * Wraps WalletEngine and gates mutating operations (create, import) behind
111
+ * API key validation. Read-only operations (address, isConnected, etc.) are
112
+ * never gated since they need no network access.
113
+ */
114
+ declare class WalletProxy {
115
+ private readonly engine;
116
+ private readonly ensureReady;
117
+ constructor(engine: WalletEngine, ensureReady: () => Promise<void>);
118
+ create(): Promise<CreatedWallet>;
119
+ importMnemonic(mnemonic: string, accountIndex?: number): Promise<ImportedWalletFromMnemonic>;
120
+ importPrivateKey(privateKey: Hex): Promise<ImportedWalletFromPrivateKey>;
121
+ address(): Address;
122
+ getSigner(): WalletClient;
123
+ getWalletClient(): WalletClient;
124
+ isConnected(): boolean;
125
+ hasExternalWallet(): boolean;
126
+ hasInternalWallet(): boolean;
127
+ connectExternal(c: ExternalWalletClient): void;
128
+ disconnectExternal(): void;
129
+ disconnect(): void;
130
+ switchChain(chain: Chain): Promise<void>;
131
+ }
132
+ /**
133
+ * Primary entry point for the Awarizon Web3 SDK.
134
+ *
135
+ * An API key is required — get yours at https://awarizon.com/dashboard/api-keys
91
136
  *
92
137
  * ```ts
93
- * const sdk = new AwarizonWeb3({ chain: "base" })
138
+ * const awarizon = new AwarizonWeb3({ chain: "base", apiKey: "awz_live_..." })
94
139
  *
95
140
  * // Internal wallet
96
- * const wallet = await sdk.wallet.create()
141
+ * const wallet = await awarizon.wallet.create()
97
142
  *
98
- * // Load a contract and call it
99
- * const staking = await sdk.contract({ address: "0x...", abi })
143
+ * // Load a contract
144
+ * const staking = await awarizon.contract({ address: "0x...", abi })
100
145
  * await staking.stake(100n)
101
- * const balance = await staking.getBalance(wallet.address)
102
- *
103
- * // Listen for events
104
146
  * staking.on("Staked", (log) => console.log(log))
105
147
  * ```
106
148
  */
107
149
  declare class AwarizonWeb3 {
108
- /** The resolved viem Chain */
109
150
  readonly chain: Chain;
110
- /** Internal wallet + signer management */
111
- readonly wallet: WalletEngine;
112
- /** The underlying viem PublicClient used for reads */
113
151
  readonly publicClient: PublicClient;
152
+ /** Wallet management — create, import, or connect external wallets */
153
+ readonly wallet: WalletProxy;
154
+ private readonly _engine;
155
+ private readonly _txEngine;
156
+ private readonly _telemetry;
157
+ private _contractCache;
114
158
  constructor(config: AwarizonConfig);
115
- /**
116
- * Connect an external wallet client (wagmi, WalletConnect, viem, EIP-1193).
117
- * The connected signer takes priority over any internal wallet.
118
- *
119
- * @example
120
- * sdk.connectWallet(walletClient)
121
- */
122
159
  connectWallet(walletClient: WalletClient): this;
123
- /**
124
- * Disconnect the externally-connected wallet.
125
- * Falls back to the internal wallet if one is loaded.
126
- */
127
160
  disconnectWallet(): this;
161
+ switchChain(chain: Chain | string): Promise<this>;
162
+ getWalletInfo(): SDKWalletInfo;
128
163
  /**
129
- * Switch the active chain.
130
- * Rebuilds the PublicClient and internal WalletClient for the new chain.
164
+ * Load a deployed contract and return a fully typed, ABI-powered instance.
165
+ * Validates the API key on the first call subsequent calls are instant.
166
+ *
167
+ * Results are cached by address — calling contract() twice with the same
168
+ * address and ABI object returns the same instance without rebuilding.
131
169
  */
132
- switchChain(chain: Chain | string): Promise<this>;
170
+ contract<TAbi extends Abi>(config: ContractConfig<TAbi>): Promise<ContractInstance>;
133
171
  /**
134
- * Returns a summary of the currently active wallet.
135
- * @throws {WalletNotConnectedError} if no wallet is connected
172
+ * Load multiple contracts in parallel. Validates the API key once, then
173
+ * instantiates all contracts concurrently.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * const [token, staking, nft] = await awarizon.contracts([
178
+ * { address: tokenAddr, abi: ERC20_ABI },
179
+ * { address: stakingAddr, abi: STAKING_ABI },
180
+ * { address: nftAddr, abi: ERC721_ABI },
181
+ * ])
182
+ * ```
136
183
  */
137
- getWalletInfo(): SDKWalletInfo;
184
+ contracts(configs: Array<{
185
+ address: Address;
186
+ abi: Abi;
187
+ }>): Promise<ContractInstance[]>;
138
188
  /**
139
- * Load a deployed smart contract and return a fully typed, ABI-powered
140
- * instance. Every function in the ABI is exposed as a direct method.
189
+ * Call a read-only (view/pure) contract function directly without loading
190
+ * a full contract instance. Best for one-off reads.
141
191
  *
142
- * **Read functions** (view / pure) use the PublicClient — no signer needed.
143
- * **Write functions** (nonpayable / payable) use the active WalletClient.
192
+ * @example
193
+ * ```ts
194
+ * const balance = await awarizon.read<bigint>({
195
+ * address: tokenAddress,
196
+ * abi: ERC20_ABI,
197
+ * method: "balanceOf",
198
+ * args: [userAddress],
199
+ * })
200
+ * ```
201
+ */
202
+ read<T = unknown>(params: {
203
+ address: Address;
204
+ abi: Abi;
205
+ method: string;
206
+ args?: unknown[];
207
+ }): Promise<T>;
208
+ /**
209
+ * Execute a state-mutating contract function directly without loading a full
210
+ * contract instance. Best for one-off writes.
144
211
  *
145
212
  * @example
146
- * const token = await sdk.contract({ address: "0x...", abi: ERC20_ABI })
147
- * const balance = await token.balanceOf(address) // read
148
- * await token.transfer(to, 100n) // write
149
- * token.on("Transfer", handler) // events
213
+ * ```ts
214
+ * const { hash, receipt } = await awarizon.write({
215
+ * address: tokenAddress,
216
+ * abi: ERC20_ABI,
217
+ * method: "transfer",
218
+ * args: [recipient, 100n],
219
+ * })
220
+ * ```
150
221
  */
151
- contract<TAbi extends Abi>(config: ContractConfig<TAbi>): Promise<ContractInstance>;
222
+ write(params: {
223
+ address: Address;
224
+ abi: Abi;
225
+ method: string;
226
+ args?: unknown[];
227
+ value?: bigint;
228
+ gas?: bigint;
229
+ }): Promise<TransactionResult>;
152
230
  /**
153
- * Returns the chain ID of the current chain.
154
- * Useful for runtime network validation.
231
+ * Batch multiple read calls into a single RPC round-trip using multicall3.
232
+ * Falls back to parallel individual reads on chains where multicall3 is
233
+ * not deployed.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const [balance, supply, allowance] = await awarizon.multicall([
238
+ * { address: tokenAddr, abi: ERC20_ABI, method: "balanceOf", args: [userAddr] },
239
+ * { address: tokenAddr, abi: ERC20_ABI, method: "totalSupply" },
240
+ * { address: tokenAddr, abi: ERC20_ABI, method: "allowance", args: [userAddr, spenderAddr] },
241
+ * ])
242
+ * ```
155
243
  */
244
+ multicall(calls: Array<{
245
+ address: Address;
246
+ abi: Abi;
247
+ method: string;
248
+ args?: unknown[];
249
+ }>): Promise<unknown[]>;
156
250
  get chainId(): number;
251
+ get isConnected(): boolean;
157
252
  /**
158
- * Check whether any wallet (internal or external) is connected.
253
+ * Flush pending telemetry and stop background timers.
254
+ * Call when tearing down a long-lived SDK instance (e.g. on server shutdown).
159
255
  */
160
- get isConnected(): boolean;
256
+ destroy(): Promise<void>;
161
257
  }
162
258
 
163
259
  declare const CHAINS: Record<string, Chain>;
@@ -173,4 +269,62 @@ declare function resolveChain(chain: Chain | string): Chain;
173
269
  /** Returns a list of all unique supported chain IDs */
174
270
  declare function getSupportedChainIds(): number[];
175
271
 
176
- export { type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type EventUnsubscribe, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, UnsupportedChainError, getSupportedChainIds, resolveChain };
272
+ type TelemetryEventType = 'contract.read' | 'contract.write' | 'contract.gas_estimate' | 'wallet.create' | 'wallet.import' | 'chain.switch';
273
+ interface TelemetryEvent {
274
+ type: TelemetryEventType;
275
+ chain: string;
276
+ chainId: number;
277
+ functionName?: string;
278
+ success: boolean;
279
+ durationMs: number;
280
+ ts: number;
281
+ }
282
+ /**
283
+ * Handles SDK-to-Awarizon API communication:
284
+ * 1. Validates the API key on first meaningful operation (5s timeout)
285
+ * 2. Batches usage events and flushes them fire-and-forget
286
+ * 3. Flushes remaining events via sendBeacon on browser page unload
287
+ *
288
+ * All telemetry failures are swallowed — they never surface to the caller.
289
+ * The only hard error is InvalidApiKeyError thrown from ensureValidated().
290
+ */
291
+ declare class TelemetryClient {
292
+ private readonly apiKey;
293
+ private readonly baseUrl;
294
+ private validated;
295
+ private validationPromise;
296
+ private queue;
297
+ private flushTimer;
298
+ private unloadListener;
299
+ constructor(apiKey: string, baseUrl?: string);
300
+ /**
301
+ * Ensures the API key has been validated against the Awarizon API.
302
+ * Idempotent — safe to call on every operation; only hits the network once.
303
+ * Times out after 5 seconds to avoid hanging in degraded network conditions.
304
+ *
305
+ * @throws {InvalidApiKeyError} if the key is invalid, revoked, or unreachable
306
+ */
307
+ ensureValidated(): Promise<void>;
308
+ /**
309
+ * Queue a usage event. Events are batched and sent periodically.
310
+ * Must only be called after ensureValidated() has resolved.
311
+ */
312
+ track(event: TelemetryEvent): void;
313
+ /**
314
+ * Flush pending events and stop background timers.
315
+ * Call when tearing down a long-lived SDK instance (e.g. server shutdown).
316
+ */
317
+ destroy(): Promise<void>;
318
+ private _validate;
319
+ private _startTimers;
320
+ private _stopTimers;
321
+ /**
322
+ * Unified flush. Pass `await = true` for graceful shutdown,
323
+ * `await = false` for fire-and-forget mid-session flushes.
324
+ */
325
+ private _flush;
326
+ /** Uses sendBeacon for guaranteed delivery on page unload */
327
+ private _flushBeacon;
328
+ }
329
+
330
+ export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getSupportedChainIds, resolveChain };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { Chain, WalletClient, Address, Abi, PublicClient } from 'viem';
1
+ import { Chain, WalletClient, Address, Abi, PublicClient, Hex } from 'viem';
2
2
  export { Abi, Address, Chain, Hash, TransactionReceipt, WalletClient } from 'viem';
3
- import { WalletEngine } from '@awarizon/wallet-engine';
3
+ import { WalletEngine, CreatedWallet, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, ExternalWalletClient } from '@awarizon/wallet-engine';
4
4
  export { ChainSwitchError, InvalidMnemonicError, InvalidPrivateKeyError, WalletEngine, WalletNotConnectedError } from '@awarizon/wallet-engine';
5
+ import { TransactionResult } from '@awarizon/tx-engine';
5
6
  export { ContractExecutionError, GasEstimationError, SimulationError, TransactionEngine, TransactionResult, TransactionTimeoutError } from '@awarizon/tx-engine';
6
7
  export { DuplicateFunctionError, InvalidABIError, UnsupportedABIItemError, generateAllMethodSignatures, generateMethodSignature, isPayableFunction, isWriteFunction, parseABI } from '@awarizon/abi-engine';
7
8
 
@@ -12,6 +13,12 @@ interface AwarizonConfig {
12
13
  * - a viem Chain object: `import { base } from "viem/chains"`
13
14
  */
14
15
  chain: Chain | string;
16
+ /**
17
+ * Awarizon API key (required).
18
+ * Generate one at https://awarizon.com/dashboard/api-keys
19
+ * Format: "awz_live_..."
20
+ */
21
+ apiKey: string;
15
22
  /**
16
23
  * Optional RPC URL override.
17
24
  * If omitted, the chain's default public RPC endpoint is used.
@@ -19,9 +26,14 @@ interface AwarizonConfig {
19
26
  rpcUrl?: string;
20
27
  /**
21
28
  * Optional pre-connected external signer.
22
- * Equivalent to calling `sdk.connectWallet(signer)` after construction.
29
+ * Equivalent to calling `awarizon.connectWallet(signer)` after construction.
23
30
  */
24
31
  signer?: WalletClient;
32
+ /**
33
+ * Base URL of the Awarizon API. Defaults to "https://awarizon.com".
34
+ * Override for local development or staging environments.
35
+ */
36
+ baseUrl?: string;
25
37
  }
26
38
  interface ContractConfig<TAbi extends Abi = Abi> {
27
39
  /** The deployed contract address */
@@ -39,7 +51,7 @@ interface PayableOptions {
39
51
  gas?: bigint;
40
52
  }
41
53
  /**
42
- * The dynamically-generated contract instance returned by sdk.contract().
54
+ * The dynamically-generated contract instance returned by awarizon.contract().
43
55
  *
44
56
  * Every function in the ABI is exposed as a method:
45
57
  * - read functions (view/pure) → return decoded values
@@ -85,79 +97,163 @@ declare class UnsupportedChainError extends Error {
85
97
  readonly chain: string;
86
98
  constructor(chain: string);
87
99
  }
100
+ declare class ApiKeyRequiredError extends Error {
101
+ readonly code: "API_KEY_REQUIRED";
102
+ constructor();
103
+ }
104
+ declare class InvalidApiKeyError extends Error {
105
+ readonly code: "INVALID_API_KEY";
106
+ constructor(message?: string);
107
+ }
88
108
 
89
109
  /**
90
- * The primary entry point for the Awarizon Web3 SDK.
110
+ * Wraps WalletEngine and gates mutating operations (create, import) behind
111
+ * API key validation. Read-only operations (address, isConnected, etc.) are
112
+ * never gated since they need no network access.
113
+ */
114
+ declare class WalletProxy {
115
+ private readonly engine;
116
+ private readonly ensureReady;
117
+ constructor(engine: WalletEngine, ensureReady: () => Promise<void>);
118
+ create(): Promise<CreatedWallet>;
119
+ importMnemonic(mnemonic: string, accountIndex?: number): Promise<ImportedWalletFromMnemonic>;
120
+ importPrivateKey(privateKey: Hex): Promise<ImportedWalletFromPrivateKey>;
121
+ address(): Address;
122
+ getSigner(): WalletClient;
123
+ getWalletClient(): WalletClient;
124
+ isConnected(): boolean;
125
+ hasExternalWallet(): boolean;
126
+ hasInternalWallet(): boolean;
127
+ connectExternal(c: ExternalWalletClient): void;
128
+ disconnectExternal(): void;
129
+ disconnect(): void;
130
+ switchChain(chain: Chain): Promise<void>;
131
+ }
132
+ /**
133
+ * Primary entry point for the Awarizon Web3 SDK.
134
+ *
135
+ * An API key is required — get yours at https://awarizon.com/dashboard/api-keys
91
136
  *
92
137
  * ```ts
93
- * const sdk = new AwarizonWeb3({ chain: "base" })
138
+ * const awarizon = new AwarizonWeb3({ chain: "base", apiKey: "awz_live_..." })
94
139
  *
95
140
  * // Internal wallet
96
- * const wallet = await sdk.wallet.create()
141
+ * const wallet = await awarizon.wallet.create()
97
142
  *
98
- * // Load a contract and call it
99
- * const staking = await sdk.contract({ address: "0x...", abi })
143
+ * // Load a contract
144
+ * const staking = await awarizon.contract({ address: "0x...", abi })
100
145
  * await staking.stake(100n)
101
- * const balance = await staking.getBalance(wallet.address)
102
- *
103
- * // Listen for events
104
146
  * staking.on("Staked", (log) => console.log(log))
105
147
  * ```
106
148
  */
107
149
  declare class AwarizonWeb3 {
108
- /** The resolved viem Chain */
109
150
  readonly chain: Chain;
110
- /** Internal wallet + signer management */
111
- readonly wallet: WalletEngine;
112
- /** The underlying viem PublicClient used for reads */
113
151
  readonly publicClient: PublicClient;
152
+ /** Wallet management — create, import, or connect external wallets */
153
+ readonly wallet: WalletProxy;
154
+ private readonly _engine;
155
+ private readonly _txEngine;
156
+ private readonly _telemetry;
157
+ private _contractCache;
114
158
  constructor(config: AwarizonConfig);
115
- /**
116
- * Connect an external wallet client (wagmi, WalletConnect, viem, EIP-1193).
117
- * The connected signer takes priority over any internal wallet.
118
- *
119
- * @example
120
- * sdk.connectWallet(walletClient)
121
- */
122
159
  connectWallet(walletClient: WalletClient): this;
123
- /**
124
- * Disconnect the externally-connected wallet.
125
- * Falls back to the internal wallet if one is loaded.
126
- */
127
160
  disconnectWallet(): this;
161
+ switchChain(chain: Chain | string): Promise<this>;
162
+ getWalletInfo(): SDKWalletInfo;
128
163
  /**
129
- * Switch the active chain.
130
- * Rebuilds the PublicClient and internal WalletClient for the new chain.
164
+ * Load a deployed contract and return a fully typed, ABI-powered instance.
165
+ * Validates the API key on the first call subsequent calls are instant.
166
+ *
167
+ * Results are cached by address — calling contract() twice with the same
168
+ * address and ABI object returns the same instance without rebuilding.
131
169
  */
132
- switchChain(chain: Chain | string): Promise<this>;
170
+ contract<TAbi extends Abi>(config: ContractConfig<TAbi>): Promise<ContractInstance>;
133
171
  /**
134
- * Returns a summary of the currently active wallet.
135
- * @throws {WalletNotConnectedError} if no wallet is connected
172
+ * Load multiple contracts in parallel. Validates the API key once, then
173
+ * instantiates all contracts concurrently.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * const [token, staking, nft] = await awarizon.contracts([
178
+ * { address: tokenAddr, abi: ERC20_ABI },
179
+ * { address: stakingAddr, abi: STAKING_ABI },
180
+ * { address: nftAddr, abi: ERC721_ABI },
181
+ * ])
182
+ * ```
136
183
  */
137
- getWalletInfo(): SDKWalletInfo;
184
+ contracts(configs: Array<{
185
+ address: Address;
186
+ abi: Abi;
187
+ }>): Promise<ContractInstance[]>;
138
188
  /**
139
- * Load a deployed smart contract and return a fully typed, ABI-powered
140
- * instance. Every function in the ABI is exposed as a direct method.
189
+ * Call a read-only (view/pure) contract function directly without loading
190
+ * a full contract instance. Best for one-off reads.
141
191
  *
142
- * **Read functions** (view / pure) use the PublicClient — no signer needed.
143
- * **Write functions** (nonpayable / payable) use the active WalletClient.
192
+ * @example
193
+ * ```ts
194
+ * const balance = await awarizon.read<bigint>({
195
+ * address: tokenAddress,
196
+ * abi: ERC20_ABI,
197
+ * method: "balanceOf",
198
+ * args: [userAddress],
199
+ * })
200
+ * ```
201
+ */
202
+ read<T = unknown>(params: {
203
+ address: Address;
204
+ abi: Abi;
205
+ method: string;
206
+ args?: unknown[];
207
+ }): Promise<T>;
208
+ /**
209
+ * Execute a state-mutating contract function directly without loading a full
210
+ * contract instance. Best for one-off writes.
144
211
  *
145
212
  * @example
146
- * const token = await sdk.contract({ address: "0x...", abi: ERC20_ABI })
147
- * const balance = await token.balanceOf(address) // read
148
- * await token.transfer(to, 100n) // write
149
- * token.on("Transfer", handler) // events
213
+ * ```ts
214
+ * const { hash, receipt } = await awarizon.write({
215
+ * address: tokenAddress,
216
+ * abi: ERC20_ABI,
217
+ * method: "transfer",
218
+ * args: [recipient, 100n],
219
+ * })
220
+ * ```
150
221
  */
151
- contract<TAbi extends Abi>(config: ContractConfig<TAbi>): Promise<ContractInstance>;
222
+ write(params: {
223
+ address: Address;
224
+ abi: Abi;
225
+ method: string;
226
+ args?: unknown[];
227
+ value?: bigint;
228
+ gas?: bigint;
229
+ }): Promise<TransactionResult>;
152
230
  /**
153
- * Returns the chain ID of the current chain.
154
- * Useful for runtime network validation.
231
+ * Batch multiple read calls into a single RPC round-trip using multicall3.
232
+ * Falls back to parallel individual reads on chains where multicall3 is
233
+ * not deployed.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * const [balance, supply, allowance] = await awarizon.multicall([
238
+ * { address: tokenAddr, abi: ERC20_ABI, method: "balanceOf", args: [userAddr] },
239
+ * { address: tokenAddr, abi: ERC20_ABI, method: "totalSupply" },
240
+ * { address: tokenAddr, abi: ERC20_ABI, method: "allowance", args: [userAddr, spenderAddr] },
241
+ * ])
242
+ * ```
155
243
  */
244
+ multicall(calls: Array<{
245
+ address: Address;
246
+ abi: Abi;
247
+ method: string;
248
+ args?: unknown[];
249
+ }>): Promise<unknown[]>;
156
250
  get chainId(): number;
251
+ get isConnected(): boolean;
157
252
  /**
158
- * Check whether any wallet (internal or external) is connected.
253
+ * Flush pending telemetry and stop background timers.
254
+ * Call when tearing down a long-lived SDK instance (e.g. on server shutdown).
159
255
  */
160
- get isConnected(): boolean;
256
+ destroy(): Promise<void>;
161
257
  }
162
258
 
163
259
  declare const CHAINS: Record<string, Chain>;
@@ -173,4 +269,62 @@ declare function resolveChain(chain: Chain | string): Chain;
173
269
  /** Returns a list of all unique supported chain IDs */
174
270
  declare function getSupportedChainIds(): number[];
175
271
 
176
- export { type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type EventUnsubscribe, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, UnsupportedChainError, getSupportedChainIds, resolveChain };
272
+ type TelemetryEventType = 'contract.read' | 'contract.write' | 'contract.gas_estimate' | 'wallet.create' | 'wallet.import' | 'chain.switch';
273
+ interface TelemetryEvent {
274
+ type: TelemetryEventType;
275
+ chain: string;
276
+ chainId: number;
277
+ functionName?: string;
278
+ success: boolean;
279
+ durationMs: number;
280
+ ts: number;
281
+ }
282
+ /**
283
+ * Handles SDK-to-Awarizon API communication:
284
+ * 1. Validates the API key on first meaningful operation (5s timeout)
285
+ * 2. Batches usage events and flushes them fire-and-forget
286
+ * 3. Flushes remaining events via sendBeacon on browser page unload
287
+ *
288
+ * All telemetry failures are swallowed — they never surface to the caller.
289
+ * The only hard error is InvalidApiKeyError thrown from ensureValidated().
290
+ */
291
+ declare class TelemetryClient {
292
+ private readonly apiKey;
293
+ private readonly baseUrl;
294
+ private validated;
295
+ private validationPromise;
296
+ private queue;
297
+ private flushTimer;
298
+ private unloadListener;
299
+ constructor(apiKey: string, baseUrl?: string);
300
+ /**
301
+ * Ensures the API key has been validated against the Awarizon API.
302
+ * Idempotent — safe to call on every operation; only hits the network once.
303
+ * Times out after 5 seconds to avoid hanging in degraded network conditions.
304
+ *
305
+ * @throws {InvalidApiKeyError} if the key is invalid, revoked, or unreachable
306
+ */
307
+ ensureValidated(): Promise<void>;
308
+ /**
309
+ * Queue a usage event. Events are batched and sent periodically.
310
+ * Must only be called after ensureValidated() has resolved.
311
+ */
312
+ track(event: TelemetryEvent): void;
313
+ /**
314
+ * Flush pending events and stop background timers.
315
+ * Call when tearing down a long-lived SDK instance (e.g. server shutdown).
316
+ */
317
+ destroy(): Promise<void>;
318
+ private _validate;
319
+ private _startTimers;
320
+ private _stopTimers;
321
+ /**
322
+ * Unified flush. Pass `await = true` for graceful shutdown,
323
+ * `await = false` for fire-and-forget mid-session flushes.
324
+ */
325
+ private _flush;
326
+ /** Uses sendBeacon for guaranteed delivery on page unload */
327
+ private _flushBeacon;
328
+ }
329
+
330
+ export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getSupportedChainIds, resolveChain };