@berachain/berajs 0.2.1 → 0.2.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.
@@ -1,4 +1,4 @@
1
- export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, t as ClaimedIncentives, u as ClaimedIncentivesLocalState, C as CustomProposal, n as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, i as IContractWriteFn, r as IncentiveReward, s as IncentiveRewardChunksWithValidatorData, m as PROPOSAL_GENRE, j as Proposal, p as ProposalAction, l as ProposalVotes, P as ProtocolMetadata, o as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, q as VerifiedAbi, V as Vote, k as Voter } from '../global.d-CN6l2b9E.cjs';
1
+ export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, t as ClaimedIncentives, u as ClaimedIncentivesLocalState, C as CustomProposal, n as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, i as IContractWriteFn, r as IncentiveReward, s as IncentiveRewardChunksWithValidatorData, m as PROPOSAL_GENRE, j as Proposal, p as ProposalAction, l as ProposalVotes, P as ProtocolMetadata, o as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, q as VerifiedAbi, V as Vote, k as Voter } from '../global.d-DLRtrPG5.cjs';
2
2
  export { A as AllowanceQueryItem, j as AllowanceToken, B as BalanceToken, z as BexStatus, w as Calldata, H as HoneySwapActions, I as IAggregatorArgs, D as IAggregatorQuote, g as IRawAggregatorQuote, v as IUserPosition, M as MinimalERC20, h as PythPriceFeedMap, S as SwapRequest, b as Token, i as TokenCurrentPriceMap, x as TokenPriceInfo, t as TokenWithAmount, a as TokenWithMetadata, y as TokenWithPrice } from '../HoneyConfigProvider-Ca3ouozs.cjs';
3
3
  import { BundleData, EnsoClient } from '@ensofinance/sdk';
4
4
  import { TransactionRequest, Address, Hex, PublicClient } from 'viem';
@@ -1,4 +1,4 @@
1
- export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, t as ClaimedIncentives, u as ClaimedIncentivesLocalState, C as CustomProposal, n as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, i as IContractWriteFn, r as IncentiveReward, s as IncentiveRewardChunksWithValidatorData, m as PROPOSAL_GENRE, j as Proposal, p as ProposalAction, l as ProposalVotes, P as ProtocolMetadata, o as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, q as VerifiedAbi, V as Vote, k as Voter } from '../global.d-wYu8G8IQ.js';
1
+ export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, t as ClaimedIncentives, u as ClaimedIncentivesLocalState, C as CustomProposal, n as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, i as IContractWriteFn, r as IncentiveReward, s as IncentiveRewardChunksWithValidatorData, m as PROPOSAL_GENRE, j as Proposal, p as ProposalAction, l as ProposalVotes, P as ProtocolMetadata, o as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, q as VerifiedAbi, V as Vote, k as Voter } from '../global.d-X3cqpCEB.js';
2
2
  export { A as AllowanceQueryItem, j as AllowanceToken, B as BalanceToken, z as BexStatus, w as Calldata, H as HoneySwapActions, I as IAggregatorArgs, D as IAggregatorQuote, g as IRawAggregatorQuote, v as IUserPosition, M as MinimalERC20, h as PythPriceFeedMap, S as SwapRequest, b as Token, i as TokenCurrentPriceMap, x as TokenPriceInfo, t as TokenWithAmount, a as TokenWithMetadata, y as TokenWithPrice } from '../HoneyConfigProvider-CK6mOKFH.js';
3
3
  import { BundleData, EnsoClient } from '@ensofinance/sdk';
4
4
  import { TransactionRequest, Address, Hex, PublicClient } from 'viem';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berachain/berajs",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "sideEffects": false,
5
5
  "files": [
6
6
  "dist",
@@ -20,8 +20,7 @@
20
20
  "gray-matter": "4.0.3",
21
21
  "lodash": "4.17.23",
22
22
  "swr": "2.3.3",
23
- "@berachain/config": "0.1.0",
24
- "@berachain/utils": "0.1.0"
23
+ "@berachain/config": "0.1.0"
25
24
  },
26
25
  "devDependencies": {
27
26
  "@types/node-fetch": "2.6.12",
@@ -32,6 +31,7 @@
32
31
  "typescript": "5.5.4",
33
32
  "viem": "2.45.0",
34
33
  "vitest": "3.2.4",
34
+ "@berachain/utils": "0.1.0",
35
35
  "@berachain/wagmi": "0.3.0"
36
36
  },
37
37
  "exports": {
@@ -56,13 +56,13 @@
56
56
  "@berachain/wagmi": "0.3.0"
57
57
  },
58
58
  "scripts": {
59
- "build": "NODE_OPTIONS='--max-old-space-size=8192' tsup",
59
+ "build": "tsup",
60
60
  "prebuild": "pnpm contracts:update",
61
61
  "test": "vitest",
62
62
  "clean": "git clean -xdf dist .turbo node_modules",
63
- "check-types": "NODE_OPTIONS='--max-old-space-size=8192' tsup --dtsOnly",
63
+ "check-types": "tsup --dtsOnly",
64
64
  "precheck-types": "pnpm prebuild",
65
- "dev": "NODE_OPTIONS='--max-old-space-size=8192' tsup --watch",
65
+ "dev": "tsup --watch",
66
66
  "lint": "biome lint",
67
67
  "lint:fix": "pnpm lint --fix",
68
68
  "errors:update": "node .scripts/updateUnkownSignatures.js && biome format src/abi/utils --write",
@@ -1,117 +1,194 @@
1
+ import { useMemo } from "react";
1
2
  import useSWR from "swr";
2
3
 
3
- import {
4
- useBeraWallet,
5
- useConfig,
6
- usePublicClient,
7
- } from "@berachain/wagmi/hooks";
4
+ import { useBeraWallet, usePublicClient } from "@berachain/wagmi/hooks";
8
5
  import BigNumber from "@berachain/utils/pkg/bignumber.js";
9
6
 
10
7
  import { getEarnedStakedBeraVault } from "~/actions/pol/getEarnedStakedBeraVault";
11
8
  import { getRewardTokenToBeraRate } from "~/actions/pol/getRewardTokenToBeraRate";
12
9
  import { getStakedBeraAPR } from "~/actions/pol/getStakedBeraAPR";
13
- import { getTokenCurrentPrices } from "~/actions/prices/getTokenCurrentPrices";
14
- import { getWalletBalances } from "~/actions/tokens/getWalletBalances";
15
10
  import { useBeraFlag } from "~/contexts/BeraFlags/BeraFlags";
16
11
  import { POLLING } from "~/enum/polling";
17
- import { assertDefined, assertPublicClient } from "~/errors/assert";
12
+ import { assertPublicClient } from "~/errors/assert";
13
+ import { usePollWalletBalances } from "~/hooks/tokens/usePollWalletBalances";
14
+ import { useTokenPrices } from "~/hooks/tokens/useTokenPrices";
18
15
  import type { StakedBeraAsset } from "~/types/pol";
19
16
  import type { StakingConfig } from "~/types/staking";
20
17
 
18
+ /**
19
+ * Fetches staked asset data in two phases for progressive loading:
20
+ *
21
+ * 1. APR — independent fetch, resolves quickly, shared by both phases.
22
+ * 2. Balances (fast path) — wallet balances (via usePollWalletBalances),
23
+ * token prices (via useTokenPrices), and exchange rates.
24
+ * Provides staked amounts and USD values immediately (earnings are 0).
25
+ * 3. Positions (slow path) — adds earnings data from the vault.
26
+ * Provides the full picture with earned amounts and USD values.
27
+ *
28
+ * Consumers can show `balances` right away and swap in `data` once positions resolve.
29
+ */
21
30
  export const useStakedData = (stakingConfigs: StakingConfig[]) => {
22
31
  const window = useBeraFlag("swberaAprWindow");
23
32
 
24
- const wagmiConfig = useConfig();
25
33
  const publicClient = usePublicClient();
26
34
  const { address: account } = useBeraWallet();
27
- const QUERY_KEY =
28
- account && wagmiConfig && stakingConfigs
29
- ? (["useStakedData", account, stakingConfigs, window] as const)
35
+
36
+ const receiptTokens = useMemo(
37
+ () => stakingConfigs.map((config) => config.receiptToken),
38
+ [stakingConfigs],
39
+ );
40
+ const inputTokens = useMemo(
41
+ () => stakingConfigs.map((config) => config.inputTokens[0]),
42
+ [stakingConfigs],
43
+ );
44
+
45
+ // APR — only updates every ~12 hours on BE
46
+ const aprKey = window ? (["useStakedData:apr", window] as const) : null;
47
+ const { data: apr } = useSWR(
48
+ aprKey,
49
+ async ([, window]) => getStakedBeraAPR({ window }),
50
+ { refreshInterval: POLLING.NORMAL },
51
+ );
52
+
53
+ const { data: walletBalances, isLoading: isLoadingBalances } =
54
+ usePollWalletBalances({ tokens: receiptTokens });
55
+
56
+ // NOT BERA PRICE, INPUT TOKEN PRICE
57
+ const { getTokenPrice } = useTokenPrices({ tokens: inputTokens });
58
+
59
+ // exchange rates from receipt token → input token (on-chain reads)
60
+ const exchangeRatesKey =
61
+ publicClient && receiptTokens.length > 0
62
+ ? (["useStakedData:exchangeRates", receiptTokens] as const)
63
+ : null;
64
+
65
+ const { data: exchangeRates } = useSWR(
66
+ exchangeRatesKey,
67
+ async ([, receiptTokens]) => {
68
+ assertPublicClient(publicClient);
69
+ return Promise.all(
70
+ receiptTokens.map((token) =>
71
+ getRewardTokenToBeraRate({
72
+ address: token.address,
73
+ publicClient,
74
+ }),
75
+ ),
76
+ );
77
+ },
78
+ { refreshInterval: POLLING.NORMAL },
79
+ );
80
+
81
+ // balances (fast path) — derived from hooks above, no extra requests
82
+ const balances = useMemo<StakedBeraAsset[] | undefined>(() => {
83
+ if (!walletBalances || !exchangeRates) return undefined;
84
+
85
+ return stakingConfigs.map((config, i): StakedBeraAsset => {
86
+ const inputToken = config.inputTokens[0];
87
+ const stakedBalance =
88
+ walletBalances.find((b) => b.address === config.receiptToken.address)
89
+ ?.balance.raw ?? "0";
90
+ const exchangeRate = exchangeRates[i] ?? 0;
91
+ const inputTokenPrice = getTokenPrice(inputToken) ?? 0;
92
+
93
+ const total = new BigNumber(stakedBalance).multipliedBy(exchangeRate);
94
+ const stakedAmount = total.dividedBy(10 ** inputToken.decimals);
95
+ const stakedAmountUsd = stakedAmount.multipliedBy(inputTokenPrice);
96
+
97
+ return {
98
+ token: inputToken,
99
+ apr: apr ?? 0,
100
+ stakedAmount: stakedAmount.toNumber(),
101
+ stakedAmountUsd: stakedAmountUsd.toNumber(),
102
+ earnedAmount: 0,
103
+ earnedAmountUsd: 0,
104
+ isLoadingEarnings: true,
105
+ };
106
+ });
107
+ }, [walletBalances, exchangeRates, stakingConfigs, apr, getTokenPrice]);
108
+
109
+ // positions (slow path) — fetch earnings and exchange rates from the vault
110
+ const positionsKey =
111
+ account && publicClient && stakingConfigs.length > 0
112
+ ? (["useStakedData:positions", account, stakingConfigs] as const)
30
113
  : null;
31
- return useSWR<StakedBeraAsset[] | undefined, any, typeof QUERY_KEY>(
32
- QUERY_KEY,
33
- async ([, account, stakingConfigs, window]) => {
34
- assertDefined(wagmiConfig, "wagmiConfig");
114
+
115
+ const {
116
+ data: positionsRaw,
117
+ isLoading: isLoadingPositions,
118
+ isValidating: isValidatingPositions,
119
+ } = useSWR(
120
+ positionsKey,
121
+ async ([, account, stakingConfigs]) => {
35
122
  assertPublicClient(publicClient);
36
- // get the apr for staking
37
- const apr = await getStakedBeraAPR({ window });
38
- // pull out the receipt tokens from the staking configs
39
- const receiptTokens = stakingConfigs.map((config) => config.receiptToken);
40
- // get the staked balances for the receipt tokens
41
- const stakedBalancesData = await getWalletBalances({
42
- account,
43
- tokenList: receiptTokens,
44
- wagmiConfig,
45
- });
46
- const data: StakedBeraAsset[] = await Promise.all(
47
- stakingConfigs.map(async (stakingConfig): Promise<StakedBeraAsset> => {
48
- // get the staking token & input/receipt token
123
+
124
+ return Promise.all(
125
+ stakingConfigs.map(async (stakingConfig) => {
49
126
  const stakingToken = stakingConfig.receiptToken;
50
- const inputToken = stakingConfig.inputTokens[0];
51
-
52
- const [earnings, inputTokenPriceData, exchangeRateNowRaw] =
53
- await Promise.all([
54
- // get the earned input token for the staking token
55
- getEarnedStakedBeraVault({
56
- address: stakingToken.address,
57
- account,
58
- }),
59
- // NOT BERA PRICE, INPUT TOKEN PRICE
60
- getTokenCurrentPrices({ addressIn: [inputToken.address] }),
61
- // use getRewardTokenToBeraRate to get the exchange rate
62
- getRewardTokenToBeraRate({
63
- address: stakingToken.address,
64
- publicClient,
65
- }),
66
- ]);
67
-
68
- // input token price
69
- const inputTokenPrice =
70
- inputTokenPriceData[inputToken.address]?.price ?? 0;
71
- // staked asset balance
72
- const stakedBalance =
73
- stakedBalancesData?.find((b) => b.address === stakingToken.address)
74
- ?.balance.raw ?? "0";
75
-
76
- const exchangeRateNow = exchangeRateNowRaw ?? 0;
77
-
78
- // unrealised gains is the users earnings
79
- const unrealisedGains = new BigNumber(earnings.earningsTotal).minus(
80
- earnings.earningsRealized,
81
- );
82
-
83
- const total = new BigNumber(stakedBalance).multipliedBy(
84
- exchangeRateNow,
85
- );
86
- // desposited is the users deposited amount
87
- const desposited = total.minus(unrealisedGains);
88
-
89
- // in terms of bera
90
- const stakedAmount = desposited.dividedBy(10 ** inputToken.decimals);
91
- const earnedAmount = unrealisedGains.dividedBy(
92
- 10 ** inputToken.decimals,
93
- );
94
-
95
- // in terms of usd
96
- const stakedAmountUsd = stakedAmount.multipliedBy(inputTokenPrice);
97
- const earnedAmountUsd = earnedAmount.multipliedBy(inputTokenPrice);
98
-
99
- const data: StakedBeraAsset = {
100
- token: inputToken,
101
- apr: apr ?? 0,
102
- stakedAmount: stakedAmount.toNumber(),
103
- earnedAmount: earnedAmount.toNumber(),
104
- stakedAmountUsd: stakedAmountUsd.toNumber(),
105
- earnedAmountUsd: earnedAmountUsd.toNumber(),
106
- };
107
-
108
- return data;
127
+
128
+ const [earnings, exchangeRate] = await Promise.all([
129
+ getEarnedStakedBeraVault({
130
+ address: stakingToken.address,
131
+ account,
132
+ }),
133
+ getRewardTokenToBeraRate({
134
+ address: stakingToken.address,
135
+ publicClient,
136
+ }),
137
+ ]);
138
+
139
+ return { earnings, exchangeRate };
109
140
  }),
110
141
  );
111
- return data;
112
- },
113
- {
114
- refreshInterval: POLLING.FAST,
115
142
  },
143
+ { refreshInterval: POLLING.FAST },
116
144
  );
145
+
146
+ // derive full StakedBeraAsset[] from raw positions + shared hooks
147
+ const data = useMemo<StakedBeraAsset[] | undefined>(() => {
148
+ if (!positionsRaw || !walletBalances) return undefined;
149
+
150
+ return stakingConfigs.map((config, i): StakedBeraAsset => {
151
+ const inputToken = config.inputTokens[0];
152
+ const stakingToken = config.receiptToken;
153
+ const { earnings, exchangeRate: exchangeRateRaw } = positionsRaw[i];
154
+
155
+ const inputTokenPrice = getTokenPrice(inputToken) ?? 0;
156
+ const stakedBalance =
157
+ walletBalances.find((b) => b.address === stakingToken.address)?.balance
158
+ .raw ?? "0";
159
+ const exchangeRate = exchangeRateRaw ?? 0;
160
+
161
+ const unrealisedGains = new BigNumber(earnings.earningsTotal).minus(
162
+ earnings.earningsRealized,
163
+ );
164
+ const total = new BigNumber(stakedBalance).multipliedBy(exchangeRate);
165
+ const deposited = total.minus(unrealisedGains);
166
+
167
+ const stakedAmount = deposited.dividedBy(10 ** inputToken.decimals);
168
+ const earnedAmount = unrealisedGains.dividedBy(10 ** inputToken.decimals);
169
+ const stakedAmountUsd = stakedAmount.multipliedBy(inputTokenPrice);
170
+ const earnedAmountUsd = earnedAmount.multipliedBy(inputTokenPrice);
171
+
172
+ return {
173
+ token: inputToken,
174
+ apr: apr ?? 0,
175
+ stakedAmount: stakedAmount.toNumber(),
176
+ earnedAmount: earnedAmount.toNumber(),
177
+ stakedAmountUsd: stakedAmountUsd.toNumber(),
178
+ earnedAmountUsd: earnedAmountUsd.toNumber(),
179
+ };
180
+ });
181
+ }, [positionsRaw, walletBalances, stakingConfigs, apr, getTokenPrice]);
182
+
183
+ return {
184
+ /** Fast path: staked amounts + USD values (no earnings) */
185
+ balances,
186
+ /** Slow path: full enriched positions with earnings */
187
+ data,
188
+ /** True only when both balances and positions are still loading */
189
+ isLoading: isLoadingBalances && isLoadingPositions,
190
+ isLoadingBalances,
191
+ isLoadingPositions,
192
+ isValidatingPositions,
193
+ };
117
194
  };
@@ -60,4 +60,5 @@ export type StakedBeraAsset = {
60
60
  stakedAmountUsd: number;
61
61
  earnedAmount: number;
62
62
  earnedAmountUsd: number;
63
+ isLoadingEarnings?: boolean;
63
64
  };