@awarizon/web3 1.3.1 → 1.3.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,4 +1,4 @@
1
- import { Chain, WalletClient, Address, Abi, PublicClient, Hex } from 'viem';
1
+ import { PublicClient, Chain, WalletClient, Address, Abi, Hex, Transport } from 'viem';
2
2
  export { Abi, Address, Chain, Hash, TransactionReceipt, WalletClient } from 'viem';
3
3
  import { WalletEngine, CreatedWallet, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, ConnectorInfo, ExternalWalletClient, EIP1193Provider, SignTypedDataParams, WalletChangeEvent, ChainChangeEvent } from '@awarizon/wallet-engine';
4
4
  export { ChainChangeEvent, ChainMismatchError, ChainSwitchError, ConnectorInfo, CreatedWallet, EIP1193Provider, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, InvalidMnemonicError, InvalidPrivateKeyError, SignTypedDataParams, WalletChangeEvent, WalletEngine, WalletNotConnectedError } from '@awarizon/wallet-engine';
@@ -6,6 +6,78 @@ import { TransactionResult } from '@awarizon/tx-engine';
6
6
  export { ContractExecutionError, GasEstimationError, SimulationError, TransactionEngine, TransactionResult, TransactionTimeoutError } from '@awarizon/tx-engine';
7
7
  export { DuplicateFunctionError, InvalidABIError, UnsupportedABIItemError, generateAllMethodSignatures, generateMethodSignature, isPayableFunction, isWriteFunction, parseABI } from '@awarizon/abi-engine';
8
8
 
9
+ interface PriceResult {
10
+ /** Uppercase token symbol (e.g. "ETH", "USDC") */
11
+ symbol: string;
12
+ /** Current USD price */
13
+ price: number;
14
+ /** Where the price came from */
15
+ source: 'chainlink' | 'coingecko';
16
+ /** Unix timestamp of the last update (only set for chainlink source) */
17
+ updatedAt?: number;
18
+ /** True when chainlink data is older than 2 hours */
19
+ stale?: boolean;
20
+ }
21
+ /**
22
+ * Fetches USD prices via Chainlink on-chain feeds (primary) with automatic
23
+ * fallback to CoinGecko's free API when no feed exists for the current chain.
24
+ *
25
+ * Attached to the SDK as `awarizon.price`.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const { price } = await awarizon.price.get('ETH')
30
+ * // → { symbol: 'ETH', price: 3421.57, source: 'chainlink', updatedAt: 1720000000 }
31
+ *
32
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
33
+ * // → { ETH: { price: 3421 }, BTC: { price: 68200 }, ... }
34
+ * ```
35
+ */
36
+ declare class PriceEngine {
37
+ private readonly publicClient;
38
+ private readonly chainId;
39
+ constructor(publicClient: PublicClient, chainId: number);
40
+ /**
41
+ * Get the current USD price of a single token by symbol.
42
+ * Tries Chainlink first; falls back to CoinGecko on failure or missing feed.
43
+ *
44
+ * @param symbol - Token symbol: 'ETH', 'BTC', 'USDC', 'LINK', etc.
45
+ *
46
+ * @example
47
+ * const { price, source } = await awarizon.price.get('ETH')
48
+ */
49
+ get(symbol: string): Promise<PriceResult>;
50
+ /**
51
+ * Get USD prices for multiple tokens in one call.
52
+ * Chainlink feeds are read in parallel; CoinGecko batch-fetches all remaining
53
+ * symbols in a single HTTP request — efficient even for large lists.
54
+ *
55
+ * @param symbols - Array of token symbols: ['ETH', 'BTC', 'USDC']
56
+ *
57
+ * @example
58
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
59
+ * console.log(prices.ETH.price) // 3421.57
60
+ * console.log(prices.ARB.source) // 'coingecko' (no feed on most chains)
61
+ */
62
+ getMany(symbols: string[]): Promise<Record<string, PriceResult>>;
63
+ /**
64
+ * Check whether a Chainlink feed exists for the given symbol on the current chain.
65
+ *
66
+ * @example
67
+ * awarizon.price.hasFeed('ETH') // true on mainnet, base, polygon, etc.
68
+ * awarizon.price.hasFeed('ARB') // true on Arbitrum, false elsewhere
69
+ */
70
+ hasFeed(symbol: string): boolean;
71
+ /**
72
+ * Return all symbols that have a Chainlink feed on the current chain.
73
+ *
74
+ * @example
75
+ * awarizon.price.supportedSymbols()
76
+ * // → ['ETH', 'BTC', 'LINK', 'USDC', 'USDT', 'DAI'] on Base
77
+ */
78
+ supportedSymbols(): string[];
79
+ }
80
+
9
81
  interface AwarizonConfig {
10
82
  /**
11
83
  * Target chain. Accepts:
@@ -723,6 +795,14 @@ declare class AwarizonWeb3 {
723
795
  readonly publicClient: PublicClient;
724
796
  /** Wallet management — create, import, or connect external wallets */
725
797
  readonly wallet: WalletProxy;
798
+ /**
799
+ * Token price engine — Chainlink on-chain feeds with CoinGecko fallback.
800
+ *
801
+ * @example
802
+ * const { price } = await awarizon.price.get('ETH')
803
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC'])
804
+ */
805
+ readonly price: PriceEngine;
726
806
  private readonly _engine;
727
807
  private readonly _txEngine;
728
808
  private readonly _telemetry;
@@ -1024,6 +1104,26 @@ declare const CHAINS: Record<string, Chain>;
1024
1104
  declare function resolveChain(chain: Chain | string): Chain;
1025
1105
  /** Returns a list of all unique supported chain IDs */
1026
1106
  declare function getSupportedChainIds(): number[];
1107
+ /**
1108
+ * Build the viem Transport for a chain.
1109
+ *
1110
+ * Priority:
1111
+ * 1. If the caller supplied an explicit `rpcUrlOverride`, use it directly.
1112
+ * 2. For chains with a known-unreliable default RPC, wrap primary + fallback
1113
+ * in viem's `fallback()` transport — primary is always tried first.
1114
+ * 3. All other chains: plain `http()` with viem's chain default.
1115
+ *
1116
+ * @example
1117
+ * // Fallback kicks in automatically for mantle, celo, gnosis, fantom, moonbeam
1118
+ * const transport = getChainTransport(mantle)
1119
+ *
1120
+ * // User override bypasses fallback entirely — they know what they want
1121
+ * const transport = getChainTransport(mantle, "https://my-own-rpc.example.com")
1122
+ */
1123
+ declare function getChainTransport(chain: Chain, rpcUrlOverride?: string): Transport;
1124
+
1125
+ declare const CHAINLINK_FEEDS: Record<number, Record<string, Address>>;
1126
+ declare const COINGECKO_IDS: Record<string, string>;
1027
1127
 
1028
1128
  type TelemetryEventType = 'contract.read' | 'contract.write' | 'contract.gas_estimate' | 'wallet.create' | 'wallet.import' | 'chain.switch';
1029
1129
  interface TelemetryEvent {
@@ -1083,4 +1183,4 @@ declare class TelemetryClient {
1083
1183
  private _flushBeacon;
1084
1184
  }
1085
1185
 
1086
- export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type ContractRegistryEntry, ERC1155_ABI, ERC20_ABI, ERC721_ABI, type Erc1155Contract, type Erc20Contract, type Erc721Contract, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getSupportedChainIds, resolveChain };
1186
+ export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINLINK_FEEDS, CHAINS, COINGECKO_IDS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type ContractRegistryEntry, ERC1155_ABI, ERC20_ABI, ERC721_ABI, type Erc1155Contract, type Erc20Contract, type Erc721Contract, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, PriceEngine, type PriceResult, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getChainTransport, getSupportedChainIds, resolveChain };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Chain, WalletClient, Address, Abi, PublicClient, Hex } from 'viem';
1
+ import { PublicClient, Chain, WalletClient, Address, Abi, Hex, Transport } from 'viem';
2
2
  export { Abi, Address, Chain, Hash, TransactionReceipt, WalletClient } from 'viem';
3
3
  import { WalletEngine, CreatedWallet, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, ConnectorInfo, ExternalWalletClient, EIP1193Provider, SignTypedDataParams, WalletChangeEvent, ChainChangeEvent } from '@awarizon/wallet-engine';
4
4
  export { ChainChangeEvent, ChainMismatchError, ChainSwitchError, ConnectorInfo, CreatedWallet, EIP1193Provider, ImportedWalletFromMnemonic, ImportedWalletFromPrivateKey, InvalidMnemonicError, InvalidPrivateKeyError, SignTypedDataParams, WalletChangeEvent, WalletEngine, WalletNotConnectedError } from '@awarizon/wallet-engine';
@@ -6,6 +6,78 @@ import { TransactionResult } from '@awarizon/tx-engine';
6
6
  export { ContractExecutionError, GasEstimationError, SimulationError, TransactionEngine, TransactionResult, TransactionTimeoutError } from '@awarizon/tx-engine';
7
7
  export { DuplicateFunctionError, InvalidABIError, UnsupportedABIItemError, generateAllMethodSignatures, generateMethodSignature, isPayableFunction, isWriteFunction, parseABI } from '@awarizon/abi-engine';
8
8
 
9
+ interface PriceResult {
10
+ /** Uppercase token symbol (e.g. "ETH", "USDC") */
11
+ symbol: string;
12
+ /** Current USD price */
13
+ price: number;
14
+ /** Where the price came from */
15
+ source: 'chainlink' | 'coingecko';
16
+ /** Unix timestamp of the last update (only set for chainlink source) */
17
+ updatedAt?: number;
18
+ /** True when chainlink data is older than 2 hours */
19
+ stale?: boolean;
20
+ }
21
+ /**
22
+ * Fetches USD prices via Chainlink on-chain feeds (primary) with automatic
23
+ * fallback to CoinGecko's free API when no feed exists for the current chain.
24
+ *
25
+ * Attached to the SDK as `awarizon.price`.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const { price } = await awarizon.price.get('ETH')
30
+ * // → { symbol: 'ETH', price: 3421.57, source: 'chainlink', updatedAt: 1720000000 }
31
+ *
32
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
33
+ * // → { ETH: { price: 3421 }, BTC: { price: 68200 }, ... }
34
+ * ```
35
+ */
36
+ declare class PriceEngine {
37
+ private readonly publicClient;
38
+ private readonly chainId;
39
+ constructor(publicClient: PublicClient, chainId: number);
40
+ /**
41
+ * Get the current USD price of a single token by symbol.
42
+ * Tries Chainlink first; falls back to CoinGecko on failure or missing feed.
43
+ *
44
+ * @param symbol - Token symbol: 'ETH', 'BTC', 'USDC', 'LINK', etc.
45
+ *
46
+ * @example
47
+ * const { price, source } = await awarizon.price.get('ETH')
48
+ */
49
+ get(symbol: string): Promise<PriceResult>;
50
+ /**
51
+ * Get USD prices for multiple tokens in one call.
52
+ * Chainlink feeds are read in parallel; CoinGecko batch-fetches all remaining
53
+ * symbols in a single HTTP request — efficient even for large lists.
54
+ *
55
+ * @param symbols - Array of token symbols: ['ETH', 'BTC', 'USDC']
56
+ *
57
+ * @example
58
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
59
+ * console.log(prices.ETH.price) // 3421.57
60
+ * console.log(prices.ARB.source) // 'coingecko' (no feed on most chains)
61
+ */
62
+ getMany(symbols: string[]): Promise<Record<string, PriceResult>>;
63
+ /**
64
+ * Check whether a Chainlink feed exists for the given symbol on the current chain.
65
+ *
66
+ * @example
67
+ * awarizon.price.hasFeed('ETH') // true on mainnet, base, polygon, etc.
68
+ * awarizon.price.hasFeed('ARB') // true on Arbitrum, false elsewhere
69
+ */
70
+ hasFeed(symbol: string): boolean;
71
+ /**
72
+ * Return all symbols that have a Chainlink feed on the current chain.
73
+ *
74
+ * @example
75
+ * awarizon.price.supportedSymbols()
76
+ * // → ['ETH', 'BTC', 'LINK', 'USDC', 'USDT', 'DAI'] on Base
77
+ */
78
+ supportedSymbols(): string[];
79
+ }
80
+
9
81
  interface AwarizonConfig {
10
82
  /**
11
83
  * Target chain. Accepts:
@@ -723,6 +795,14 @@ declare class AwarizonWeb3 {
723
795
  readonly publicClient: PublicClient;
724
796
  /** Wallet management — create, import, or connect external wallets */
725
797
  readonly wallet: WalletProxy;
798
+ /**
799
+ * Token price engine — Chainlink on-chain feeds with CoinGecko fallback.
800
+ *
801
+ * @example
802
+ * const { price } = await awarizon.price.get('ETH')
803
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC'])
804
+ */
805
+ readonly price: PriceEngine;
726
806
  private readonly _engine;
727
807
  private readonly _txEngine;
728
808
  private readonly _telemetry;
@@ -1024,6 +1104,26 @@ declare const CHAINS: Record<string, Chain>;
1024
1104
  declare function resolveChain(chain: Chain | string): Chain;
1025
1105
  /** Returns a list of all unique supported chain IDs */
1026
1106
  declare function getSupportedChainIds(): number[];
1107
+ /**
1108
+ * Build the viem Transport for a chain.
1109
+ *
1110
+ * Priority:
1111
+ * 1. If the caller supplied an explicit `rpcUrlOverride`, use it directly.
1112
+ * 2. For chains with a known-unreliable default RPC, wrap primary + fallback
1113
+ * in viem's `fallback()` transport — primary is always tried first.
1114
+ * 3. All other chains: plain `http()` with viem's chain default.
1115
+ *
1116
+ * @example
1117
+ * // Fallback kicks in automatically for mantle, celo, gnosis, fantom, moonbeam
1118
+ * const transport = getChainTransport(mantle)
1119
+ *
1120
+ * // User override bypasses fallback entirely — they know what they want
1121
+ * const transport = getChainTransport(mantle, "https://my-own-rpc.example.com")
1122
+ */
1123
+ declare function getChainTransport(chain: Chain, rpcUrlOverride?: string): Transport;
1124
+
1125
+ declare const CHAINLINK_FEEDS: Record<number, Record<string, Address>>;
1126
+ declare const COINGECKO_IDS: Record<string, string>;
1027
1127
 
1028
1128
  type TelemetryEventType = 'contract.read' | 'contract.write' | 'contract.gas_estimate' | 'wallet.create' | 'wallet.import' | 'chain.switch';
1029
1129
  interface TelemetryEvent {
@@ -1083,4 +1183,4 @@ declare class TelemetryClient {
1083
1183
  private _flushBeacon;
1084
1184
  }
1085
1185
 
1086
- export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type ContractRegistryEntry, ERC1155_ABI, ERC20_ABI, ERC721_ABI, type Erc1155Contract, type Erc20Contract, type Erc721Contract, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getSupportedChainIds, resolveChain };
1186
+ export { ApiKeyRequiredError, type AwarizonConfig, AwarizonWeb3, CHAINLINK_FEEDS, CHAINS, COINGECKO_IDS, type ContractConfig, type ContractInstance, ContractNotLoadedError, type ContractRegistryEntry, ERC1155_ABI, ERC20_ABI, ERC721_ABI, type Erc1155Contract, type Erc20Contract, type Erc721Contract, type EventUnsubscribe, InvalidApiKeyError, NetworkMismatchError, type PayableOptions, PriceEngine, type PriceResult, ProviderError, type SDKWalletInfo, TelemetryClient, type TelemetryEvent, type TelemetryEventType, UnsupportedChainError, getChainTransport, getSupportedChainIds, resolveChain };
package/dist/index.js CHANGED
@@ -82,6 +82,27 @@ function getSupportedChainIds() {
82
82
  return true;
83
83
  }).map((c) => c.id);
84
84
  }
85
+ var FALLBACK_RPCS = {
86
+ 5e3: "https://mantle-mainnet.public.blastapi.io",
87
+ // mantle
88
+ 42220: "https://celo.drpc.org",
89
+ // celo
90
+ 100: "https://gnosis.drpc.org",
91
+ // gnosis
92
+ 250: "https://rpc.fantom.network",
93
+ // fantom
94
+ 1284: "https://moonbeam.drpc.org"
95
+ // moonbeam
96
+ };
97
+ function getChainTransport(chain, rpcUrlOverride) {
98
+ if (rpcUrlOverride) return viem.http(rpcUrlOverride);
99
+ const fallbackUrl = FALLBACK_RPCS[chain.id];
100
+ if (fallbackUrl) {
101
+ const primaryUrl = chain.rpcUrls.default.http[0];
102
+ return viem.fallback([viem.http(primaryUrl), viem.http(fallbackUrl)]);
103
+ }
104
+ return viem.http();
105
+ }
85
106
  function trackEvent(telemetry, type, chain, functionName, success, start) {
86
107
  telemetry?.track({
87
108
  type,
@@ -361,6 +382,309 @@ var TelemetryClient = class {
361
382
  );
362
383
  }
363
384
  };
385
+
386
+ // src/price/feeds.ts
387
+ var AGGREGATOR_ABI = [
388
+ {
389
+ inputs: [],
390
+ name: "latestRoundData",
391
+ outputs: [
392
+ { name: "roundId", type: "uint80" },
393
+ { name: "answer", type: "int256" },
394
+ { name: "startedAt", type: "uint256" },
395
+ { name: "updatedAt", type: "uint256" },
396
+ { name: "answeredInRound", type: "uint80" }
397
+ ],
398
+ stateMutability: "view",
399
+ type: "function"
400
+ },
401
+ {
402
+ inputs: [],
403
+ name: "decimals",
404
+ outputs: [{ name: "", type: "uint8" }],
405
+ stateMutability: "view",
406
+ type: "function"
407
+ }
408
+ ];
409
+ var CHAINLINK_FEEDS = {
410
+ // Ethereum Mainnet
411
+ 1: {
412
+ ETH: "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",
413
+ BTC: "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88b",
414
+ BNB: "0x14e613AC84a31f709eadbEF3bf98585328207896",
415
+ MATIC: "0x7bAC85A8a13A4BcD8abb3eB7d6b4d632c895a5f6",
416
+ AVAX: "0xFF3EEb22B5E3dE6e705b44749C2559d704923FD7",
417
+ LINK: "0x2c1d072e956AFFC0D435Cb7AC308d97936742191",
418
+ UNI: "0x553303d460EE0afB37EdFf9bE42922D8FF63220e",
419
+ AAVE: "0x547a514d5e3769680Ce22B2361c10Ea13619e8a9",
420
+ MKR: "0xec1D1B3b0443256cc3860e24a46F108e699484Aa",
421
+ SNX: "0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699",
422
+ CRV: "0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33",
423
+ USDC: "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6",
424
+ USDT: "0x3E7d1eAB13ad0104d2750B8863b489D65364e32D",
425
+ DAI: "0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9",
426
+ FRAX: "0xB9E1E3A9feFf48998E45Fa90847ed4D467E8BcfD"
427
+ },
428
+ // Base
429
+ 8453: {
430
+ ETH: "0x71041dddad3595F9CEd3dCCFBe3D1F4b0a16Bb70",
431
+ BTC: "0x64c911996D3c6aC71f9b455B1E8E7266BcFBF15F",
432
+ LINK: "0x56a43EB56Da12C0dc1D972ACb089c06a5dEF8e69",
433
+ USDC: "0x7e860098F58bBFC8648a4311b374B1D669a2bc9b"
434
+ },
435
+ // Polygon
436
+ 137: {
437
+ ETH: "0xF9680D99D6C9589e2a93a78A04A279e509205945",
438
+ BTC: "0xc907E116054Ad103354f2D350FD2514433D57F6f",
439
+ MATIC: "0xAB594600376Ec9fD91F8e885dADF0CE036862dE0",
440
+ LINK: "0xd9FFdb71EbE7496cC440152d43986Aae0AB76665",
441
+ AAVE: "0x72484B12719E23115761D5DA1646945632979bB6",
442
+ UNI: "0xdf0Fb4e4F928d2dCB76f438575fDD8682386e13C",
443
+ USDC: "0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7",
444
+ USDT: "0x0A6513e40db6EB1b165753AD52E80663aea50545",
445
+ DAI: "0x4746DeC9e833A82EC7C2C1356372CcF2cfcD2F3D"
446
+ },
447
+ // Arbitrum One
448
+ 42161: {
449
+ ETH: "0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612",
450
+ BTC: "0x6ce185860a4963106506C203335A2910413708e9",
451
+ LINK: "0x86E53CF1B873786aC9Cc60cde71fFd0035d6df2d",
452
+ ARB: "0xb2A824043730FE05F3DA2efaFa1CBbe83fa548D6",
453
+ USDC: "0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3",
454
+ USDT: "0x3f3f5dF88dC9F13eac63DF89EC16ef6e7E25DdE7"
455
+ },
456
+ // Optimism
457
+ 10: {
458
+ ETH: "0x13e3Ee699D1909E989722E753853AE30b17e08c5",
459
+ BTC: "0xD702DD976Fb76Fffc2D3963D037dfDae5b04E593",
460
+ LINK: "0xCc232dcFAAE6354cE191Bd574108c1aD03f86450",
461
+ OP: "0x0D276FC14719f9292D5C1eA2198673d1f4269246",
462
+ USDC: "0x16a9FA2FDa030272Ce99B29CF780dFA30361d35f",
463
+ USDT: "0xECef79E109e997bCA29c1c0897ec9d7b03647F5E"
464
+ },
465
+ // BNB Smart Chain
466
+ 56: {
467
+ BNB: "0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE",
468
+ ETH: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2",
469
+ BTC: "0x264990fbd0A4796A3E3d8E37C4d5F87a3aCa5Ebf",
470
+ LINK: "0xca236E327F629f9Fc2c30A4E95775EbF0B89fac8",
471
+ USDT: "0xB97Ad0E74fa7d920791E90258A6E2085088b4320",
472
+ DAI: "0x132d3C0B1D2cEa0BC552588063bdBb210FDeecfA"
473
+ },
474
+ // Avalanche C-Chain
475
+ 43114: {
476
+ ETH: "0x976B3D034E162d8bD72D6b9C989d545b839003b0",
477
+ BTC: "0x2779D32d5166BAaa2B2b658333bA7e6Ec0C65743",
478
+ AVAX: "0x0A77230d17318075983913bC2145DB16C7366156",
479
+ LINK: "0x49ccd9ca821EfEab2b98c60DC60F518E765eDe9a",
480
+ USDC: "0xF096872672F44d6EBA71527d2277B6f4B77Ea29A",
481
+ USDT: "0xEBE676ee90Fe1112671f19b6B7459bC678B67e8a"
482
+ }
483
+ };
484
+ var COINGECKO_IDS = {
485
+ // Native tokens
486
+ ETH: "ethereum",
487
+ BTC: "bitcoin",
488
+ BNB: "binancecoin",
489
+ MATIC: "matic-network",
490
+ POL: "matic-network",
491
+ AVAX: "avalanche-2",
492
+ FTM: "fantom",
493
+ GLMR: "moonbeam",
494
+ CELO: "celo",
495
+ XDAI: "xdai",
496
+ GNO: "gnosis",
497
+ MNT: "mantle",
498
+ // Major stables
499
+ USDC: "usd-coin",
500
+ USDT: "tether",
501
+ DAI: "dai",
502
+ BUSD: "binance-usd",
503
+ FRAX: "frax",
504
+ LUSD: "liquity-usd",
505
+ GUSD: "gemini-dollar",
506
+ TUSD: "true-usd",
507
+ USDD: "usdd",
508
+ FDUSD: "first-digital-usd",
509
+ // DeFi blue chips
510
+ LINK: "chainlink",
511
+ UNI: "uniswap",
512
+ AAVE: "aave",
513
+ MKR: "maker",
514
+ SNX: "havven",
515
+ CRV: "curve-dao-token",
516
+ LDO: "lido-dao",
517
+ RPL: "rocket-pool",
518
+ BAL: "balancer",
519
+ COMP: "compound-governance-token",
520
+ YFI: "yearn-finance",
521
+ SUSHI: "sushi",
522
+ // L2 tokens
523
+ ARB: "arbitrum",
524
+ OP: "optimism",
525
+ IMX: "immutable-x",
526
+ // Other popular alts
527
+ DOGE: "dogecoin",
528
+ SHIB: "shiba-inu",
529
+ PEPE: "pepe",
530
+ WLD: "worldcoin-wld",
531
+ APE: "apecoin",
532
+ GRT: "the-graph",
533
+ ENS: "ethereum-name-service",
534
+ BLUR: "blur"
535
+ };
536
+
537
+ // src/price/index.ts
538
+ var TWO_HOURS_SECS = 7200;
539
+ async function fetchChainlink(publicClient, chainId, symbol) {
540
+ const feeds = CHAINLINK_FEEDS[chainId];
541
+ if (!feeds) return null;
542
+ const address = feeds[symbol.toUpperCase()];
543
+ if (!address) return null;
544
+ try {
545
+ const [roundData, rawDecimals] = await Promise.all([
546
+ publicClient.readContract({
547
+ address,
548
+ abi: AGGREGATOR_ABI,
549
+ functionName: "latestRoundData"
550
+ }),
551
+ publicClient.readContract({
552
+ address,
553
+ abi: AGGREGATOR_ABI,
554
+ functionName: "decimals"
555
+ })
556
+ ]);
557
+ const answer = roundData[1];
558
+ const updatedAt = Number(roundData[3]);
559
+ const decimals = Number(rawDecimals);
560
+ if (answer <= 0n) return null;
561
+ const price = Number(answer) / 10 ** decimals;
562
+ const stale = Date.now() / 1e3 - updatedAt > TWO_HOURS_SECS;
563
+ return { symbol: symbol.toUpperCase(), price, source: "chainlink", updatedAt, stale };
564
+ } catch {
565
+ return null;
566
+ }
567
+ }
568
+ var CG_BASE = "https://api.coingecko.com/api/v3";
569
+ async function fetchCoinGecko(symbols) {
570
+ const ids = symbols.map((s) => COINGECKO_IDS[s.toUpperCase()]).filter(Boolean);
571
+ if (ids.length === 0) return {};
572
+ const url = `${CG_BASE}/simple/price?ids=${ids.join(",")}&vs_currencies=usd`;
573
+ const res = await fetch(url);
574
+ if (!res.ok) throw new Error(`[awarizon/price] CoinGecko returned ${res.status}`);
575
+ const data = await res.json();
576
+ const out = {};
577
+ for (const sym of symbols) {
578
+ const id = COINGECKO_IDS[sym.toUpperCase()];
579
+ const price = id ? data[id]?.usd : void 0;
580
+ if (price !== void 0) out[sym.toUpperCase()] = price;
581
+ }
582
+ return out;
583
+ }
584
+ var PriceEngine = class {
585
+ constructor(publicClient, chainId) {
586
+ this.publicClient = publicClient;
587
+ this.chainId = chainId;
588
+ }
589
+ /**
590
+ * Get the current USD price of a single token by symbol.
591
+ * Tries Chainlink first; falls back to CoinGecko on failure or missing feed.
592
+ *
593
+ * @param symbol - Token symbol: 'ETH', 'BTC', 'USDC', 'LINK', etc.
594
+ *
595
+ * @example
596
+ * const { price, source } = await awarizon.price.get('ETH')
597
+ */
598
+ async get(symbol) {
599
+ const sym = symbol.toUpperCase();
600
+ const chainlink = await fetchChainlink(this.publicClient, this.chainId, sym);
601
+ if (chainlink && !chainlink.stale) return chainlink;
602
+ if (COINGECKO_IDS[sym]) {
603
+ try {
604
+ const cgPrices = await fetchCoinGecko([sym]);
605
+ const price = cgPrices[sym];
606
+ if (price !== void 0) {
607
+ return { symbol: sym, price, source: "coingecko" };
608
+ }
609
+ } catch {
610
+ if (chainlink) return chainlink;
611
+ }
612
+ }
613
+ if (chainlink) return chainlink;
614
+ throw new Error(
615
+ `[awarizon/price] No price available for "${sym}". No Chainlink feed on chain ${this.chainId} and CoinGecko ID not registered. Supported symbols: ETH, BTC, BNB, MATIC, AVAX, LINK, UNI, AAVE, USDC, USDT, DAI, and more.`
616
+ );
617
+ }
618
+ /**
619
+ * Get USD prices for multiple tokens in one call.
620
+ * Chainlink feeds are read in parallel; CoinGecko batch-fetches all remaining
621
+ * symbols in a single HTTP request — efficient even for large lists.
622
+ *
623
+ * @param symbols - Array of token symbols: ['ETH', 'BTC', 'USDC']
624
+ *
625
+ * @example
626
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
627
+ * console.log(prices.ETH.price) // 3421.57
628
+ * console.log(prices.ARB.source) // 'coingecko' (no feed on most chains)
629
+ */
630
+ async getMany(symbols) {
631
+ const syms = symbols.map((s) => s.toUpperCase());
632
+ const chainlinkResults = await Promise.all(
633
+ syms.map((sym) => fetchChainlink(this.publicClient, this.chainId, sym))
634
+ );
635
+ const out = {};
636
+ const needsCG = [];
637
+ for (let i = 0; i < syms.length; i++) {
638
+ const sym = syms[i];
639
+ const cl = chainlinkResults[i];
640
+ if (cl && !cl.stale) {
641
+ out[sym] = cl;
642
+ } else {
643
+ needsCG.push(sym);
644
+ }
645
+ }
646
+ if (needsCG.length > 0) {
647
+ try {
648
+ const cgPrices = await fetchCoinGecko(needsCG);
649
+ for (const sym of needsCG) {
650
+ const price = cgPrices[sym];
651
+ if (price !== void 0) {
652
+ out[sym] = { symbol: sym, price, source: "coingecko" };
653
+ } else {
654
+ const cl = chainlinkResults[syms.indexOf(sym)];
655
+ if (cl) out[sym] = cl;
656
+ }
657
+ }
658
+ } catch {
659
+ for (const sym of needsCG) {
660
+ const cl = chainlinkResults[syms.indexOf(sym)];
661
+ if (cl) out[sym] = cl;
662
+ }
663
+ }
664
+ }
665
+ return out;
666
+ }
667
+ /**
668
+ * Check whether a Chainlink feed exists for the given symbol on the current chain.
669
+ *
670
+ * @example
671
+ * awarizon.price.hasFeed('ETH') // true on mainnet, base, polygon, etc.
672
+ * awarizon.price.hasFeed('ARB') // true on Arbitrum, false elsewhere
673
+ */
674
+ hasFeed(symbol) {
675
+ return !!CHAINLINK_FEEDS[this.chainId]?.[symbol.toUpperCase()];
676
+ }
677
+ /**
678
+ * Return all symbols that have a Chainlink feed on the current chain.
679
+ *
680
+ * @example
681
+ * awarizon.price.supportedSymbols()
682
+ * // → ['ETH', 'BTC', 'LINK', 'USDC', 'USDT', 'DAI'] on Base
683
+ */
684
+ supportedSymbols() {
685
+ return Object.keys(CHAINLINK_FEEDS[this.chainId] ?? {});
686
+ }
687
+ };
364
688
  var ERC20_ABI = viem.erc20Abi;
365
689
  var ERC721_ABI = [
366
690
  { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] },
@@ -481,12 +805,13 @@ var AwarizonWeb3 = class {
481
805
  this.chain = resolveChain(config.chain);
482
806
  this.publicClient = viem.createPublicClient({
483
807
  chain: this.chain,
484
- transport: viem.http(config.rpcUrl)
808
+ transport: getChainTransport(this.chain, config.rpcUrl)
485
809
  });
486
810
  this._engine = new walletEngine.WalletEngine({
487
811
  chain: this.chain,
488
812
  publicClient: this.publicClient,
489
- rpcUrl: config.rpcUrl
813
+ rpcUrl: config.rpcUrl,
814
+ getTransport: (chain) => getChainTransport(chain, config.rpcUrl)
490
815
  });
491
816
  this._txEngine = new txEngine.TransactionEngine(
492
817
  this.publicClient,
@@ -498,6 +823,7 @@ var AwarizonWeb3 = class {
498
823
  this._engine,
499
824
  () => this._telemetry.ensureValidated()
500
825
  );
826
+ this.price = new PriceEngine(this.publicClient, this.chain.id);
501
827
  if (config.signer) {
502
828
  this._engine.connectExternal(config.signer);
503
829
  }
@@ -1054,16 +1380,20 @@ Object.defineProperty(exports, "parseABI", {
1054
1380
  });
1055
1381
  exports.ApiKeyRequiredError = ApiKeyRequiredError;
1056
1382
  exports.AwarizonWeb3 = AwarizonWeb3;
1383
+ exports.CHAINLINK_FEEDS = CHAINLINK_FEEDS;
1057
1384
  exports.CHAINS = CHAINS;
1385
+ exports.COINGECKO_IDS = COINGECKO_IDS;
1058
1386
  exports.ContractNotLoadedError = ContractNotLoadedError;
1059
1387
  exports.ERC1155_ABI = ERC1155_ABI;
1060
1388
  exports.ERC20_ABI = ERC20_ABI;
1061
1389
  exports.ERC721_ABI = ERC721_ABI;
1062
1390
  exports.InvalidApiKeyError = InvalidApiKeyError;
1063
1391
  exports.NetworkMismatchError = NetworkMismatchError;
1392
+ exports.PriceEngine = PriceEngine;
1064
1393
  exports.ProviderError = ProviderError;
1065
1394
  exports.TelemetryClient = TelemetryClient;
1066
1395
  exports.UnsupportedChainError = UnsupportedChainError;
1396
+ exports.getChainTransport = getChainTransport;
1067
1397
  exports.getSupportedChainIds = getSupportedChainIds;
1068
1398
  exports.resolveChain = resolveChain;
1069
1399
  //# sourceMappingURL=index.js.map