@awarizon/web3 1.3.1 → 1.3.3

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { erc20Abi, createPublicClient, http } from 'viem';
1
+ import { erc20Abi, http, fallback, createPublicClient } from 'viem';
2
2
  import { WalletEngine } from '@awarizon/wallet-engine';
3
3
  export { ChainMismatchError, ChainSwitchError, InvalidMnemonicError, InvalidPrivateKeyError, WalletEngine, WalletNotConnectedError } from '@awarizon/wallet-engine';
4
4
  import { TransactionEngine } from '@awarizon/tx-engine';
@@ -83,6 +83,27 @@ function getSupportedChainIds() {
83
83
  return true;
84
84
  }).map((c) => c.id);
85
85
  }
86
+ var FALLBACK_RPCS = {
87
+ 5e3: "https://mantle-mainnet.public.blastapi.io",
88
+ // mantle
89
+ 42220: "https://celo.drpc.org",
90
+ // celo
91
+ 100: "https://gnosis.drpc.org",
92
+ // gnosis
93
+ 250: "https://rpc.fantom.network",
94
+ // fantom
95
+ 1284: "https://moonbeam.drpc.org"
96
+ // moonbeam
97
+ };
98
+ function getChainTransport(chain, rpcUrlOverride) {
99
+ if (rpcUrlOverride) return http(rpcUrlOverride);
100
+ const fallbackUrl = FALLBACK_RPCS[chain.id];
101
+ if (fallbackUrl) {
102
+ const primaryUrl = chain.rpcUrls.default.http[0];
103
+ return fallback([http(primaryUrl), http(fallbackUrl)]);
104
+ }
105
+ return http();
106
+ }
86
107
  function trackEvent(telemetry, type, chain, functionName, success, start) {
87
108
  telemetry?.track({
88
109
  type,
@@ -362,6 +383,309 @@ var TelemetryClient = class {
362
383
  );
363
384
  }
364
385
  };
386
+
387
+ // src/price/feeds.ts
388
+ var AGGREGATOR_ABI = [
389
+ {
390
+ inputs: [],
391
+ name: "latestRoundData",
392
+ outputs: [
393
+ { name: "roundId", type: "uint80" },
394
+ { name: "answer", type: "int256" },
395
+ { name: "startedAt", type: "uint256" },
396
+ { name: "updatedAt", type: "uint256" },
397
+ { name: "answeredInRound", type: "uint80" }
398
+ ],
399
+ stateMutability: "view",
400
+ type: "function"
401
+ },
402
+ {
403
+ inputs: [],
404
+ name: "decimals",
405
+ outputs: [{ name: "", type: "uint8" }],
406
+ stateMutability: "view",
407
+ type: "function"
408
+ }
409
+ ];
410
+ var CHAINLINK_FEEDS = {
411
+ // Ethereum Mainnet
412
+ 1: {
413
+ ETH: "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419",
414
+ BTC: "0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88b",
415
+ BNB: "0x14e613AC84a31f709eadbEF3bf98585328207896",
416
+ MATIC: "0x7bAC85A8a13A4BcD8abb3eB7d6b4d632c895a5f6",
417
+ AVAX: "0xFF3EEb22B5E3dE6e705b44749C2559d704923FD7",
418
+ LINK: "0x2c1d072e956AFFC0D435Cb7AC308d97936742191",
419
+ UNI: "0x553303d460EE0afB37EdFf9bE42922D8FF63220e",
420
+ AAVE: "0x547a514d5e3769680Ce22B2361c10Ea13619e8a9",
421
+ MKR: "0xec1D1B3b0443256cc3860e24a46F108e699484Aa",
422
+ SNX: "0xDC3EA94CD0AC27d9A86C180091e7f78C683d3699",
423
+ CRV: "0xCd627aA160A6fA45Eb793D19Ef54f5062F20f33",
424
+ USDC: "0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6",
425
+ USDT: "0x3E7d1eAB13ad0104d2750B8863b489D65364e32D",
426
+ DAI: "0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9",
427
+ FRAX: "0xB9E1E3A9feFf48998E45Fa90847ed4D467E8BcfD"
428
+ },
429
+ // Base
430
+ 8453: {
431
+ ETH: "0x71041dddad3595F9CEd3dCCFBe3D1F4b0a16Bb70",
432
+ BTC: "0x64c911996D3c6aC71f9b455B1E8E7266BcFBF15F",
433
+ LINK: "0x56a43EB56Da12C0dc1D972ACb089c06a5dEF8e69",
434
+ USDC: "0x7e860098F58bBFC8648a4311b374B1D669a2bc9b"
435
+ },
436
+ // Polygon
437
+ 137: {
438
+ ETH: "0xF9680D99D6C9589e2a93a78A04A279e509205945",
439
+ BTC: "0xc907E116054Ad103354f2D350FD2514433D57F6f",
440
+ MATIC: "0xAB594600376Ec9fD91F8e885dADF0CE036862dE0",
441
+ LINK: "0xd9FFdb71EbE7496cC440152d43986Aae0AB76665",
442
+ AAVE: "0x72484B12719E23115761D5DA1646945632979bB6",
443
+ UNI: "0xdf0Fb4e4F928d2dCB76f438575fDD8682386e13C",
444
+ USDC: "0xfE4A8cc5b5B2366C1B58Bea3858e81843581b2F7",
445
+ USDT: "0x0A6513e40db6EB1b165753AD52E80663aea50545",
446
+ DAI: "0x4746DeC9e833A82EC7C2C1356372CcF2cfcD2F3D"
447
+ },
448
+ // Arbitrum One
449
+ 42161: {
450
+ ETH: "0x639Fe6ab55C921f74e7fac1ee960C0B6293ba612",
451
+ BTC: "0x6ce185860a4963106506C203335A2910413708e9",
452
+ LINK: "0x86E53CF1B873786aC9Cc60cde71fFd0035d6df2d",
453
+ ARB: "0xb2A824043730FE05F3DA2efaFa1CBbe83fa548D6",
454
+ USDC: "0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3",
455
+ USDT: "0x3f3f5dF88dC9F13eac63DF89EC16ef6e7E25DdE7"
456
+ },
457
+ // Optimism
458
+ 10: {
459
+ ETH: "0x13e3Ee699D1909E989722E753853AE30b17e08c5",
460
+ BTC: "0xD702DD976Fb76Fffc2D3963D037dfDae5b04E593",
461
+ LINK: "0xCc232dcFAAE6354cE191Bd574108c1aD03f86450",
462
+ OP: "0x0D276FC14719f9292D5C1eA2198673d1f4269246",
463
+ USDC: "0x16a9FA2FDa030272Ce99B29CF780dFA30361d35f",
464
+ USDT: "0xECef79E109e997bCA29c1c0897ec9d7b03647F5E"
465
+ },
466
+ // BNB Smart Chain
467
+ 56: {
468
+ BNB: "0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE",
469
+ ETH: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2",
470
+ BTC: "0x264990fbd0A4796A3E3d8E37C4d5F87a3aCa5Ebf",
471
+ LINK: "0xca236E327F629f9Fc2c30A4E95775EbF0B89fac8",
472
+ USDT: "0xB97Ad0E74fa7d920791E90258A6E2085088b4320",
473
+ DAI: "0x132d3C0B1D2cEa0BC552588063bdBb210FDeecfA"
474
+ },
475
+ // Avalanche C-Chain
476
+ 43114: {
477
+ ETH: "0x976B3D034E162d8bD72D6b9C989d545b839003b0",
478
+ BTC: "0x2779D32d5166BAaa2B2b658333bA7e6Ec0C65743",
479
+ AVAX: "0x0A77230d17318075983913bC2145DB16C7366156",
480
+ LINK: "0x49ccd9ca821EfEab2b98c60DC60F518E765eDe9a",
481
+ USDC: "0xF096872672F44d6EBA71527d2277B6f4B77Ea29A",
482
+ USDT: "0xEBE676ee90Fe1112671f19b6B7459bC678B67e8a"
483
+ }
484
+ };
485
+ var COINGECKO_IDS = {
486
+ // Native tokens
487
+ ETH: "ethereum",
488
+ BTC: "bitcoin",
489
+ BNB: "binancecoin",
490
+ MATIC: "matic-network",
491
+ POL: "matic-network",
492
+ AVAX: "avalanche-2",
493
+ FTM: "fantom",
494
+ GLMR: "moonbeam",
495
+ CELO: "celo",
496
+ XDAI: "xdai",
497
+ GNO: "gnosis",
498
+ MNT: "mantle",
499
+ // Major stables
500
+ USDC: "usd-coin",
501
+ USDT: "tether",
502
+ DAI: "dai",
503
+ BUSD: "binance-usd",
504
+ FRAX: "frax",
505
+ LUSD: "liquity-usd",
506
+ GUSD: "gemini-dollar",
507
+ TUSD: "true-usd",
508
+ USDD: "usdd",
509
+ FDUSD: "first-digital-usd",
510
+ // DeFi blue chips
511
+ LINK: "chainlink",
512
+ UNI: "uniswap",
513
+ AAVE: "aave",
514
+ MKR: "maker",
515
+ SNX: "havven",
516
+ CRV: "curve-dao-token",
517
+ LDO: "lido-dao",
518
+ RPL: "rocket-pool",
519
+ BAL: "balancer",
520
+ COMP: "compound-governance-token",
521
+ YFI: "yearn-finance",
522
+ SUSHI: "sushi",
523
+ // L2 tokens
524
+ ARB: "arbitrum",
525
+ OP: "optimism",
526
+ IMX: "immutable-x",
527
+ // Other popular alts
528
+ DOGE: "dogecoin",
529
+ SHIB: "shiba-inu",
530
+ PEPE: "pepe",
531
+ WLD: "worldcoin-wld",
532
+ APE: "apecoin",
533
+ GRT: "the-graph",
534
+ ENS: "ethereum-name-service",
535
+ BLUR: "blur"
536
+ };
537
+
538
+ // src/price/index.ts
539
+ var TWO_HOURS_SECS = 7200;
540
+ async function fetchChainlink(publicClient, chainId, symbol) {
541
+ const feeds = CHAINLINK_FEEDS[chainId];
542
+ if (!feeds) return null;
543
+ const address = feeds[symbol.toUpperCase()];
544
+ if (!address) return null;
545
+ try {
546
+ const [roundData, rawDecimals] = await Promise.all([
547
+ publicClient.readContract({
548
+ address,
549
+ abi: AGGREGATOR_ABI,
550
+ functionName: "latestRoundData"
551
+ }),
552
+ publicClient.readContract({
553
+ address,
554
+ abi: AGGREGATOR_ABI,
555
+ functionName: "decimals"
556
+ })
557
+ ]);
558
+ const answer = roundData[1];
559
+ const updatedAt = Number(roundData[3]);
560
+ const decimals = Number(rawDecimals);
561
+ if (answer <= 0n) return null;
562
+ const price = Number(answer) / 10 ** decimals;
563
+ const stale = Date.now() / 1e3 - updatedAt > TWO_HOURS_SECS;
564
+ return { symbol: symbol.toUpperCase(), price, source: "chainlink", updatedAt, stale };
565
+ } catch {
566
+ return null;
567
+ }
568
+ }
569
+ var CG_BASE = "https://api.coingecko.com/api/v3";
570
+ async function fetchCoinGecko(symbols) {
571
+ const ids = symbols.map((s) => COINGECKO_IDS[s.toUpperCase()]).filter(Boolean);
572
+ if (ids.length === 0) return {};
573
+ const url = `${CG_BASE}/simple/price?ids=${ids.join(",")}&vs_currencies=usd`;
574
+ const res = await fetch(url);
575
+ if (!res.ok) throw new Error(`[awarizon/price] CoinGecko returned ${res.status}`);
576
+ const data = await res.json();
577
+ const out = {};
578
+ for (const sym of symbols) {
579
+ const id = COINGECKO_IDS[sym.toUpperCase()];
580
+ const price = id ? data[id]?.usd : void 0;
581
+ if (price !== void 0) out[sym.toUpperCase()] = price;
582
+ }
583
+ return out;
584
+ }
585
+ var PriceEngine = class {
586
+ constructor(publicClient, chainId) {
587
+ this.publicClient = publicClient;
588
+ this.chainId = chainId;
589
+ }
590
+ /**
591
+ * Get the current USD price of a single token by symbol.
592
+ * Tries Chainlink first; falls back to CoinGecko on failure or missing feed.
593
+ *
594
+ * @param symbol - Token symbol: 'ETH', 'BTC', 'USDC', 'LINK', etc.
595
+ *
596
+ * @example
597
+ * const { price, source } = await awarizon.price.get('ETH')
598
+ */
599
+ async get(symbol) {
600
+ const sym = symbol.toUpperCase();
601
+ const chainlink = await fetchChainlink(this.publicClient, this.chainId, sym);
602
+ if (chainlink && !chainlink.stale) return chainlink;
603
+ if (COINGECKO_IDS[sym]) {
604
+ try {
605
+ const cgPrices = await fetchCoinGecko([sym]);
606
+ const price = cgPrices[sym];
607
+ if (price !== void 0) {
608
+ return { symbol: sym, price, source: "coingecko" };
609
+ }
610
+ } catch {
611
+ if (chainlink) return chainlink;
612
+ }
613
+ }
614
+ if (chainlink) return chainlink;
615
+ throw new Error(
616
+ `[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.`
617
+ );
618
+ }
619
+ /**
620
+ * Get USD prices for multiple tokens in one call.
621
+ * Chainlink feeds are read in parallel; CoinGecko batch-fetches all remaining
622
+ * symbols in a single HTTP request — efficient even for large lists.
623
+ *
624
+ * @param symbols - Array of token symbols: ['ETH', 'BTC', 'USDC']
625
+ *
626
+ * @example
627
+ * const prices = await awarizon.price.getMany(['ETH', 'BTC', 'USDC', 'ARB'])
628
+ * console.log(prices.ETH.price) // 3421.57
629
+ * console.log(prices.ARB.source) // 'coingecko' (no feed on most chains)
630
+ */
631
+ async getMany(symbols) {
632
+ const syms = symbols.map((s) => s.toUpperCase());
633
+ const chainlinkResults = await Promise.all(
634
+ syms.map((sym) => fetchChainlink(this.publicClient, this.chainId, sym))
635
+ );
636
+ const out = {};
637
+ const needsCG = [];
638
+ for (let i = 0; i < syms.length; i++) {
639
+ const sym = syms[i];
640
+ const cl = chainlinkResults[i];
641
+ if (cl && !cl.stale) {
642
+ out[sym] = cl;
643
+ } else {
644
+ needsCG.push(sym);
645
+ }
646
+ }
647
+ if (needsCG.length > 0) {
648
+ try {
649
+ const cgPrices = await fetchCoinGecko(needsCG);
650
+ for (const sym of needsCG) {
651
+ const price = cgPrices[sym];
652
+ if (price !== void 0) {
653
+ out[sym] = { symbol: sym, price, source: "coingecko" };
654
+ } else {
655
+ const cl = chainlinkResults[syms.indexOf(sym)];
656
+ if (cl) out[sym] = cl;
657
+ }
658
+ }
659
+ } catch {
660
+ for (const sym of needsCG) {
661
+ const cl = chainlinkResults[syms.indexOf(sym)];
662
+ if (cl) out[sym] = cl;
663
+ }
664
+ }
665
+ }
666
+ return out;
667
+ }
668
+ /**
669
+ * Check whether a Chainlink feed exists for the given symbol on the current chain.
670
+ *
671
+ * @example
672
+ * awarizon.price.hasFeed('ETH') // true on mainnet, base, polygon, etc.
673
+ * awarizon.price.hasFeed('ARB') // true on Arbitrum, false elsewhere
674
+ */
675
+ hasFeed(symbol) {
676
+ return !!CHAINLINK_FEEDS[this.chainId]?.[symbol.toUpperCase()];
677
+ }
678
+ /**
679
+ * Return all symbols that have a Chainlink feed on the current chain.
680
+ *
681
+ * @example
682
+ * awarizon.price.supportedSymbols()
683
+ * // → ['ETH', 'BTC', 'LINK', 'USDC', 'USDT', 'DAI'] on Base
684
+ */
685
+ supportedSymbols() {
686
+ return Object.keys(CHAINLINK_FEEDS[this.chainId] ?? {});
687
+ }
688
+ };
365
689
  var ERC20_ABI = erc20Abi;
366
690
  var ERC721_ABI = [
367
691
  { type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] },
@@ -402,9 +726,9 @@ var WalletProxy = class {
402
726
  await this.ensureReady();
403
727
  return this.engine.create();
404
728
  }
405
- async importMnemonic(mnemonic, accountIndex) {
729
+ async importMnemonic(mnemonic, addressIndex) {
406
730
  await this.ensureReady();
407
- return this.engine.importMnemonic(mnemonic, accountIndex);
731
+ return this.engine.importMnemonic(mnemonic, addressIndex);
408
732
  }
409
733
  async importPrivateKey(privateKey) {
410
734
  await this.ensureReady();
@@ -482,12 +806,13 @@ var AwarizonWeb3 = class {
482
806
  this.chain = resolveChain(config.chain);
483
807
  this.publicClient = createPublicClient({
484
808
  chain: this.chain,
485
- transport: http(config.rpcUrl)
809
+ transport: getChainTransport(this.chain, config.rpcUrl)
486
810
  });
487
811
  this._engine = new WalletEngine({
488
812
  chain: this.chain,
489
813
  publicClient: this.publicClient,
490
- rpcUrl: config.rpcUrl
814
+ rpcUrl: config.rpcUrl,
815
+ getTransport: (chain) => getChainTransport(chain, config.rpcUrl)
491
816
  });
492
817
  this._txEngine = new TransactionEngine(
493
818
  this.publicClient,
@@ -499,6 +824,7 @@ var AwarizonWeb3 = class {
499
824
  this._engine,
500
825
  () => this._telemetry.ensureValidated()
501
826
  );
827
+ this.price = new PriceEngine(this.publicClient, this.chain.id);
502
828
  if (config.signer) {
503
829
  this._engine.connectExternal(config.signer);
504
830
  }
@@ -977,6 +1303,6 @@ Currently registered: ${registered}`
977
1303
  }
978
1304
  };
979
1305
 
980
- export { ApiKeyRequiredError, AwarizonWeb3, CHAINS, ContractNotLoadedError, ERC1155_ABI, ERC20_ABI, ERC721_ABI, InvalidApiKeyError, NetworkMismatchError, ProviderError, TelemetryClient, UnsupportedChainError, getSupportedChainIds, resolveChain };
1306
+ export { ApiKeyRequiredError, AwarizonWeb3, CHAINLINK_FEEDS, CHAINS, COINGECKO_IDS, ContractNotLoadedError, ERC1155_ABI, ERC20_ABI, ERC721_ABI, InvalidApiKeyError, NetworkMismatchError, PriceEngine, ProviderError, TelemetryClient, UnsupportedChainError, getChainTransport, getSupportedChainIds, resolveChain };
981
1307
  //# sourceMappingURL=index.mjs.map
982
1308
  //# sourceMappingURL=index.mjs.map