@berachain/berajs 0.2.8-beta.6 → 0.2.8-beta.7

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.
Files changed (65) hide show
  1. package/dist/actions/exports.cjs +1 -1
  2. package/dist/actions/exports.cjs.map +1 -1
  3. package/dist/actions/exports.d.cts +95 -50
  4. package/dist/actions/exports.d.ts +95 -50
  5. package/dist/actions/exports.mjs +1 -1
  6. package/dist/actions/exports.mjs.map +1 -1
  7. package/dist/{chunk-G4CNETLS.mjs → chunk-6K252BGM.mjs} +2 -2
  8. package/dist/{chunk-I7M43BB4.cjs → chunk-D6L7LTA2.cjs} +2 -2
  9. package/dist/chunk-D6L7LTA2.cjs.map +1 -0
  10. package/dist/{chunk-T5FSQ3YE.mjs → chunk-JDZGYU5T.mjs} +2 -2
  11. package/dist/{chunk-T5FSQ3YE.mjs.map → chunk-JDZGYU5T.mjs.map} +1 -1
  12. package/dist/{chunk-7EAKCNQT.cjs → chunk-JLFBRMOF.cjs} +2 -2
  13. package/dist/{chunk-7EAKCNQT.cjs.map → chunk-JLFBRMOF.cjs.map} +1 -1
  14. package/dist/chunk-MASD43N5.mjs +4 -0
  15. package/dist/chunk-MASD43N5.mjs.map +1 -0
  16. package/dist/chunk-MGGPHKA2.cjs +4 -0
  17. package/dist/{chunk-WD4B3SXS.cjs.map → chunk-MGGPHKA2.cjs.map} +1 -1
  18. package/dist/{chunk-S5VOCVBR.mjs → chunk-UENDEN3M.mjs} +2 -2
  19. package/dist/{chunk-E32UP4GV.cjs → chunk-UFIM7WQ4.cjs} +2 -2
  20. package/dist/{chunk-E32UP4GV.cjs.map → chunk-UFIM7WQ4.cjs.map} +1 -1
  21. package/dist/contexts/exports.cjs +1 -1
  22. package/dist/contexts/exports.mjs +1 -1
  23. package/dist/enum/exports.cjs +1 -1
  24. package/dist/enum/exports.d.cts +1 -1
  25. package/dist/enum/exports.d.ts +1 -1
  26. package/dist/enum/exports.mjs +1 -1
  27. package/dist/{getValidatorQueuedOperatorAddress-DUZOmxLV.d.ts → getValidatorQueuedOperatorAddress-BcyxE9uw.d.ts} +2 -2
  28. package/dist/{getValidatorQueuedOperatorAddress-BQXkSFd9.d.cts → getValidatorQueuedOperatorAddress-Cql_D50j.d.cts} +2 -2
  29. package/dist/{global.d-SU9Epq0M.d.ts → global.d-5w_lvl2J.d.ts} +1 -1
  30. package/dist/{global.d-6aSWIkV_.d.cts → global.d-B7IeayVX.d.cts} +1 -1
  31. package/dist/hooks/exports.cjs +3 -3
  32. package/dist/hooks/exports.cjs.map +1 -1
  33. package/dist/hooks/exports.d.cts +4 -4
  34. package/dist/hooks/exports.d.ts +4 -4
  35. package/dist/hooks/exports.mjs +3 -3
  36. package/dist/hooks/exports.mjs.map +1 -1
  37. package/dist/{txnEnum-CCuQUFlh.d.cts → txnEnum-7_o92X3N.d.cts} +2 -0
  38. package/dist/{txnEnum-CCuQUFlh.d.ts → txnEnum-7_o92X3N.d.ts} +2 -0
  39. package/dist/types/exports.d.cts +2 -2
  40. package/dist/types/exports.d.ts +2 -2
  41. package/package.json +4 -4
  42. package/src/actions/clients/getApolloClient.ts +11 -4
  43. package/src/actions/dex/getOnChainPool.ts +1 -1
  44. package/src/actions/enso/getBendMultiplyBundle.ts +9 -2
  45. package/src/actions/enso/util.ts +6 -8
  46. package/src/actions/governance/checkProposalField.ts +108 -54
  47. package/src/actions/governance/computeActualStatus.ts +7 -3
  48. package/src/actions/governance/getAllProposals.ts +15 -8
  49. package/src/actions/governance/getBodyErrors.ts +13 -5
  50. package/src/actions/governance/getDecodedFunctionData.ts +27 -19
  51. package/src/actions/governance/getProposalDetails.ts +8 -4
  52. package/src/actions/governance/getProposalFromTx.ts +19 -10
  53. package/src/actions/governance/getProposalParams.ts +17 -17
  54. package/src/actions/governance/getProposalVotes.ts +7 -3
  55. package/src/actions/governance/getQuorum.ts +7 -7
  56. package/src/actions/governance/parseProposalBody.ts +19 -9
  57. package/src/actions/pol/getRewardVaultIncentives.ts +2 -2
  58. package/src/actions/tokens/getTokenInformation.ts +8 -15
  59. package/src/enum/txnEnum.ts +2 -0
  60. package/dist/chunk-5NDYN2IB.mjs +0 -4
  61. package/dist/chunk-5NDYN2IB.mjs.map +0 -1
  62. package/dist/chunk-I7M43BB4.cjs.map +0 -1
  63. package/dist/chunk-WD4B3SXS.cjs +0 -4
  64. /package/dist/{chunk-G4CNETLS.mjs.map → chunk-6K252BGM.mjs.map} +0 -0
  65. /package/dist/{chunk-S5VOCVBR.mjs.map → chunk-UENDEN3M.mjs.map} +0 -0
@@ -145,6 +145,8 @@ declare enum TransactionActionType {
145
145
  QUEUE_UNBONDING_BERA = "Queue Unstake BERA",
146
146
  BEND_MARKET_REPAY_AND_WITHDRAW_COLLATERAL = "Bend Market Repay and Withdraw Collateral",
147
147
  BEND_MARKET_SUPPLY_COLLATERAL_AND_BORROW = "Bend Market Supply Collateral and Borrow",
148
+ BEND_MARKET_MULTIPLY = "Bend Market Multiply",
149
+ BEND_MARKET_DEMULTIPLY = "Bend Market Demultiply",
148
150
  BEND_VAULT_SUPPLY = "Bend Vault Supply",
149
151
  BEND_VAULT_WITHDRAW = "Bend Vault Withdraw",
150
152
  BEND_CURATOR_REALLOCATE = "Bend Curator Reallocate",
@@ -145,6 +145,8 @@ declare enum TransactionActionType {
145
145
  QUEUE_UNBONDING_BERA = "Queue Unstake BERA",
146
146
  BEND_MARKET_REPAY_AND_WITHDRAW_COLLATERAL = "Bend Market Repay and Withdraw Collateral",
147
147
  BEND_MARKET_SUPPLY_COLLATERAL_AND_BORROW = "Bend Market Supply Collateral and Borrow",
148
+ BEND_MARKET_MULTIPLY = "Bend Market Multiply",
149
+ BEND_MARKET_DEMULTIPLY = "Bend Market Demultiply",
148
150
  BEND_VAULT_SUPPLY = "Bend Vault Supply",
149
151
  BEND_VAULT_WITHDRAW = "Bend Vault Withdraw",
150
152
  BEND_CURATOR_REALLOCATE = "Bend Curator Reallocate",
@@ -1,10 +1,10 @@
1
- export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, i as ClaimedIncentives, j as ClaimedIncentivesLocalState, C as CustomProposal, k as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, l as IContractWriteFn, m as IncentiveReward, n as IncentiveRewardChunksWithValidatorData, o as PROPOSAL_GENRE, p as Proposal, q as ProposalAction, r as ProposalVotes, P as ProtocolMetadata, s as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, V as VerifiedAbi, t as Vote, u as Voter } from '../global.d-6aSWIkV_.cjs';
1
+ export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, i as ClaimedIncentives, j as ClaimedIncentivesLocalState, C as CustomProposal, k as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, l as IContractWriteFn, m as IncentiveReward, n as IncentiveRewardChunksWithValidatorData, o as PROPOSAL_GENRE, p as Proposal, q as ProposalAction, r as ProposalVotes, P as ProtocolMetadata, s as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, V as VerifiedAbi, t as Vote, u as Voter } from '../global.d-B7IeayVX.cjs';
2
2
  import { M as MinimalERC20 } from '../HoneyConfigProvider-DfkjmzEf.cjs';
3
3
  export { A as AllowanceQueryItem, j as AllowanceToken, B as BalanceToken, y as BexStatus, w as Calldata, H as HoneySwapActions, I as IAggregatorArgs, z as IAggregatorQuote, g as IRawAggregatorQuote, v as IUserPosition, h as PythPriceFeedMap, S as SwapRequest, b as Token, i as TokenCurrentPriceMap, x as TokenPriceInfo, t as TokenWithAmount, a as TokenWithMetadata, D as TokenWithPrice } from '../HoneyConfigProvider-DfkjmzEf.cjs';
4
4
  import { BundleData, EnsoClient } from '@ensofinance/sdk';
5
5
  import { TransactionRequest, Address, Hex, PublicClient } from 'viem';
6
6
  import '@berachain/graphql/governance';
7
- import '../txnEnum-CCuQUFlh.cjs';
7
+ import '../txnEnum-7_o92X3N.cjs';
8
8
  import '@berachain/graphql/pol/api';
9
9
  import '@wagmi/core';
10
10
  import 'swr';
@@ -1,10 +1,10 @@
1
- export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, i as ClaimedIncentives, j as ClaimedIncentivesLocalState, C as CustomProposal, k as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, l as IContractWriteFn, m as IncentiveReward, n as IncentiveRewardChunksWithValidatorData, o as PROPOSAL_GENRE, p as Proposal, q as ProposalAction, r as ProposalVotes, P as ProtocolMetadata, s as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, V as VerifiedAbi, t as Vote, u as Voter } from '../global.d-SU9Epq0M.js';
1
+ export { A as AggregatedTokenTotals, g as BribeBoostReward, b as BribeBoostRewardItem, B as BribeBoostRewardProof, h as BribeBoostValidatorApr, i as ClaimedIncentives, j as ClaimedIncentivesLocalState, C as CustomProposal, k as CustomProposalActionErrors, a as CustomProposalErrors, D as DefaultHookOptions, c as DefaultHookReturnType, G as GovernanceTopic, I as IContractWrite, l as IContractWriteFn, m as IncentiveReward, n as IncentiveRewardChunksWithValidatorData, o as PROPOSAL_GENRE, p as Proposal, q as ProposalAction, r as ProposalVotes, P as ProtocolMetadata, s as SafeProposalAction, d as StakedBeraAsset, S as StakingConfig, U as UserVaultInfo, V as VerifiedAbi, t as Vote, u as Voter } from '../global.d-5w_lvl2J.js';
2
2
  import { M as MinimalERC20 } from '../HoneyConfigProvider-DVP_9KZn.js';
3
3
  export { A as AllowanceQueryItem, j as AllowanceToken, B as BalanceToken, y as BexStatus, w as Calldata, H as HoneySwapActions, I as IAggregatorArgs, z as IAggregatorQuote, g as IRawAggregatorQuote, v as IUserPosition, h as PythPriceFeedMap, S as SwapRequest, b as Token, i as TokenCurrentPriceMap, x as TokenPriceInfo, t as TokenWithAmount, a as TokenWithMetadata, D as TokenWithPrice } from '../HoneyConfigProvider-DVP_9KZn.js';
4
4
  import { BundleData, EnsoClient } from '@ensofinance/sdk';
5
5
  import { TransactionRequest, Address, Hex, PublicClient } from 'viem';
6
6
  import '@berachain/graphql/governance';
7
- import '../txnEnum-CCuQUFlh.js';
7
+ import '../txnEnum-7_o92X3N.js';
8
8
  import '@berachain/graphql/pol/api';
9
9
  import '@wagmi/core';
10
10
  import 'swr';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@berachain/berajs",
3
- "version": "0.2.8-beta.6",
3
+ "version": "0.2.8-beta.7",
4
4
  "sideEffects": false,
5
5
  "files": [
6
6
  "dist",
@@ -13,7 +13,7 @@
13
13
  "@apollo/client": "4.1.6",
14
14
  "@berachain-foundation/berancer-sdk": "1.1.4",
15
15
  "@berachain/abis": "0.1.0",
16
- "@berachain/config": "0.1.4",
16
+ "@berachain/config": "0.1.5",
17
17
  "@berachain/graphql": "0.4.9",
18
18
  "@ensofinance/sdk": "2.0.12",
19
19
  "@pythnetwork/hermes-client": "2.0.0",
@@ -30,7 +30,7 @@
30
30
  "viem": "2.45.0",
31
31
  "vitest": "3.2.4",
32
32
  "@berachain/utils": "0.1.0",
33
- "@berachain/wagmi": "0.4.0"
33
+ "@berachain/wagmi": "0.4.2"
34
34
  },
35
35
  "exports": {
36
36
  "./*": {
@@ -51,7 +51,7 @@
51
51
  "react": "^19.1",
52
52
  "react-dom": "^19.1",
53
53
  "viem": "^2.41.2",
54
- "@berachain/wagmi": "0.4.0"
54
+ "@berachain/wagmi": "0.4.2"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup",
@@ -16,15 +16,22 @@ import { BeraApolloClient } from "./BeraApolloClient";
16
16
  * @see {@link https://stellate.co/docs/graphql-metrics/tracking/clients}
17
17
  */
18
18
  function applyStellateClientName(url: BeraConfigHttpLink): BeraConfigHttpLink {
19
- if (!currentDapp) {
20
- return url;
21
- }
22
19
  const headers = typeof url === "string" ? undefined : url.headers;
20
+ const isDapp = !!currentDapp;
21
+ const isTest = process.env.VERCEL_ENV === "test";
22
+
23
23
  return {
24
24
  uri: getUriFromLink(url),
25
25
  headers: {
26
26
  ...headers,
27
- "x-graphql-client-name": `berachain.${currentDapp}.${process.env.NEXT_RUNTIME || "browser"}`,
27
+ "x-graphql-client-name": `berachain.${
28
+ isDapp
29
+ ? "dapps"
30
+ : isTest
31
+ ? "test"
32
+ : // this tracks usage of the berajs package in other packages
33
+ "berajs"
34
+ }`,
28
35
  "x-graphql-client-version": `${process.env.VERCEL_TARGET_ENV}.${process.env.VERCEL_GIT_COMMIT_SHA}`,
29
36
  },
30
37
  };
@@ -46,7 +46,7 @@ export interface OnChainPool {
46
46
  swapFee: string;
47
47
  decimals: number;
48
48
  weights: readonly string[] | undefined;
49
- version: any;
49
+ version: unknown;
50
50
  factory: Address;
51
51
  type: GqlPoolType;
52
52
  /**
@@ -245,6 +245,8 @@ export async function getBendMultiplyBundle({
245
245
  },
246
246
  ];
247
247
 
248
+ const hasWalletSupply = rawSupplyCollateralAmount !== "0";
249
+
248
250
  const flashloanActions = [
249
251
  {
250
252
  protocol: "bend",
@@ -252,8 +254,13 @@ export async function getBendMultiplyBundle({
252
254
  args: {
253
255
  flashloanToken: loanAddress,
254
256
  flashloanAmount: rawBorrowAmount,
255
- tokenIn: collateralAddress,
256
- amountIn: rawSupplyCollateralAmount,
257
+ // Only include tokenIn/amountIn when the user is supplying collateral
258
+ // from their wallet. For loop-only (multiply from existing position
259
+ // collateral), no wallet transfer is needed.
260
+ ...(hasWalletSupply && {
261
+ tokenIn: collateralAddress,
262
+ amountIn: rawSupplyCollateralAmount,
263
+ }),
257
264
  tokenOut: loanAddress,
258
265
  callback: [
259
266
  // [0] Swap the flashloaned loan tokens into collateral
@@ -37,10 +37,9 @@ function toBigIntOrUndefined(
37
37
 
38
38
  /**
39
39
  * Get the zap transactions for a given bundle.
40
- * @param args - The arguments for the zap transactions.
41
40
  * @returns The zap transaction & approval transaction if required.
42
41
  */
43
- export const getTransactionsFromBundle = async ({
42
+ export async function getTransactionsFromBundle({
44
43
  fromAddress,
45
44
  amountIn,
46
45
  tokenIn,
@@ -48,7 +47,7 @@ export const getTransactionsFromBundle = async ({
48
47
  ensoClient,
49
48
  bundle,
50
49
  publicClient,
51
- }: GetZapTransactionsArgs): Promise<GetZapTransactions> => {
50
+ }: GetZapTransactionsArgs): Promise<GetZapTransactions> {
52
51
  const transactions: GetZapTransactions = [];
53
52
  /**
54
53
  * If the token is not the native token, we need to check if approval is required.
@@ -92,15 +91,14 @@ export const getTransactionsFromBundle = async ({
92
91
  gasLimit: BigInt(bundle.gas),
93
92
  });
94
93
  return transactions;
95
- };
94
+ }
96
95
 
97
96
  /**
98
97
  * Get ensowallet transactions for a bundle with approval handling.
99
98
  * Checks allowance on the ensowallet spender and prepends approval when needed.
100
- * @param args - The arguments for transaction generation.
101
99
  * @returns The bundle transaction and optional approval transaction.
102
100
  */
103
- export const getEnsoWalletTransactionsWithApproval = async ({
101
+ export async function getEnsoWalletTransactionsWithApproval({
104
102
  fromAddress,
105
103
  amountIn,
106
104
  tokenIn,
@@ -109,7 +107,7 @@ export const getEnsoWalletTransactionsWithApproval = async ({
109
107
  }: GetEnsoWalletTransactionsWithApprovalArgs): Promise<{
110
108
  transactions: GetZapTransactions;
111
109
  approval: AllowanceQueryItem | null;
112
- }> => {
110
+ }> {
113
111
  const transactions: GetZapTransactions = [];
114
112
  const spender = getAddress(bundle.tx.to);
115
113
  let approval: AllowanceQueryItem | null = null;
@@ -163,7 +161,7 @@ export const getEnsoWalletTransactionsWithApproval = async ({
163
161
  gasLimit: bundle.gas ? BigInt(bundle.gas) : undefined,
164
162
  });
165
163
  return { transactions, approval };
166
- };
164
+ }
167
165
 
168
166
  /**
169
167
  * Compute the fraction of swap output retained after accounting for slippage.
@@ -10,43 +10,74 @@ type CheckProposalFieldResult =
10
10
  | CheckProposalFieldResultMinimal[]
11
11
  | Record<string, CheckProposalFieldResultMinimal>;
12
12
 
13
- interface CheckProposalField {
14
- (arg: {
15
- fieldOrType:
16
- | "address"
17
- | "hex"
18
- | "abi"
19
- | "string"
20
- | "bool"
21
- | `uint${string}`
22
- | `int${string}`
23
- | "action"
24
- | "title"
25
- | "forumLink"
26
- | "description"
27
- | "logoURI"
28
- | "url";
29
- value: any;
30
- required?: boolean;
31
- baseUrl?: string;
32
- components?: readonly (AbiParameter | readonly AbiParameter[])[];
33
- }): CheckProposalFieldResultMinimal;
34
- (arg: {
35
- fieldOrType: "tuple[]" | "tuple";
36
- value: any;
37
- required?: boolean;
38
- baseUrl?: string;
39
- components?: readonly (AbiParameter | readonly AbiParameter[])[];
40
- }): CheckProposalFieldResult;
13
+ /**
14
+ * Internal implementation arg covering the full union of all valid fieldOrType
15
+ * values. The public overloads below provide the narrowed return types.
16
+ */
17
+ interface CheckProposalFieldImplArg {
18
+ fieldOrType:
19
+ | "address"
20
+ | "hex"
21
+ | "abi"
22
+ | "string"
23
+ | "bool"
24
+ | `uint${string}`
25
+ | `int${string}`
26
+ | "action"
27
+ | "title"
28
+ | "forumLink"
29
+ | "description"
30
+ | "logoURI"
31
+ | "url"
32
+ | "tuple[]"
33
+ | "tuple";
34
+ value: unknown;
35
+ required?: boolean;
36
+ baseUrl?: string;
37
+ components?: readonly (AbiParameter | readonly AbiParameter[])[];
41
38
  }
42
- // @ts-expect-error TODO: this is not typed, will throw if not valid
43
- export const checkProposalField: CheckProposalField = ({
39
+
40
+ /**
41
+ * Validates a single proposal field or ABI-typed value.
42
+ * Returns `null` if valid, or a `ProposalErrorCodes` value describing the problem.
43
+ */
44
+ export function checkProposalField(arg: {
45
+ fieldOrType:
46
+ | "address"
47
+ | "hex"
48
+ | "abi"
49
+ | "string"
50
+ | "bool"
51
+ | `uint${string}`
52
+ | `int${string}`
53
+ | "action"
54
+ | "title"
55
+ | "forumLink"
56
+ | "description"
57
+ | "logoURI"
58
+ | "url";
59
+ value: unknown;
60
+ required?: boolean;
61
+ baseUrl?: string;
62
+ components?: readonly (AbiParameter | readonly AbiParameter[])[];
63
+ }): CheckProposalFieldResultMinimal;
64
+ /**
65
+ * For tuple/tuple[] types, may return nested error structures.
66
+ */
67
+ export function checkProposalField(arg: {
68
+ fieldOrType: "tuple[]" | "tuple";
69
+ value: unknown;
70
+ required?: boolean;
71
+ baseUrl?: string;
72
+ components?: readonly (AbiParameter | readonly AbiParameter[])[];
73
+ }): CheckProposalFieldResult;
74
+ export function checkProposalField({
44
75
  fieldOrType,
45
76
  value,
46
77
  required = true,
47
78
  baseUrl,
48
79
  components,
49
- }) => {
80
+ }: CheckProposalFieldImplArg): CheckProposalFieldResult {
50
81
  const notRequiredAbiTypes = ["bool", "string"];
51
82
 
52
83
  if (
@@ -89,19 +120,19 @@ export const checkProposalField: CheckProposalField = ({
89
120
  return null;
90
121
 
91
122
  case "title":
92
- if (value.length === 0) {
123
+ if (typeof value !== "string" || value.length === 0) {
93
124
  return ProposalErrorCodes.REQUIRED;
94
125
  }
95
126
  return null;
96
127
 
97
128
  case "description":
98
- if (value.length === 0) {
129
+ if (typeof value !== "string" || value.length === 0) {
99
130
  return ProposalErrorCodes.REQUIRED;
100
131
  }
101
132
  return null;
102
133
 
103
- case "forumLink":
104
- if (value.length === 0) {
134
+ case "forumLink": {
135
+ if (typeof value !== "string" || value.length === 0) {
105
136
  return ProposalErrorCodes.REQUIRED;
106
137
  }
107
138
 
@@ -109,8 +140,7 @@ export const checkProposalField: CheckProposalField = ({
109
140
  return ProposalErrorCodes.INVALID_ADDRESS;
110
141
  }
111
142
 
112
- // biome-ignore lint/correctness/noSwitchDeclarations: <explanation>
113
- const base = new URL(baseUrl as string);
143
+ const base = new URL(baseUrl!);
114
144
 
115
145
  // base.pathname = "/c/";
116
146
 
@@ -119,21 +149,25 @@ export const checkProposalField: CheckProposalField = ({
119
149
  }
120
150
 
121
151
  return null;
152
+ }
122
153
 
123
154
  case "address":
124
- if (!isAddress(value, { strict: true })) {
155
+ if (typeof value !== "string" || !isAddress(value, { strict: true })) {
125
156
  return ProposalErrorCodes.INVALID_ADDRESS;
126
157
  }
127
158
 
128
159
  return null;
129
160
 
130
161
  case "hex":
131
- if (!isHex(value, { strict: true })) {
162
+ if (typeof value !== "string" || !isHex(value, { strict: true })) {
132
163
  return ProposalErrorCodes.INVALID_ADDRESS;
133
164
  }
134
165
  return null;
135
166
 
136
167
  case "abi":
168
+ if (typeof value !== "string") {
169
+ return ProposalErrorCodes.INVALID_ABI;
170
+ }
137
171
  try {
138
172
  JSON.parse(value);
139
173
  } catch {
@@ -142,20 +176,29 @@ export const checkProposalField: CheckProposalField = ({
142
176
  return null;
143
177
 
144
178
  case "action":
145
- if (!isAddress(value, { strict: true })) {
179
+ if (typeof value !== "string" || !isAddress(value, { strict: true })) {
146
180
  return ProposalErrorCodes.INVALID_ADDRESS;
147
181
  }
148
182
  return null;
149
183
 
150
184
  case "tuple":
151
185
  if (typeof value === "object" && Array.isArray(components)) {
152
- const errors: Record<string, ProposalErrorCodes | null> = {};
186
+ const errors: Record<string, CheckProposalFieldResult> = {};
153
187
 
154
188
  for (const component of components) {
155
- errors[component.name!] = checkProposalField({
156
- fieldOrType: component.type,
157
- value: value[component.name!],
158
- components: component.components,
189
+ // Intersect with components? to access the field safely;
190
+ // it only exists on tuple AbiParameter variants
191
+ const abiParam = component as AbiParameter & {
192
+ components?: readonly AbiParameter[];
193
+ };
194
+ const name = abiParam.name!;
195
+ // fieldOrType is cast to "tuple" | "tuple[]" to satisfy overload 2
196
+ // (returns CheckProposalFieldResult). The actual runtime type dispatches
197
+ // to the correct branch.
198
+ errors[name] = checkProposalField({
199
+ fieldOrType: abiParam.type as "tuple" | "tuple[]",
200
+ value: (value as Record<string, unknown>)[name],
201
+ components: abiParam.components,
159
202
  });
160
203
  }
161
204
 
@@ -163,7 +206,7 @@ export const checkProposalField: CheckProposalField = ({
163
206
  return null;
164
207
  }
165
208
 
166
- return errors;
209
+ return errors as Record<string, CheckProposalFieldResultMinimal>;
167
210
  }
168
211
 
169
212
  return null;
@@ -182,30 +225,41 @@ export const checkProposalField: CheckProposalField = ({
182
225
  return null;
183
226
  }
184
227
 
185
- return errors;
228
+ // errors contains tuple results (null | Record<string, ...>);
229
+ // cast is intentional — the type definition predates nested support
230
+ return errors as unknown as CheckProposalFieldResultMinimal[];
186
231
  }
187
232
 
188
233
  return null;
234
+
189
235
  case "logoURI": {
190
236
  if (value === undefined || value === "") {
191
237
  return null;
192
238
  }
193
- if (URL.canParse(value) && new URL(value).protocol === "https:") {
194
- return null;
239
+ if (
240
+ typeof value !== "string" ||
241
+ !URL.canParse(value) ||
242
+ new URL(value).protocol !== "https:"
243
+ ) {
244
+ return ProposalErrorCodes.MUST_BE_HTTPS_OR_IPFS;
195
245
  }
196
- return ProposalErrorCodes.MUST_BE_HTTPS_OR_IPFS;
246
+ return null;
197
247
  }
198
248
  case "url": {
199
249
  if (value === undefined || value === "") {
200
250
  return null;
201
251
  }
202
- if (URL.canParse(value) && new URL(value).protocol === "https:") {
203
- return null;
252
+ if (
253
+ typeof value !== "string" ||
254
+ !URL.canParse(value) ||
255
+ new URL(value).protocol !== "https:"
256
+ ) {
257
+ return ProposalErrorCodes.MUST_BE_HTTPS;
204
258
  }
205
- return ProposalErrorCodes.MUST_BE_HTTPS;
259
+ return null;
206
260
  }
207
261
  default:
208
262
  console.error(`Invalid field or type: ${fieldOrType}`);
209
263
  return null;
210
264
  }
211
- };
265
+ }
@@ -15,11 +15,15 @@ export const MOCKED_PROPOSAL_STATUSES: readonly ProposalStatus[] = [
15
15
  ProposalStatus.QuorumNotReached,
16
16
  ];
17
17
 
18
+ /**
19
+ * Derives the effective `ProposalStatus` by reconciling subgraph data with the
20
+ * on-chain contract state. Falls back to subgraph timestamps when the on-chain
21
+ * state is unavailable.
22
+ */
18
23
  export function computeActualStatus(
24
+ /** Subgraph proposal data */
19
25
  proposal: ProposalSelectionFragment,
20
- /**
21
- * Value returned by the `state` function of the governance contract.
22
- */
26
+ /** Value returned by the `state` function of the governance contract */
23
27
  proposalOnChainState?: ProposalState,
24
28
  ): ProposalStatus {
25
29
  /**
@@ -14,6 +14,20 @@ import {
14
14
  import { getApolloClient } from "../clients/getApolloClient";
15
15
  import { computeActualStatus } from "./computeActualStatus";
16
16
 
17
+ export type GetAllProposalsArgs = BeraJS.BaseFunctionArgs & {
18
+ /** Subgraph filter applied to the proposals query */
19
+ where: Proposal_Filter;
20
+ /** Number of proposals to skip (for pagination) */
21
+ offset?: number;
22
+ /** Maximum proposals per page; must be ≤ 1000 */
23
+ perPage?: number;
24
+ orderBy?: Proposal_OrderBy;
25
+ orderDirection?: OrderDirection;
26
+ /** Full-text search query; switches to the search endpoint when provided */
27
+ text?: string;
28
+ };
29
+
30
+ /** Fetches a paginated list of governance proposals from the subgraph */
17
31
  export async function getAllProposals({
18
32
  where,
19
33
  orderBy,
@@ -22,14 +36,7 @@ export async function getAllProposals({
22
36
  perPage = 20,
23
37
  text,
24
38
  ...args
25
- }: BeraJS.BaseFunctionArgs & {
26
- offset?: number;
27
- where: Proposal_Filter;
28
- perPage?: number;
29
- orderBy?: Proposal_OrderBy;
30
- orderDirection?: OrderDirection;
31
- text?: string;
32
- }): Promise<ProposalSelectionFragment[] | undefined> {
39
+ }: GetAllProposalsArgs): Promise<ProposalSelectionFragment[] | undefined> {
33
40
  try {
34
41
  if (perPage > 1000) {
35
42
  throw new Error("perPage must be less than 1000");
@@ -5,10 +5,18 @@ import type {
5
5
  } from "../../types/governance";
6
6
  import { checkProposalField } from "./checkProposalField";
7
7
 
8
- export const getBodyErrors = (
9
- proposal: CustomProposal,
10
- currentTopic: GovernanceTopic,
11
- ) => {
8
+ export interface GetBodyErrorsArgs {
9
+ /** The proposal to validate */
10
+ proposal: CustomProposal;
11
+ /** The current governance topic, used for forum link base URL validation */
12
+ currentTopic: GovernanceTopic;
13
+ }
14
+
15
+ /** Validates the body fields (title, description, forum link) of a proposal */
16
+ export function getBodyErrors({
17
+ proposal,
18
+ currentTopic,
19
+ }: GetBodyErrorsArgs): CustomProposalErrors {
12
20
  const e: CustomProposalErrors = {};
13
21
  e.title = checkProposalField({
14
22
  fieldOrType: "title",
@@ -25,4 +33,4 @@ export const getBodyErrors = (
25
33
  });
26
34
 
27
35
  return e;
28
- };
36
+ }
@@ -17,14 +17,19 @@ import { beraChefAbi } from "@berachain/abis/pol/rewards/beraChef";
17
17
  import { rewardVaultAbi } from "@berachain/abis/pol/rewards/rewardVault";
18
18
 
19
19
  // Function to check if ABI contains proxy-related functions
20
- function isProxyABI(abi: Abi[]): boolean {
21
- return abi.some(
22
- (item: any) =>
23
- item.name === "implementation" ||
24
- item.name === "proxyType" ||
25
- (item.type === "constructor" &&
26
- item.inputs?.[0]?.name === "implementation"),
27
- );
20
+ function isProxyABI(abi: Abi): boolean {
21
+ return abi.some((item: AbiItem) => {
22
+ const i = item as {
23
+ name?: string;
24
+ type: string;
25
+ inputs?: readonly { name?: string }[];
26
+ };
27
+ return (
28
+ i.name === "implementation" ||
29
+ i.name === "proxyType" ||
30
+ (i.type === "constructor" && i.inputs?.[0]?.name === "implementation")
31
+ );
32
+ });
28
33
  }
29
34
 
30
35
  /**
@@ -118,27 +123,30 @@ function _getFunctionSignature(abiItem: AbiFunction | undefined) {
118
123
  }
119
124
  }
120
125
 
126
+ export interface GetDecodedFunctionDataArgs {
127
+ /** Contract address that emitted the calldata */
128
+ address: Address;
129
+ /** Raw calldata to decode */
130
+ callData: `0x${string}`;
131
+ /** @default defaultChainId */
132
+ chainId?: number;
133
+ publicClient: PublicClient;
134
+ }
135
+
121
136
  /**
122
137
  * Decodes the function data from a given contract address and calldata.
123
138
  *
124
- * This function attempts to decode the provided calldata using a known set of ABIs.
125
- * If the call data cannot be decoded with the known ABIs, it fetches the ABI from the blockexplorer API.
139
+ * Attempts to decode using a known set of ABIs first, then falls back to
140
+ * fetching the ABI from the block-explorer API.
126
141
  *
127
- * @param address - The contract address.
128
- * @param callData - The calldata to decode, in hexadecimal format.
129
- * @returns An object containing the decoded ABI item, function signature, function name, and arguments.
142
+ * @returns An object with the decoded ABI item, function signature, function name, and arguments.
130
143
  */
131
144
  export async function getDecodedFunctionData({
132
145
  address,
133
146
  callData,
134
147
  chainId = defaultChainId,
135
148
  publicClient,
136
- }: {
137
- address: Address;
138
- callData: `0x${string}`;
139
- chainId?: number;
140
- publicClient: PublicClient;
141
- }) {
149
+ }: GetDecodedFunctionDataArgs) {
142
150
  const knownAbi = [...beraChefAbi, ...rewardVaultAbi, ...erc20Abi];
143
151
 
144
152
  const abi = await _getAbiForCallData({
@@ -10,13 +10,17 @@ import {
10
10
  import { getApolloClient } from "../clients/getApolloClient";
11
11
  import { computeActualStatus } from "./computeActualStatus";
12
12
 
13
+ export type GetProposalDetailsArgs = BeraJS.BaseFunctionArgs & {
14
+ /** On-chain proposal ID */
15
+ proposalId: string;
16
+ client?: PublicClient;
17
+ };
18
+
19
+ /** Fetches a single proposal with its vote data from the subgraph */
13
20
  export async function getProposalDetails({
14
21
  proposalId,
15
22
  ...args
16
- }: BeraJS.BaseFunctionArgs & {
17
- proposalId: string;
18
- client?: PublicClient;
19
- }): Promise<ProposalWithVotesFragment | undefined> {
23
+ }: GetProposalDetailsArgs): Promise<ProposalWithVotesFragment | undefined> {
20
24
  const governanceClient = getApolloClient("governance.subgraph", args);
21
25
 
22
26
  const res = await governanceClient.query<