@metamask-previews/assets-controller 2.0.0-preview-33dbba4f3 → 2.0.0-preview-a196307b6

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.
@@ -12,7 +12,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
12
12
  };
13
13
  var _StakedBalanceFetcher_providerGetter, _StakedBalanceFetcher_onStakedBalanceUpdate;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.StakedBalanceFetcher = exports.isStakingContractAssetId = exports.getSupportedStakingChainIds = exports.getStakingContractAddress = void 0;
15
+ exports.StakedBalanceFetcher = exports.STAKING_INTERFACE = exports.isStakingContractAssetId = exports.getSupportedStakingChainIds = exports.getStakingContractAddress = void 0;
16
16
  const abi_1 = require("@ethersproject/abi");
17
17
  const providers_1 = require("@ethersproject/providers");
18
18
  const polling_controller_1 = require("@metamask/polling-controller");
@@ -37,7 +37,7 @@ const STAKING_CONTRACT_ABI = [
37
37
  type: 'function',
38
38
  },
39
39
  ];
40
- const STAKING_INTERFACE = new abi_1.Interface(STAKING_CONTRACT_ABI);
40
+ exports.STAKING_INTERFACE = new abi_1.Interface(STAKING_CONTRACT_ABI);
41
41
  const STAKING_DECIMALS = 18;
42
42
  const DEFAULT_STAKED_BALANCE_INTERVAL = 180000; // 3 minutes
43
43
  class StakedBalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingControllerOnly)() {
@@ -98,24 +98,24 @@ class StakedBalanceFetcher extends (0, polling_controller_1.StaticIntervalPollin
98
98
  return { amount: '0' };
99
99
  }
100
100
  try {
101
- const sharesCalldata = STAKING_INTERFACE.encodeFunctionData('getShares', [
101
+ const sharesCalldata = exports.STAKING_INTERFACE.encodeFunctionData('getShares', [
102
102
  accountAddress,
103
103
  ]);
104
104
  const sharesResult = await provider.call({
105
105
  to: contractAddress,
106
106
  data: sharesCalldata,
107
107
  });
108
- const sharesRaw = STAKING_INTERFACE.decodeFunctionResult('getShares', sharesResult)[0];
108
+ const sharesRaw = exports.STAKING_INTERFACE.decodeFunctionResult('getShares', sharesResult)[0];
109
109
  const sharesBigNum = BigInt(sharesRaw.toString());
110
110
  if (sharesBigNum === 0n) {
111
111
  return { amount: '0' };
112
112
  }
113
- const assetsCalldata = STAKING_INTERFACE.encodeFunctionData('convertToAssets', [sharesBigNum]);
113
+ const assetsCalldata = exports.STAKING_INTERFACE.encodeFunctionData('convertToAssets', [sharesBigNum]);
114
114
  const assetsResult = await provider.call({
115
115
  to: contractAddress,
116
116
  data: assetsCalldata,
117
117
  });
118
- const assetsRaw = STAKING_INTERFACE.decodeFunctionResult('convertToAssets', assetsResult)[0];
118
+ const assetsRaw = exports.STAKING_INTERFACE.decodeFunctionResult('convertToAssets', assetsResult)[0];
119
119
  const assetsWei = BigInt(assetsRaw.toString());
120
120
  const amount = (0, utils_1.weiToHumanReadable)(assetsWei, STAKING_DECIMALS);
121
121
  return { amount };
@@ -1 +1 @@
1
- {"version":3,"file":"StakedBalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\n\nimport type { Address, AccountId, ChainId } from '../types';\nimport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n weiToHumanReadable,\n} from '../utils';\n\nexport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n};\n\nexport type StakedBalancePollingInput = {\n /** Chain ID (hex format, e.g. 0x1) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/** Human-readable staked balance (e.g. \"1.5\" for 1.5 ETH). */\nexport type StakedBalance = {\n amount: string;\n};\n\n/** Result reported via the update callback. */\nexport type StakedBalanceFetchResult = {\n /** Account ID (UUID). */\n accountId: AccountId;\n /** Hex chain ID. */\n chainId: ChainId;\n /** Human-readable staked balance. */\n balance: StakedBalance;\n};\n\n/**\n * Callback type for staked balance updates.\n */\nexport type OnStakedBalanceUpdateCallback = (\n result: StakedBalanceFetchResult,\n) => void;\n\n/** Staking contract ABI: getShares(account) and convertToAssets(shares). */\nconst STAKING_CONTRACT_ABI = [\n {\n inputs: [{ internalType: 'address', name: 'account', type: 'address' }],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }],\n name: 'convertToAssets',\n outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\nconst STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);\n\nconst STAKING_DECIMALS = 18;\n\nexport type StakedBalanceFetcherConfig = {\n /** Polling interval in ms (default: 180s) */\n pollingInterval?: number;\n /** Returns the network provider for the given chain. Required for fetchStakedBalance. */\n getNetworkProvider?: (chainId: ChainId) => Web3Provider | undefined;\n};\n\nconst DEFAULT_STAKED_BALANCE_INTERVAL = 180_000; // 3 minutes\n\nexport class StakedBalanceFetcher extends StaticIntervalPollingControllerOnly<StakedBalancePollingInput>() {\n readonly #providerGetter?: (chainId: ChainId) => Web3Provider | undefined;\n\n #onStakedBalanceUpdate: OnStakedBalanceUpdateCallback | undefined;\n\n constructor(config?: StakedBalanceFetcherConfig) {\n super();\n this.#providerGetter = config?.getNetworkProvider;\n\n this.setIntervalLength(\n config?.pollingInterval ?? DEFAULT_STAKED_BALANCE_INTERVAL,\n );\n }\n\n /**\n * Register a callback that is invoked after every successful poll with\n * the staked balance (including zero). Zero is reported so that merged\n * updates can clear prior non-zero state.\n *\n * @param callback - The callback to invoke.\n */\n setOnStakedBalanceUpdate(callback: OnStakedBalanceUpdateCallback): void {\n this.#onStakedBalanceUpdate = callback;\n }\n\n async _executePoll(input: StakedBalancePollingInput): Promise<void> {\n let result: StakedBalance;\n try {\n result = await this.fetchStakedBalance(input);\n } catch {\n // Do not push an update on provider/RPC failure; otherwise we would\n // overwrite existing non-zero staked balances with zero in state.\n return;\n }\n\n if (this.#onStakedBalanceUpdate) {\n this.#onStakedBalanceUpdate({\n accountId: input.accountId,\n chainId: input.chainId,\n balance: result,\n });\n }\n }\n\n /**\n * Fetches the staked balance for an account on a chain using the same\n * staking contract as AccountTrackerController (getShares then convertToAssets).\n * Returns a human-readable amount string (e.g. \"1.5\" for 1.5 ETH).\n * Throws when no provider is available or when the RPC/contract call fails, so\n * callers do not persist a false zero and overwrite existing balances.\n *\n * @param input - Chain, account ID, and address to query.\n * @returns Human-readable staked balance (amount string).\n * @throws When provider is missing or when getShares/convertToAssets fails.\n */\n async fetchStakedBalance(\n input: StakedBalancePollingInput,\n ): Promise<StakedBalance> {\n const { chainId, accountAddress } = input;\n const provider = this.#providerGetter?.(chainId);\n if (!provider) {\n throw new Error('StakedBalanceFetcher: no provider available for chain');\n }\n const contractAddress = getStakingContractAddress(chainId);\n\n if (!contractAddress) {\n return { amount: '0' };\n }\n\n try {\n const sharesCalldata = STAKING_INTERFACE.encodeFunctionData('getShares', [\n accountAddress,\n ]);\n const sharesResult = await provider.call({\n to: contractAddress,\n data: sharesCalldata,\n });\n const sharesRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'getShares',\n sharesResult,\n )[0];\n const sharesBigNum = BigInt(sharesRaw.toString());\n\n if (sharesBigNum === 0n) {\n return { amount: '0' };\n }\n\n const assetsCalldata = STAKING_INTERFACE.encodeFunctionData(\n 'convertToAssets',\n [sharesBigNum],\n );\n const assetsResult = await provider.call({\n to: contractAddress,\n data: assetsCalldata,\n });\n const assetsRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'convertToAssets',\n assetsResult,\n )[0];\n const assetsWei = BigInt(assetsRaw.toString());\n\n const amount = weiToHumanReadable(assetsWei, STAKING_DECIMALS);\n return { amount };\n } catch (error) {\n throw error instanceof Error\n ? error\n : new Error('StakedBalanceFetcher: failed to fetch staked balance');\n }\n }\n}\n"]}
1
+ {"version":3,"file":"StakedBalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\n\nimport type { Address, AccountId, ChainId } from '../types';\nimport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n weiToHumanReadable,\n} from '../utils';\n\nexport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n};\n\nexport type StakedBalancePollingInput = {\n /** Chain ID (hex format, e.g. 0x1) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/** Human-readable staked balance (e.g. \"1.5\" for 1.5 ETH). */\nexport type StakedBalance = {\n amount: string;\n};\n\n/** Result reported via the update callback. */\nexport type StakedBalanceFetchResult = {\n /** Account ID (UUID). */\n accountId: AccountId;\n /** Hex chain ID. */\n chainId: ChainId;\n /** Human-readable staked balance. */\n balance: StakedBalance;\n};\n\n/**\n * Callback type for staked balance updates.\n */\nexport type OnStakedBalanceUpdateCallback = (\n result: StakedBalanceFetchResult,\n) => void;\n\n/** Staking contract ABI: getShares(account) and convertToAssets(shares). */\nconst STAKING_CONTRACT_ABI = [\n {\n inputs: [{ internalType: 'address', name: 'account', type: 'address' }],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }],\n name: 'convertToAssets',\n outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\nexport const STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);\n\nconst STAKING_DECIMALS = 18;\n\nexport type StakedBalanceFetcherConfig = {\n /** Polling interval in ms (default: 180s) */\n pollingInterval?: number;\n /** Returns the network provider for the given chain. Required for fetchStakedBalance. */\n getNetworkProvider?: (chainId: ChainId) => Web3Provider | undefined;\n};\n\nconst DEFAULT_STAKED_BALANCE_INTERVAL = 180_000; // 3 minutes\n\nexport class StakedBalanceFetcher extends StaticIntervalPollingControllerOnly<StakedBalancePollingInput>() {\n readonly #providerGetter?: (chainId: ChainId) => Web3Provider | undefined;\n\n #onStakedBalanceUpdate: OnStakedBalanceUpdateCallback | undefined;\n\n constructor(config?: StakedBalanceFetcherConfig) {\n super();\n this.#providerGetter = config?.getNetworkProvider;\n\n this.setIntervalLength(\n config?.pollingInterval ?? DEFAULT_STAKED_BALANCE_INTERVAL,\n );\n }\n\n /**\n * Register a callback that is invoked after every successful poll with\n * the staked balance (including zero). Zero is reported so that merged\n * updates can clear prior non-zero state.\n *\n * @param callback - The callback to invoke.\n */\n setOnStakedBalanceUpdate(callback: OnStakedBalanceUpdateCallback): void {\n this.#onStakedBalanceUpdate = callback;\n }\n\n async _executePoll(input: StakedBalancePollingInput): Promise<void> {\n let result: StakedBalance;\n try {\n result = await this.fetchStakedBalance(input);\n } catch {\n // Do not push an update on provider/RPC failure; otherwise we would\n // overwrite existing non-zero staked balances with zero in state.\n return;\n }\n\n if (this.#onStakedBalanceUpdate) {\n this.#onStakedBalanceUpdate({\n accountId: input.accountId,\n chainId: input.chainId,\n balance: result,\n });\n }\n }\n\n /**\n * Fetches the staked balance for an account on a chain using the same\n * staking contract as AccountTrackerController (getShares then convertToAssets).\n * Returns a human-readable amount string (e.g. \"1.5\" for 1.5 ETH).\n * Throws when no provider is available or when the RPC/contract call fails, so\n * callers do not persist a false zero and overwrite existing balances.\n *\n * @param input - Chain, account ID, and address to query.\n * @returns Human-readable staked balance (amount string).\n * @throws When provider is missing or when getShares/convertToAssets fails.\n */\n async fetchStakedBalance(\n input: StakedBalancePollingInput,\n ): Promise<StakedBalance> {\n const { chainId, accountAddress } = input;\n const provider = this.#providerGetter?.(chainId);\n if (!provider) {\n throw new Error('StakedBalanceFetcher: no provider available for chain');\n }\n const contractAddress = getStakingContractAddress(chainId);\n\n if (!contractAddress) {\n return { amount: '0' };\n }\n\n try {\n const sharesCalldata = STAKING_INTERFACE.encodeFunctionData('getShares', [\n accountAddress,\n ]);\n const sharesResult = await provider.call({\n to: contractAddress,\n data: sharesCalldata,\n });\n const sharesRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'getShares',\n sharesResult,\n )[0];\n const sharesBigNum = BigInt(sharesRaw.toString());\n\n if (sharesBigNum === 0n) {\n return { amount: '0' };\n }\n\n const assetsCalldata = STAKING_INTERFACE.encodeFunctionData(\n 'convertToAssets',\n [sharesBigNum],\n );\n const assetsResult = await provider.call({\n to: contractAddress,\n data: assetsCalldata,\n });\n const assetsRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'convertToAssets',\n assetsResult,\n )[0];\n const assetsWei = BigInt(assetsRaw.toString());\n\n const amount = weiToHumanReadable(assetsWei, STAKING_DECIMALS);\n return { amount };\n } catch (error) {\n throw error instanceof Error\n ? error\n : new Error('StakedBalanceFetcher: failed to fetch staked balance');\n }\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import { Interface } from "@ethersproject/abi";
1
2
  import { Web3Provider } from "@ethersproject/providers";
2
3
  import type { Address, AccountId, ChainId } from "../types/index.cjs";
3
4
  import { getStakingContractAddress, getSupportedStakingChainIds, isStakingContractAssetId } from "../utils/index.cjs";
@@ -27,6 +28,7 @@ export type StakedBalanceFetchResult = {
27
28
  * Callback type for staked balance updates.
28
29
  */
29
30
  export type OnStakedBalanceUpdateCallback = (result: StakedBalanceFetchResult) => void;
31
+ export declare const STAKING_INTERFACE: Interface;
30
32
  export type StakedBalanceFetcherConfig = {
31
33
  /** Polling interval in ms (default: 180s) */
32
34
  pollingInterval?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"StakedBalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iCAAiC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,2BAAiB;AAC5D,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EAEzB,2BAAiB;AAElB,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,yBAAyB;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC1C,MAAM,EAAE,wBAAwB,KAC7B,IAAI,CAAC;AAwBV,MAAM,MAAM,0BAA0B,GAAG;IACvC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,SAAS,CAAC;CACrE,CAAC;;;;;6CAzDA,sCAAsC;;;;;;;;;;;;;AA6DxC,qBAAa,oBAAqB,SAAQ,yBAAgE;;gBAK5F,MAAM,CAAC,EAAE,0BAA0B;IAS/C;;;;;;OAMG;IACH,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B,GAAG,IAAI;IAIjE,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnE;;;;;;;;;;OAUG;IACG,kBAAkB,CACtB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,aAAa,CAAC;CAoD1B"}
1
+ {"version":3,"file":"StakedBalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAC/C,OAAO,EAAE,YAAY,EAAE,iCAAiC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,2BAAiB;AAC5D,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EAEzB,2BAAiB;AAElB,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,yBAAyB;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC1C,MAAM,EAAE,wBAAwB,KAC7B,IAAI,CAAC;AAoBV,eAAO,MAAM,iBAAiB,WAAsC,CAAC;AAIrE,MAAM,MAAM,0BAA0B,GAAG;IACvC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,SAAS,CAAC;CACrE,CAAC;;;;;6CAzDA,sCAAsC;;;;;;;;;;;;;AA6DxC,qBAAa,oBAAqB,SAAQ,yBAAgE;;gBAK5F,MAAM,CAAC,EAAE,0BAA0B;IAS/C;;;;;;OAMG;IACH,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B,GAAG,IAAI;IAIjE,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnE;;;;;;;;;;OAUG;IACG,kBAAkB,CACtB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,aAAa,CAAC;CAoD1B"}
@@ -1,3 +1,4 @@
1
+ import { Interface } from "@ethersproject/abi";
1
2
  import { Web3Provider } from "@ethersproject/providers";
2
3
  import type { Address, AccountId, ChainId } from "../types/index.mjs";
3
4
  import { getStakingContractAddress, getSupportedStakingChainIds, isStakingContractAssetId } from "../utils/index.mjs";
@@ -27,6 +28,7 @@ export type StakedBalanceFetchResult = {
27
28
  * Callback type for staked balance updates.
28
29
  */
29
30
  export type OnStakedBalanceUpdateCallback = (result: StakedBalanceFetchResult) => void;
31
+ export declare const STAKING_INTERFACE: Interface;
30
32
  export type StakedBalanceFetcherConfig = {
31
33
  /** Polling interval in ms (default: 180s) */
32
34
  pollingInterval?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"StakedBalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,iCAAiC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,2BAAiB;AAC5D,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EAEzB,2BAAiB;AAElB,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,yBAAyB;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC1C,MAAM,EAAE,wBAAwB,KAC7B,IAAI,CAAC;AAwBV,MAAM,MAAM,0BAA0B,GAAG;IACvC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,SAAS,CAAC;CACrE,CAAC;;;;;6CAzDA,sCAAsC;;;;;;;;;;;;;AA6DxC,qBAAa,oBAAqB,SAAQ,yBAAgE;;gBAK5F,MAAM,CAAC,EAAE,0BAA0B;IAS/C;;;;;;OAMG;IACH,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B,GAAG,IAAI;IAIjE,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnE;;;;;;;;;;OAUG;IACG,kBAAkB,CACtB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,aAAa,CAAC;CAoD1B"}
1
+ {"version":3,"file":"StakedBalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAC/C,OAAO,EAAE,YAAY,EAAE,iCAAiC;AAGxD,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,2BAAiB;AAC5D,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EAEzB,2BAAiB;AAElB,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,yBAAyB;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAC1C,MAAM,EAAE,wBAAwB,KAC7B,IAAI,CAAC;AAoBV,eAAO,MAAM,iBAAiB,WAAsC,CAAC;AAIrE,MAAM,MAAM,0BAA0B,GAAG;IACvC,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,SAAS,CAAC;CACrE,CAAC;;;;;6CAzDA,sCAAsC;;;;;;;;;;;;;AA6DxC,qBAAa,oBAAqB,SAAQ,yBAAgE;;gBAK5F,MAAM,CAAC,EAAE,0BAA0B;IAS/C;;;;;;OAMG;IACH,wBAAwB,CAAC,QAAQ,EAAE,6BAA6B,GAAG,IAAI;IAIjE,YAAY,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnE;;;;;;;;;;OAUG;IACG,kBAAkB,CACtB,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,aAAa,CAAC;CAoD1B"}
@@ -32,7 +32,7 @@ const STAKING_CONTRACT_ABI = [
32
32
  type: 'function',
33
33
  },
34
34
  ];
35
- const STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);
35
+ export const STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);
36
36
  const STAKING_DECIMALS = 18;
37
37
  const DEFAULT_STAKED_BALANCE_INTERVAL = 180000; // 3 minutes
38
38
  export class StakedBalanceFetcher extends StaticIntervalPollingControllerOnly() {
@@ -1 +1 @@
1
- {"version":3,"file":"StakedBalanceFetcher.mjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\n\nimport type { Address, AccountId, ChainId } from '../types';\nimport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n weiToHumanReadable,\n} from '../utils';\n\nexport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n};\n\nexport type StakedBalancePollingInput = {\n /** Chain ID (hex format, e.g. 0x1) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/** Human-readable staked balance (e.g. \"1.5\" for 1.5 ETH). */\nexport type StakedBalance = {\n amount: string;\n};\n\n/** Result reported via the update callback. */\nexport type StakedBalanceFetchResult = {\n /** Account ID (UUID). */\n accountId: AccountId;\n /** Hex chain ID. */\n chainId: ChainId;\n /** Human-readable staked balance. */\n balance: StakedBalance;\n};\n\n/**\n * Callback type for staked balance updates.\n */\nexport type OnStakedBalanceUpdateCallback = (\n result: StakedBalanceFetchResult,\n) => void;\n\n/** Staking contract ABI: getShares(account) and convertToAssets(shares). */\nconst STAKING_CONTRACT_ABI = [\n {\n inputs: [{ internalType: 'address', name: 'account', type: 'address' }],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }],\n name: 'convertToAssets',\n outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\nconst STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);\n\nconst STAKING_DECIMALS = 18;\n\nexport type StakedBalanceFetcherConfig = {\n /** Polling interval in ms (default: 180s) */\n pollingInterval?: number;\n /** Returns the network provider for the given chain. Required for fetchStakedBalance. */\n getNetworkProvider?: (chainId: ChainId) => Web3Provider | undefined;\n};\n\nconst DEFAULT_STAKED_BALANCE_INTERVAL = 180_000; // 3 minutes\n\nexport class StakedBalanceFetcher extends StaticIntervalPollingControllerOnly<StakedBalancePollingInput>() {\n readonly #providerGetter?: (chainId: ChainId) => Web3Provider | undefined;\n\n #onStakedBalanceUpdate: OnStakedBalanceUpdateCallback | undefined;\n\n constructor(config?: StakedBalanceFetcherConfig) {\n super();\n this.#providerGetter = config?.getNetworkProvider;\n\n this.setIntervalLength(\n config?.pollingInterval ?? DEFAULT_STAKED_BALANCE_INTERVAL,\n );\n }\n\n /**\n * Register a callback that is invoked after every successful poll with\n * the staked balance (including zero). Zero is reported so that merged\n * updates can clear prior non-zero state.\n *\n * @param callback - The callback to invoke.\n */\n setOnStakedBalanceUpdate(callback: OnStakedBalanceUpdateCallback): void {\n this.#onStakedBalanceUpdate = callback;\n }\n\n async _executePoll(input: StakedBalancePollingInput): Promise<void> {\n let result: StakedBalance;\n try {\n result = await this.fetchStakedBalance(input);\n } catch {\n // Do not push an update on provider/RPC failure; otherwise we would\n // overwrite existing non-zero staked balances with zero in state.\n return;\n }\n\n if (this.#onStakedBalanceUpdate) {\n this.#onStakedBalanceUpdate({\n accountId: input.accountId,\n chainId: input.chainId,\n balance: result,\n });\n }\n }\n\n /**\n * Fetches the staked balance for an account on a chain using the same\n * staking contract as AccountTrackerController (getShares then convertToAssets).\n * Returns a human-readable amount string (e.g. \"1.5\" for 1.5 ETH).\n * Throws when no provider is available or when the RPC/contract call fails, so\n * callers do not persist a false zero and overwrite existing balances.\n *\n * @param input - Chain, account ID, and address to query.\n * @returns Human-readable staked balance (amount string).\n * @throws When provider is missing or when getShares/convertToAssets fails.\n */\n async fetchStakedBalance(\n input: StakedBalancePollingInput,\n ): Promise<StakedBalance> {\n const { chainId, accountAddress } = input;\n const provider = this.#providerGetter?.(chainId);\n if (!provider) {\n throw new Error('StakedBalanceFetcher: no provider available for chain');\n }\n const contractAddress = getStakingContractAddress(chainId);\n\n if (!contractAddress) {\n return { amount: '0' };\n }\n\n try {\n const sharesCalldata = STAKING_INTERFACE.encodeFunctionData('getShares', [\n accountAddress,\n ]);\n const sharesResult = await provider.call({\n to: contractAddress,\n data: sharesCalldata,\n });\n const sharesRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'getShares',\n sharesResult,\n )[0];\n const sharesBigNum = BigInt(sharesRaw.toString());\n\n if (sharesBigNum === 0n) {\n return { amount: '0' };\n }\n\n const assetsCalldata = STAKING_INTERFACE.encodeFunctionData(\n 'convertToAssets',\n [sharesBigNum],\n );\n const assetsResult = await provider.call({\n to: contractAddress,\n data: assetsCalldata,\n });\n const assetsRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'convertToAssets',\n assetsResult,\n )[0];\n const assetsWei = BigInt(assetsRaw.toString());\n\n const amount = weiToHumanReadable(assetsWei, STAKING_DECIMALS);\n return { amount };\n } catch (error) {\n throw error instanceof Error\n ? error\n : new Error('StakedBalanceFetcher: failed to fetch staked balance');\n }\n }\n}\n"]}
1
+ {"version":3,"file":"StakedBalanceFetcher.mjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/StakedBalanceFetcher.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,2BAA2B;AAC/C,OAAO,EAAE,YAAY,EAAE,iCAAiC;AACxD,OAAO,EAAE,mCAAmC,EAAE,qCAAqC;AAGnF,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EACxB,kBAAkB,EACnB,2BAAiB;AAElB,OAAO,EACL,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,EACzB,CAAC;AAiCF,4EAA4E;AAC5E,MAAM,oBAAoB,GAAG;IAC3B;QACE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACvE,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACjE,eAAe,EAAE,MAAM;QACvB,IAAI,EAAE,UAAU;KACjB;IACD;QACE,MAAM,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACtE,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACvE,eAAe,EAAE,MAAM;QACvB,IAAI,EAAE,UAAU;KACjB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,SAAS,CAAC,oBAAoB,CAAC,CAAC;AAErE,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAS5B,MAAM,+BAA+B,GAAG,MAAO,CAAC,CAAC,YAAY;AAE7D,MAAM,OAAO,oBAAqB,SAAQ,mCAAmC,EAA6B;IAKxG,YAAY,MAAmC;QAC7C,KAAK,EAAE,CAAC;QALD,uDAAiE;QAE1E,8DAAkE;QAIhE,uBAAA,IAAI,wCAAmB,MAAM,EAAE,kBAAkB,MAAA,CAAC;QAElD,IAAI,CAAC,iBAAiB,CACpB,MAAM,EAAE,eAAe,IAAI,+BAA+B,CAC3D,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,wBAAwB,CAAC,QAAuC;QAC9D,uBAAA,IAAI,+CAA0B,QAAQ,MAAA,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAgC;QACjD,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,oEAAoE;YACpE,kEAAkE;YAClE,OAAO;QACT,CAAC;QAED,IAAI,uBAAA,IAAI,mDAAuB,EAAE,CAAC;YAChC,uBAAA,IAAI,mDAAuB,MAA3B,IAAI,EAAwB;gBAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,kBAAkB,CACtB,KAAgC;QAEhC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;QAC1C,MAAM,QAAQ,GAAG,uBAAA,IAAI,4CAAgB,EAAE,KAAtB,IAAI,EAAmB,OAAO,CAAC,CAAC;QACjD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,eAAe,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACzB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,WAAW,EAAE;gBACvE,cAAc;aACf,CAAC,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;gBACvC,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,cAAc;aACrB,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,iBAAiB,CAAC,oBAAoB,CACtD,WAAW,EACX,YAAY,CACb,CAAC,CAAC,CAAC,CAAC;YACL,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;YAElD,IAAI,YAAY,KAAK,EAAE,EAAE,CAAC;gBACxB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YACzB,CAAC;YAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,kBAAkB,CACzD,iBAAiB,EACjB,CAAC,YAAY,CAAC,CACf,CAAC;YACF,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC;gBACvC,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,cAAc;aACrB,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,iBAAiB,CAAC,oBAAoB,CACtD,iBAAiB,EACjB,YAAY,CACb,CAAC,CAAC,CAAC,CAAC;YACL,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;YAE/C,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;YAC/D,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,YAAY,KAAK;gBAC1B,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;CACF","sourcesContent":["import { Interface } from '@ethersproject/abi';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\n\nimport type { Address, AccountId, ChainId } from '../types';\nimport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n weiToHumanReadable,\n} from '../utils';\n\nexport {\n getStakingContractAddress,\n getSupportedStakingChainIds,\n isStakingContractAssetId,\n};\n\nexport type StakedBalancePollingInput = {\n /** Chain ID (hex format, e.g. 0x1) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/** Human-readable staked balance (e.g. \"1.5\" for 1.5 ETH). */\nexport type StakedBalance = {\n amount: string;\n};\n\n/** Result reported via the update callback. */\nexport type StakedBalanceFetchResult = {\n /** Account ID (UUID). */\n accountId: AccountId;\n /** Hex chain ID. */\n chainId: ChainId;\n /** Human-readable staked balance. */\n balance: StakedBalance;\n};\n\n/**\n * Callback type for staked balance updates.\n */\nexport type OnStakedBalanceUpdateCallback = (\n result: StakedBalanceFetchResult,\n) => void;\n\n/** Staking contract ABI: getShares(account) and convertToAssets(shares). */\nconst STAKING_CONTRACT_ABI = [\n {\n inputs: [{ internalType: 'address', name: 'account', type: 'address' }],\n name: 'getShares',\n outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n {\n inputs: [{ internalType: 'uint256', name: 'shares', type: 'uint256' }],\n name: 'convertToAssets',\n outputs: [{ internalType: 'uint256', name: 'assets', type: 'uint256' }],\n stateMutability: 'view',\n type: 'function',\n },\n];\n\nexport const STAKING_INTERFACE = new Interface(STAKING_CONTRACT_ABI);\n\nconst STAKING_DECIMALS = 18;\n\nexport type StakedBalanceFetcherConfig = {\n /** Polling interval in ms (default: 180s) */\n pollingInterval?: number;\n /** Returns the network provider for the given chain. Required for fetchStakedBalance. */\n getNetworkProvider?: (chainId: ChainId) => Web3Provider | undefined;\n};\n\nconst DEFAULT_STAKED_BALANCE_INTERVAL = 180_000; // 3 minutes\n\nexport class StakedBalanceFetcher extends StaticIntervalPollingControllerOnly<StakedBalancePollingInput>() {\n readonly #providerGetter?: (chainId: ChainId) => Web3Provider | undefined;\n\n #onStakedBalanceUpdate: OnStakedBalanceUpdateCallback | undefined;\n\n constructor(config?: StakedBalanceFetcherConfig) {\n super();\n this.#providerGetter = config?.getNetworkProvider;\n\n this.setIntervalLength(\n config?.pollingInterval ?? DEFAULT_STAKED_BALANCE_INTERVAL,\n );\n }\n\n /**\n * Register a callback that is invoked after every successful poll with\n * the staked balance (including zero). Zero is reported so that merged\n * updates can clear prior non-zero state.\n *\n * @param callback - The callback to invoke.\n */\n setOnStakedBalanceUpdate(callback: OnStakedBalanceUpdateCallback): void {\n this.#onStakedBalanceUpdate = callback;\n }\n\n async _executePoll(input: StakedBalancePollingInput): Promise<void> {\n let result: StakedBalance;\n try {\n result = await this.fetchStakedBalance(input);\n } catch {\n // Do not push an update on provider/RPC failure; otherwise we would\n // overwrite existing non-zero staked balances with zero in state.\n return;\n }\n\n if (this.#onStakedBalanceUpdate) {\n this.#onStakedBalanceUpdate({\n accountId: input.accountId,\n chainId: input.chainId,\n balance: result,\n });\n }\n }\n\n /**\n * Fetches the staked balance for an account on a chain using the same\n * staking contract as AccountTrackerController (getShares then convertToAssets).\n * Returns a human-readable amount string (e.g. \"1.5\" for 1.5 ETH).\n * Throws when no provider is available or when the RPC/contract call fails, so\n * callers do not persist a false zero and overwrite existing balances.\n *\n * @param input - Chain, account ID, and address to query.\n * @returns Human-readable staked balance (amount string).\n * @throws When provider is missing or when getShares/convertToAssets fails.\n */\n async fetchStakedBalance(\n input: StakedBalancePollingInput,\n ): Promise<StakedBalance> {\n const { chainId, accountAddress } = input;\n const provider = this.#providerGetter?.(chainId);\n if (!provider) {\n throw new Error('StakedBalanceFetcher: no provider available for chain');\n }\n const contractAddress = getStakingContractAddress(chainId);\n\n if (!contractAddress) {\n return { amount: '0' };\n }\n\n try {\n const sharesCalldata = STAKING_INTERFACE.encodeFunctionData('getShares', [\n accountAddress,\n ]);\n const sharesResult = await provider.call({\n to: contractAddress,\n data: sharesCalldata,\n });\n const sharesRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'getShares',\n sharesResult,\n )[0];\n const sharesBigNum = BigInt(sharesRaw.toString());\n\n if (sharesBigNum === 0n) {\n return { amount: '0' };\n }\n\n const assetsCalldata = STAKING_INTERFACE.encodeFunctionData(\n 'convertToAssets',\n [sharesBigNum],\n );\n const assetsResult = await provider.call({\n to: contractAddress,\n data: assetsCalldata,\n });\n const assetsRaw = STAKING_INTERFACE.decodeFunctionResult(\n 'convertToAssets',\n assetsResult,\n )[0];\n const assetsWei = BigInt(assetsRaw.toString());\n\n const amount = weiToHumanReadable(assetsWei, STAKING_DECIMALS);\n return { amount };\n } catch (error) {\n throw error instanceof Error\n ? error\n : new Error('StakedBalanceFetcher: failed to fetch staked balance');\n }\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/assets-controller",
3
- "version": "2.0.0-preview-33dbba4f3",
3
+ "version": "2.0.0-preview-a196307b6",
4
4
  "description": "Tracks assets balances/prices and handles token detection across all digital assets",
5
5
  "keywords": [
6
6
  "MetaMask",