@reserve-protocol/sdk 0.0.2 → 0.1.0

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 (4) hide show
  1. package/README.md +15 -9
  2. package/dist/index.d.mts +4854 -1230
  3. package/dist/index.mjs +2483 -1870
  4. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -302,6 +302,58 @@ function createDtfClientApi({ baseUrl }) {
302
302
  };
303
303
  }
304
304
  //#endregion
305
+ //#region src/client/explorer.ts
306
+ const EXPLORER_REQUEST_TIMEOUT_MS = 5e3;
307
+ function createDtfClientExplorer({ etherscanApiKey }) {
308
+ const metadataCache = /* @__PURE__ */ new Map();
309
+ const requestCache = /* @__PURE__ */ new Map();
310
+ return { getContractMetadata(params) {
311
+ if (!etherscanApiKey) return Promise.resolve(null);
312
+ const address = getAddress(params.address);
313
+ const cacheKey = `${params.chainId}:${address.toLowerCase()}`;
314
+ const cached = metadataCache.get(cacheKey);
315
+ if (cached) return Promise.resolve(cached);
316
+ const pending = requestCache.get(cacheKey);
317
+ if (pending) return pending;
318
+ const request = fetchContractMetadata({
319
+ chainId: params.chainId,
320
+ address,
321
+ etherscanApiKey
322
+ }).catch(() => null).then((metadata) => {
323
+ if (metadata) metadataCache.set(cacheKey, metadata);
324
+ return metadata;
325
+ }).finally(() => {
326
+ requestCache.delete(cacheKey);
327
+ });
328
+ requestCache.set(cacheKey, request);
329
+ return request;
330
+ } };
331
+ }
332
+ async function fetchContractMetadata({ chainId, address, etherscanApiKey }) {
333
+ const url = new URL("https://api.etherscan.io/v2/api");
334
+ url.searchParams.set("chainid", String(chainId));
335
+ url.searchParams.set("module", "contract");
336
+ url.searchParams.set("action", "getsourcecode");
337
+ url.searchParams.set("address", address);
338
+ url.searchParams.set("apikey", etherscanApiKey);
339
+ const response = await fetch(url, { signal: AbortSignal.timeout(EXPLORER_REQUEST_TIMEOUT_MS) });
340
+ if (!response.ok) return null;
341
+ const data = await response.json();
342
+ if (data.status !== "1" || !Array.isArray(data.result)) return null;
343
+ const metadata = data.result[0];
344
+ if (!metadata?.ABI || !metadata.ContractName || metadata.ABI === "Contract source code not verified") return null;
345
+ try {
346
+ const abi = JSON.parse(metadata.ABI);
347
+ if (!Array.isArray(abi)) return null;
348
+ return {
349
+ abi,
350
+ contractName: metadata.ContractName
351
+ };
352
+ } catch {
353
+ return null;
354
+ }
355
+ }
356
+ //#endregion
305
357
  //#region src/config/index.ts
306
358
  const DEFAULT_API_BASE_URL = "https://api.reserve.org";
307
359
  const SUPPORTED_CHAINS = {
@@ -525,6 +577,7 @@ function createDtfClient(config = {}) {
525
577
  const chains = createChainConfig(config.chains);
526
578
  return {
527
579
  api: createDtfClientApi({ baseUrl: apiBaseUrl }),
580
+ explorer: createDtfClientExplorer({ etherscanApiKey: config.etherscanApiKey }),
528
581
  subgraph: createDtfClientSubgraph({ chains }),
529
582
  viem: createDtfClientViem({ chains })
530
583
  };
@@ -537,10 +590,13 @@ function createChainConfig(overrides = {}) {
537
590
  indexSubgraphUrl: INDEX_DTF_SUBGRAPH_URL[chainId],
538
591
  ...chainId in YIELD_DTF_SUBGRAPH_URL ? { yieldSubgraphUrl: YIELD_DTF_SUBGRAPH_URL[chainId] } : {},
539
592
  ...override,
540
- rpcUrls: [...override?.rpcUrls ?? [], ...DEFAULT_RPC_URLS[chainId]]
593
+ rpcUrls: dedupeRpcUrls([...override?.rpcUrls ?? [], ...DEFAULT_RPC_URLS[chainId]])
541
594
  }];
542
595
  }));
543
596
  }
597
+ function dedupeRpcUrls(rpcUrls) {
598
+ return [...new Set(rpcUrls)];
599
+ }
544
600
  function trimTrailingSlash(value) {
545
601
  return value.endsWith("/") ? value.slice(0, -1) : value;
546
602
  }
@@ -10289,53 +10345,9 @@ const dtfIndexStakingVaultOptimisticAbi = [
10289
10345
  }
10290
10346
  ];
10291
10347
  //#endregion
10292
- //#region src/index-dtf/abis/optimistic-timelock.ts
10293
- const optimisticTimelockAbi = [{
10294
- type: "function",
10295
- name: "getRoleMemberCount",
10296
- inputs: [{
10297
- name: "role",
10298
- type: "bytes32",
10299
- internalType: "bytes32"
10300
- }],
10301
- outputs: [{
10302
- name: "",
10303
- type: "uint256",
10304
- internalType: "uint256"
10305
- }],
10306
- stateMutability: "view"
10307
- }, {
10308
- type: "function",
10309
- name: "getRoleMember",
10310
- inputs: [{
10311
- name: "role",
10312
- type: "bytes32",
10313
- internalType: "bytes32"
10314
- }, {
10315
- name: "index",
10316
- type: "uint256",
10317
- internalType: "uint256"
10318
- }],
10319
- outputs: [{
10320
- name: "",
10321
- type: "address",
10322
- internalType: "address"
10323
- }],
10324
- stateMutability: "view"
10325
- }];
10326
- //#endregion
10327
- //#region src/index-dtf/governance/optimistic-errors.ts
10328
- function isUnsupportedOptimisticContractError(error) {
10329
- const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
10330
- return message.includes("returned no data") || message.includes("could not decode") || message.includes("data size of 0 bytes") || message.includes("function") && message.includes("not found");
10331
- }
10332
- function isUnsupportedVoteLockOptimisticReadError(error) {
10333
- const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
10334
- return isUnsupportedOptimisticContractError(error) || message.includes("execution reverted") && (message.includes("optimisticdelegates") || message.includes("getoptimisticvotes") || message.includes("getpastoptimisticvotes"));
10335
- }
10336
- //#endregion
10337
10348
  //#region src/index-dtf/governance/utils.ts
10338
10349
  const D18$1 = 10n ** 18n;
10350
+ const MAX_UINT256$2 = (1n << 256n) - 1n;
10339
10351
  function getProposalGovernanceAddresses(dtf) {
10340
10352
  return dedupeAddresses([
10341
10353
  ...dtf.governance.all.flatMap((authority) => authority.type === "governance" ? [authority.address] : []),
@@ -10373,37 +10385,51 @@ function mapGuardianGroup(authority) {
10373
10385
  function getZeroValues(length) {
10374
10386
  return Array.from({ length }, () => 0n);
10375
10387
  }
10376
- function getVoteState(proposal, timestamp = getCurrentTime()) {
10388
+ function getProposalState(proposal, timestamp = getCurrentTime()) {
10377
10389
  const state = createInitialVotingState(proposal.state);
10378
10390
  const isOptimistic = proposal.isOptimistic === true;
10391
+ const optimisticVetoThresholdVotes = isOptimistic ? getOptimisticVetoVotes(proposal) : void 0;
10392
+ const optimisticTransitioned = isOptimistic && proposal.vetoThreshold === MAX_UINT256$2;
10393
+ const optimisticZeroSnapshotSupply = isOptimistic && proposal.optimistic?.snapshotSupply?.raw === 0n;
10394
+ const optimisticVetoReached = isOptimistic && optimisticVetoThresholdVotes !== void 0 && optimisticVetoThresholdVotes > 0n && proposal.againstWeightedVotes.raw >= optimisticVetoThresholdVotes;
10395
+ const quorumVotes = proposal.quorumVotes.raw;
10379
10396
  if (proposal.state === "QUEUED" && proposal.executionETA) state.deadline = proposal.executionETA - timestamp;
10380
- else if (proposal.state === "PENDING") if (timestamp >= proposal.voteEnd && proposal.optimistic) state.state = getOptimisticFinalState(proposal);
10381
- else if (timestamp >= proposal.voteEnd && isOptimistic) state.state = proposal.state;
10382
- else if (timestamp >= proposal.voteStart && timestamp < proposal.voteEnd) {
10397
+ else if (proposal.state === "PENDING") if (timestamp <= proposal.voteStart) state.deadline = proposal.voteStart - timestamp;
10398
+ else if (optimisticTransitioned) state.state = "DEFEATED";
10399
+ else if (optimisticZeroSnapshotSupply) state.state = "CANCELED";
10400
+ else if (optimisticVetoReached) state.state = "DEFEATED";
10401
+ else if (timestamp > proposal.voteEnd && isOptimistic) state.state = getOptimisticFinalState(proposal, optimisticVetoThresholdVotes);
10402
+ else if (timestamp <= proposal.voteEnd) {
10383
10403
  state.state = "ACTIVE";
10384
10404
  state.deadline = proposal.voteEnd - timestamp;
10385
- } else if (timestamp < proposal.voteStart) state.deadline = proposal.voteStart - timestamp;
10386
- else state.state = "EXPIRED";
10387
- else if (proposal.state === "ACTIVE") if (timestamp >= proposal.voteEnd) if (proposal.optimistic) state.state = getOptimisticFinalState(proposal);
10388
- else if (isOptimistic) state.state = proposal.state;
10405
+ } else state.state = "EXPIRED";
10406
+ else if (proposal.state === "ACTIVE") if (optimisticTransitioned) state.state = "DEFEATED";
10407
+ else if (optimisticZeroSnapshotSupply) state.state = "CANCELED";
10408
+ else if (optimisticVetoReached) state.state = "DEFEATED";
10409
+ else if (timestamp > proposal.voteEnd) if (isOptimistic) state.state = getOptimisticFinalState(proposal, optimisticVetoThresholdVotes);
10389
10410
  else if (proposal.againstWeightedVotes.raw > proposal.forWeightedVotes.raw || proposal.forWeightedVotes.raw === 0n) state.state = "DEFEATED";
10390
- else if (proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw < proposal.quorumVotes.raw) state.state = "QUORUM_NOT_REACHED";
10411
+ else if (proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw < quorumVotes) state.state = "QUORUM_NOT_REACHED";
10391
10412
  else state.state = "SUCCEEDED";
10392
10413
  else state.deadline = proposal.voteEnd - timestamp;
10393
10414
  const totalVotes = proposal.forWeightedVotes.raw + proposal.againstWeightedVotes.raw + proposal.abstainWeightedVotes.raw;
10394
- state.quorum = proposal.forWeightedVotes.raw > 0n && proposal.forWeightedVotes.raw >= proposal.quorumVotes.raw;
10395
- state.forVotesReachedQuorum = state.quorum;
10396
- state.participationQuorumReached = proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw >= proposal.quorumVotes.raw;
10397
- state.vetoReached = proposal.optimistic ? proposal.againstWeightedVotes.raw >= getOptimisticVetoThresholdVotes(proposal.optimistic) : false;
10415
+ state.quorum = isOptimistic ? optimisticVetoThresholdVotes !== void 0 && optimisticVetoThresholdVotes > 0n && proposal.againstWeightedVotes.raw >= optimisticVetoThresholdVotes : proposal.forWeightedVotes.raw > 0n && proposal.forWeightedVotes.raw >= quorumVotes;
10416
+ state.forVotesReachedQuorum = isOptimistic ? false : state.quorum;
10417
+ state.participationQuorumReached = isOptimistic ? state.quorum : proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw >= quorumVotes;
10418
+ state.vetoReached = isOptimistic ? state.quorum : false;
10419
+ state.threshold = getVotingThresholdState({
10420
+ currentVotes: isOptimistic ? proposal.againstWeightedVotes.raw : proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw,
10421
+ targetVotes: isOptimistic ? optimisticVetoThresholdVotes : quorumVotes,
10422
+ reached: isOptimistic ? state.vetoReached : state.participationQuorumReached
10423
+ });
10398
10424
  if (totalVotes > 0n) {
10399
10425
  state.for = getVotePercentage(proposal.forWeightedVotes.raw, totalVotes);
10400
10426
  state.abstain = getVotePercentage(proposal.abstainWeightedVotes.raw, totalVotes);
10401
- state.against = getVotePercentage(proposal.againstWeightedVotes.raw, totalVotes);
10427
+ state.against = isOptimistic && optimisticVetoThresholdVotes !== void 0 && optimisticVetoThresholdVotes > 0n ? getVotePercentage(proposal.againstWeightedVotes.raw, optimisticVetoThresholdVotes) : getVotePercentage(proposal.againstWeightedVotes.raw, totalVotes);
10402
10428
  }
10403
10429
  return state;
10404
10430
  }
10405
10431
  function withVoteState(proposal, timestamp = getCurrentTime()) {
10406
- const votingState = getVoteState(proposal, timestamp);
10432
+ const votingState = getProposalState(proposal, timestamp);
10407
10433
  return {
10408
10434
  ...proposal,
10409
10435
  state: votingState.state,
@@ -10418,25 +10444,106 @@ function createInitialVotingState(state) {
10418
10444
  forVotesReachedQuorum: false,
10419
10445
  participationQuorumReached: false,
10420
10446
  vetoReached: false,
10447
+ threshold: {
10448
+ currentVotes: mapAmount(0n),
10449
+ progress: 0,
10450
+ reached: false,
10451
+ hasTarget: false
10452
+ },
10421
10453
  for: 0,
10422
10454
  against: 0,
10423
10455
  abstain: 0
10424
10456
  };
10425
10457
  }
10426
- function getOptimisticVetoThresholdVotes(optimistic) {
10427
- const thresholdVotes = optimistic.vetoThreshold * optimistic.snapshotSupply.raw / D18$1;
10428
- return thresholdVotes > 0n ? thresholdVotes : 1n;
10458
+ function getVotingThresholdState({ currentVotes, targetVotes, reached }) {
10459
+ if (targetVotes === void 0 || targetVotes === MAX_UINT256$2) return {
10460
+ currentVotes: mapAmount(currentVotes),
10461
+ progress: 0,
10462
+ reached: false,
10463
+ hasTarget: false
10464
+ };
10465
+ return {
10466
+ currentVotes: mapAmount(currentVotes),
10467
+ targetVotes: mapAmount(targetVotes),
10468
+ progress: targetVotes > 0n ? getVotePercentage(currentVotes, targetVotes) : reached ? 100 : 0,
10469
+ reached,
10470
+ hasTarget: true
10471
+ };
10429
10472
  }
10430
- function getOptimisticFinalState(proposal) {
10431
- if (!proposal.optimistic) return proposal.state;
10432
- if (proposal.optimistic.snapshotSupply.raw === 0n) return "CANCELED";
10433
- return proposal.againstWeightedVotes.raw >= getOptimisticVetoThresholdVotes(proposal.optimistic) ? "DEFEATED" : "SUCCEEDED";
10473
+ function getOptimisticVetoThresholdVotes(optimistic) {
10474
+ if (optimistic.vetoThreshold === 0n || optimistic.snapshotSupply.raw === 0n) return 0n;
10475
+ const vetoThresholdVotes = optimistic.vetoThreshold * optimistic.snapshotSupply.raw / D18$1;
10476
+ return vetoThresholdVotes === 0n ? 1n : vetoThresholdVotes;
10477
+ }
10478
+ function getOptimisticFinalState(proposal, vetoThresholdVotes) {
10479
+ if (vetoThresholdVotes === void 0) return proposal.againstWeightedVotes.raw === 0n ? "SUCCEEDED" : proposal.state;
10480
+ if (vetoThresholdVotes === 0n) return proposal.againstWeightedVotes.raw === 0n ? "SUCCEEDED" : proposal.state;
10481
+ return proposal.againstWeightedVotes.raw >= vetoThresholdVotes ? "DEFEATED" : "SUCCEEDED";
10482
+ }
10483
+ function getOptimisticVetoVotes(proposal) {
10484
+ if (!proposal.optimistic) return;
10485
+ if (proposal.optimistic.vetoThresholdVotes) {
10486
+ const vetoThresholdVotes = proposal.optimistic.vetoThresholdVotes.raw;
10487
+ return vetoThresholdVotes > 0n ? vetoThresholdVotes : void 0;
10488
+ }
10489
+ if (proposal.optimistic.snapshotSupply === void 0 || proposal.optimistic.vetoThreshold === void 0) return;
10490
+ const vetoThresholdVotes = getOptimisticVetoThresholdVotes({
10491
+ snapshotSupply: proposal.optimistic.snapshotSupply,
10492
+ vetoThreshold: proposal.optimistic.vetoThreshold
10493
+ });
10494
+ return vetoThresholdVotes > 0n ? vetoThresholdVotes : void 0;
10434
10495
  }
10435
10496
  function getVotePercentage(votes, totalVotes) {
10436
10497
  return Number(votes * 10000n / totalVotes) / 100;
10437
10498
  }
10438
10499
  //#endregion
10500
+ //#region src/index-dtf/abis/optimistic-timelock.ts
10501
+ const optimisticTimelockAbi = [{
10502
+ type: "function",
10503
+ name: "getRoleMemberCount",
10504
+ inputs: [{
10505
+ name: "role",
10506
+ type: "bytes32",
10507
+ internalType: "bytes32"
10508
+ }],
10509
+ outputs: [{
10510
+ name: "",
10511
+ type: "uint256",
10512
+ internalType: "uint256"
10513
+ }],
10514
+ stateMutability: "view"
10515
+ }, {
10516
+ type: "function",
10517
+ name: "getRoleMember",
10518
+ inputs: [{
10519
+ name: "role",
10520
+ type: "bytes32",
10521
+ internalType: "bytes32"
10522
+ }, {
10523
+ name: "index",
10524
+ type: "uint256",
10525
+ internalType: "uint256"
10526
+ }],
10527
+ outputs: [{
10528
+ name: "",
10529
+ type: "address",
10530
+ internalType: "address"
10531
+ }],
10532
+ stateMutability: "view"
10533
+ }];
10534
+ //#endregion
10535
+ //#region src/index-dtf/governance/optimistic-errors.ts
10536
+ function isUnsupportedOptimisticContractError(error) {
10537
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
10538
+ return message.includes("returned no data") || message.includes("could not decode") || message.includes("data size of 0 bytes") || message.includes("function") && message.includes("not found");
10539
+ }
10540
+ function isUnsupportedVoteLockOptimisticReadError(error) {
10541
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
10542
+ return isUnsupportedOptimisticContractError(error) || (message.includes("execution reverted") || message.includes("reverted")) && (message.includes("optimisticdelegates") || message.includes("getoptimisticvotes") || message.includes("getpastoptimisticvotes"));
10543
+ }
10544
+ //#endregion
10439
10545
  //#region src/index-dtf/governance/optimistic.ts
10546
+ const MAX_UINT256$1 = (1n << 256n) - 1n;
10440
10547
  const OPTIMISTIC_PROPOSER_ROLE = "0x26f49d08685d9cdd4951a7470bc8fbe9dd0f00419c1a44c1b89f845867ae12e0";
10441
10548
  const CANCELLER_ROLE = "0xfd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783";
10442
10549
  async function getOptimisticProposalContext(client, params) {
@@ -10456,28 +10563,28 @@ async function getOptimisticProposalContext(client, params) {
10456
10563
  return null;
10457
10564
  }
10458
10565
  if (!isOptimistic) return null;
10459
- const [vetoThreshold, snapshot, token] = await client.viem.getPublicClient(params.chainId).multicall({
10460
- allowFailure: false,
10461
- contracts: [
10462
- {
10463
- address: governance,
10464
- abi: dtfIndexGovernanceOptimisticAbi,
10465
- functionName: "vetoThreshold",
10466
- args: [proposalId]
10467
- },
10468
- {
10566
+ const vetoThreshold = params.vetoThreshold;
10567
+ let snapshot = params.snapshot;
10568
+ let token = params.voteToken ? getAddress(params.voteToken) : void 0;
10569
+ if (vetoThreshold === void 0 || vetoThreshold === 0n || vetoThreshold === MAX_UINT256$1) return null;
10570
+ if (snapshot === void 0 || token === void 0) {
10571
+ const [contractSnapshot, contractToken] = await client.viem.getPublicClient(params.chainId).multicall({
10572
+ allowFailure: false,
10573
+ contracts: [{
10469
10574
  address: governance,
10470
10575
  abi: dtfIndexGovernanceOptimisticAbi,
10471
10576
  functionName: "proposalSnapshot",
10472
10577
  args: [proposalId]
10473
- },
10474
- {
10578
+ }, {
10475
10579
  address: governance,
10476
10580
  abi: dtfIndexGovernanceOptimisticAbi,
10477
10581
  functionName: "token"
10478
- }
10479
- ]
10480
- });
10582
+ }]
10583
+ });
10584
+ snapshot = snapshot ?? contractSnapshot;
10585
+ token = token ?? contractToken;
10586
+ }
10587
+ if (vetoThreshold === void 0 || snapshot === void 0 || token === void 0) throw new Error("Missing optimistic proposal context values");
10481
10588
  const mappedSnapshotSupply = mapAmount(await client.viem.readContract({
10482
10589
  chainId: params.chainId,
10483
10590
  address: token,
@@ -14676,6 +14783,9 @@ const GetIndexDtfProposalsDocument = new TypedDocumentString$1(`
14676
14783
  state
14677
14784
  isOptimistic
14678
14785
  vetoThreshold
14786
+ vetoThresholdVotes
14787
+ optimisticSnapshot
14788
+ optimisticSnapshotSupply
14679
14789
  forWeightedVotes
14680
14790
  abstainWeightedVotes
14681
14791
  againstWeightedVotes
@@ -14691,6 +14801,9 @@ const GetIndexDtfProposalsDocument = new TypedDocumentString$1(`
14691
14801
  }
14692
14802
  governance {
14693
14803
  id
14804
+ token {
14805
+ id
14806
+ }
14694
14807
  timelock {
14695
14808
  id
14696
14809
  }
@@ -14715,6 +14828,9 @@ const GetAllIndexDtfProposalsDocument = new TypedDocumentString$1(`
14715
14828
  state
14716
14829
  isOptimistic
14717
14830
  vetoThreshold
14831
+ vetoThresholdVotes
14832
+ optimisticSnapshot
14833
+ optimisticSnapshotSupply
14718
14834
  forWeightedVotes
14719
14835
  abstainWeightedVotes
14720
14836
  againstWeightedVotes
@@ -14730,6 +14846,9 @@ const GetAllIndexDtfProposalsDocument = new TypedDocumentString$1(`
14730
14846
  }
14731
14847
  governance {
14732
14848
  id
14849
+ token {
14850
+ id
14851
+ }
14733
14852
  timelock {
14734
14853
  id
14735
14854
  }
@@ -14764,16 +14883,21 @@ const GetIndexDtfProposalDocument = new TypedDocumentString$1(`
14764
14883
  }
14765
14884
  proposal(id: $proposalId) {
14766
14885
  id
14886
+ txnHash
14767
14887
  timelockId
14768
14888
  description
14769
14889
  creationTime
14770
14890
  voteStart
14771
14891
  voteEnd
14772
14892
  queueBlock
14893
+ queueTxnHash
14773
14894
  queueTime
14774
14895
  state
14775
14896
  isOptimistic
14776
14897
  vetoThreshold
14898
+ vetoThresholdVotes
14899
+ optimisticSnapshot
14900
+ optimisticSnapshotSupply
14777
14901
  executionETA
14778
14902
  executionTime
14779
14903
  executionBlock
@@ -14802,6 +14926,9 @@ const GetIndexDtfProposalDocument = new TypedDocumentString$1(`
14802
14926
  governance {
14803
14927
  id
14804
14928
  optimisticSelectorRegistry
14929
+ token {
14930
+ id
14931
+ }
14805
14932
  timelock {
14806
14933
  id
14807
14934
  type
@@ -14840,11 +14967,58 @@ const GetIndexDtfProposalDocument = new TypedDocumentString$1(`
14840
14967
  }
14841
14968
  }
14842
14969
  }`);
14970
+ const GetIndexDtfProposalChallengeDocument = new TypedDocumentString$1(`
14971
+ query GetIndexDtfProposalChallenge($governanceId: String!, $description: String!, $creationBlock: BigInt!) {
14972
+ proposals(
14973
+ first: 1
14974
+ orderBy: creationBlock
14975
+ orderDirection: desc
14976
+ where: {governance: $governanceId, description: $description, creationBlock_lte: $creationBlock, isOptimistic: true}
14977
+ ) {
14978
+ id
14979
+ }
14980
+ }
14981
+ `);
14982
+ const GetIndexDtfProposalVotingSnapshotDocument = new TypedDocumentString$1(`
14983
+ query GetIndexDtfProposalVotingSnapshot($proposalId: ID!) {
14984
+ proposal(id: $proposalId) {
14985
+ id
14986
+ state
14987
+ isOptimistic
14988
+ vetoThreshold
14989
+ vetoThresholdVotes
14990
+ optimisticSnapshot
14991
+ optimisticSnapshotSupply
14992
+ voteStart
14993
+ voteEnd
14994
+ forWeightedVotes
14995
+ againstWeightedVotes
14996
+ abstainWeightedVotes
14997
+ quorumVotes
14998
+ governance {
14999
+ id
15000
+ token {
15001
+ id
15002
+ }
15003
+ }
15004
+ votes {
15005
+ choice
15006
+ voter {
15007
+ address
15008
+ }
15009
+ weight
15010
+ }
15011
+ }
15012
+ }
15013
+ `);
14843
15014
  const GetIndexDtfDelegatesDocument = new TypedDocumentString$1(`
14844
15015
  query GetIndexDtfDelegates($stToken: ID!, $limit: Int = 10) {
14845
15016
  stakingToken(id: $stToken) {
14846
15017
  id
14847
15018
  totalDelegates
15019
+ currentDelegates
15020
+ totalOptimisticDelegates
15021
+ currentOptimisticDelegates
14848
15022
  token {
14849
15023
  totalSupply
14850
15024
  }
@@ -14852,7 +15026,7 @@ const GetIndexDtfDelegatesDocument = new TypedDocumentString$1(`
14852
15026
  first: $limit
14853
15027
  orderBy: delegatedVotes
14854
15028
  orderDirection: desc
14855
- where: {address_not: "0x0000000000000000000000000000000000000000"}
15029
+ where: {or: [{address_not: "0x0000000000000000000000000000000000000000", delegatedVotesRaw_gt: "0"}, {address_not: "0x0000000000000000000000000000000000000000", optimisticDelegatedVotesRaw_gt: "0"}]}
14856
15030
  ) {
14857
15031
  address
14858
15032
  delegatedVotesRaw
@@ -15657,1302 +15831,147 @@ async function getDelegates(client, params) {
15657
15831
  address: stToken
15658
15832
  }
15659
15833
  });
15660
- return stakingToken.delegates.map((delegate) => ({
15661
- address: getAddress(delegate.address),
15662
- delegatedVotes: mapAmount(delegate.delegatedVotesRaw),
15663
- optimisticDelegatedVotes: mapAmount(delegate.optimisticDelegatedVotesRaw),
15664
- numberVotes: Number(delegate.numberVotes),
15665
- numberOptimisticVotes: Number(delegate.numberOptimisticVotes),
15666
- hasBeenStandardDelegate: delegate.hasBeenStandardDelegate,
15667
- hasBeenOptimisticDelegate: delegate.hasBeenOptimisticDelegate,
15668
- tokenHoldersRepresentedAmount: Number(delegate.tokenHoldersRepresentedAmount),
15669
- optimisticTokenHoldersRepresentedAmount: Number(delegate.optimisticTokenHoldersRepresentedAmount)
15670
- }));
15671
- }
15672
- //#endregion
15673
- //#region src/index-dtf/governance/guardians.ts
15674
- async function getGuardians(client, params) {
15675
- const dtf = "dtf" in params ? params.dtf : await getDtf(client, params);
15676
- const owner = mapGuardianGroup(dtf.governance.admin.primary);
15677
- const basket = mapGuardianGroup(dtf.governance.rebalance.primary);
15678
- const dao = mapGuardianGroup(dtf.governance.voteLock);
15679
- return {
15680
- owner,
15681
- basket,
15682
- dao,
15683
- all: dedupeAddresses([
15684
- ...owner.guardians,
15685
- ...basket.guardians,
15686
- ...dao.guardians
15687
- ])
15688
- };
15689
- }
15690
- //#endregion
15691
- //#region src/index-dtf/governance/legacy-vote-lock.ts
15692
- async function getLegacyVoteLocks(client, params) {
15693
- const context = await getLegacyVoteLockContext(client, params);
15694
- const legacyGovernance = context?.legacyGovernance.filter((governance) => governance.toLowerCase() !== zeroAddress);
15695
- if (!context || !legacyGovernance || legacyGovernance.length === 0) return [];
15696
- const legacyVoteLocks = await Promise.all(legacyGovernance.map((governance) => readLegacyVoteLock(client, context.chainId, governance)));
15697
- const currentVoteLock = context.currentVoteLock.toLowerCase();
15698
- const result = [];
15699
- for (const voteLock of legacyVoteLocks) {
15700
- if (!voteLock) continue;
15701
- const address = voteLock;
15702
- if (address.toLowerCase() === currentVoteLock) continue;
15703
- if (!result.some((existing) => existing.toLowerCase() === address.toLowerCase())) result.push(address);
15704
- }
15705
- return result;
15706
- }
15707
- async function readLegacyVoteLock(client, chainId, governance) {
15708
- try {
15709
- return await client.viem.readContract({
15710
- chainId,
15711
- address: governance,
15712
- abi: dtfIndexGovernanceAbi,
15713
- functionName: "token"
15714
- });
15715
- } catch (error) {
15716
- if (isUnreadableLegacyGovernance(error)) return null;
15717
- throw error;
15834
+ const voteSupply = BigInt(stakingToken.token.totalSupply);
15835
+ const delegates = [];
15836
+ const normalDelegates = [];
15837
+ const optimisticDelegates = [];
15838
+ for (const delegate of stakingToken.delegates) {
15839
+ const delegatedVotes = mapAmount(delegate.delegatedVotesRaw);
15840
+ const optimisticDelegatedVotes = mapAmount(delegate.optimisticDelegatedVotesRaw);
15841
+ const mappedDelegate = {
15842
+ address: getAddress(delegate.address),
15843
+ delegatedVotes,
15844
+ optimisticDelegatedVotes,
15845
+ weightedVotes: getWeightedVotes(delegatedVotes.raw, voteSupply),
15846
+ optimisticWeightedVotes: getWeightedVotes(optimisticDelegatedVotes.raw, voteSupply),
15847
+ numberVotes: Number(delegate.numberVotes),
15848
+ numberOptimisticVotes: Number(delegate.numberOptimisticVotes),
15849
+ hasBeenStandardDelegate: delegate.hasBeenStandardDelegate,
15850
+ hasBeenOptimisticDelegate: delegate.hasBeenOptimisticDelegate,
15851
+ tokenHoldersRepresentedAmount: Number(delegate.tokenHoldersRepresentedAmount),
15852
+ optimisticTokenHoldersRepresentedAmount: Number(delegate.optimisticTokenHoldersRepresentedAmount)
15853
+ };
15854
+ delegates.push(mappedDelegate);
15855
+ if (delegatedVotes.raw > 0n) normalDelegates.push(mappedDelegate);
15856
+ if (optimisticDelegatedVotes.raw > 0n) optimisticDelegates.push(mappedDelegate);
15718
15857
  }
15719
- }
15720
- async function getLegacyVoteLockContext(client, params) {
15721
- if ("currentVoteLock" in params) return {
15722
- chainId: params.chainId,
15723
- currentVoteLock: getAddress(params.currentVoteLock),
15724
- legacyGovernance: params.legacyGovernance.map((address) => getAddress(address))
15725
- };
15726
- const dtf = "dtf" in params ? params.dtf : await getDtf(client, params);
15727
- if (!dtf.voteLockVault) return null;
15728
15858
  return {
15729
- chainId: dtf.chainId,
15730
- currentVoteLock: dtf.voteLockVault.token.address,
15731
- legacyGovernance: dtf.voteLockVault.legacyGovernance
15859
+ delegates,
15860
+ normalDelegates,
15861
+ optimisticDelegates,
15862
+ totalDelegates: Number(stakingToken.totalDelegates),
15863
+ currentDelegates: Number(stakingToken.currentDelegates),
15864
+ totalNormalDelegates: Number(stakingToken.totalDelegates),
15865
+ currentNormalDelegates: Number(stakingToken.currentDelegates),
15866
+ totalOptimisticDelegates: Number(stakingToken.totalOptimisticDelegates),
15867
+ currentOptimisticDelegates: Number(stakingToken.currentOptimisticDelegates),
15868
+ voteSupply: mapAmount(voteSupply)
15732
15869
  };
15733
15870
  }
15734
- function isUnreadableLegacyGovernance(error) {
15735
- const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
15736
- return message.includes("returned no data") || message.includes("function \"token\" reverted");
15871
+ function getWeightedVotes(votes, voteSupply) {
15872
+ if (voteSupply === 0n) return 0;
15873
+ return Number(votes) / Number(voteSupply) * 100;
15737
15874
  }
15738
15875
  //#endregion
15739
- //#region src/index-dtf/governance/proposal-actions.ts
15740
- const TIMELOCK_OPERATION_PARAMS = parseAbiParameters("address[], uint256[], bytes[], bytes32, bytes32");
15741
- function prepareIndexDtfVote(params) {
15742
- return prepareContractCall({
15743
- chainId: params.chainId,
15744
- address: params.governance,
15745
- abi: dtfIndexGovernanceAbi,
15746
- functionName: "castVote",
15747
- args: [BigInt(params.proposalId), params.support]
15748
- });
15749
- }
15750
- function prepareIndexDtfVoteWithReason(params) {
15751
- return prepareContractCall({
15752
- chainId: params.chainId,
15753
- address: params.governance,
15754
- abi: dtfIndexGovernanceAbi,
15755
- functionName: "castVoteWithReason",
15756
- args: [
15757
- BigInt(params.proposalId),
15758
- params.support,
15759
- params.reason
15760
- ]
15761
- });
15762
- }
15763
- function prepareIndexDtfVoteWithReasonAndParams(params) {
15764
- return prepareContractCall({
15765
- chainId: params.chainId,
15766
- address: params.governance,
15767
- abi: dtfIndexGovernanceAbi,
15768
- functionName: "castVoteWithReasonAndParams",
15769
- args: [
15770
- BigInt(params.proposalId),
15771
- params.support,
15772
- params.reason,
15773
- params.voteParams
15774
- ]
15775
- });
15776
- }
15777
- function prepareIndexDtfQueueProposal(params) {
15778
- const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
15779
- return prepareContractCall({
15780
- chainId: params.chainId,
15781
- address: params.proposal.governance,
15782
- abi: dtfIndexGovernanceAbi,
15783
- functionName: "queue",
15784
- args: [
15785
- targets,
15786
- values,
15787
- calldatas,
15788
- descriptionHash
15789
- ]
15790
- });
15791
- }
15792
- function prepareIndexDtfExecuteProposal(params) {
15793
- const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
15794
- return prepareContractCall({
15795
- chainId: params.chainId,
15796
- address: params.proposal.governance,
15797
- abi: dtfIndexGovernanceAbi,
15798
- functionName: "execute",
15799
- args: [
15800
- targets,
15801
- values,
15802
- calldatas,
15803
- descriptionHash
15804
- ]
15805
- });
15806
- }
15807
- function prepareIndexDtfCancelProposal(params) {
15808
- if (!params.proposal.timelock) throw new SdkError({
15809
- code: "INVALID_INPUT",
15810
- message: "timelock is required to cancel a proposal"
15811
- });
15812
- return prepareContractCall({
15813
- chainId: params.chainId,
15814
- address: params.proposal.timelock,
15815
- abi: timelockAbi,
15816
- functionName: "cancel",
15817
- args: [getTimelockOperationId(params.proposal)]
15818
- });
15819
- }
15820
- function prepareIndexDtfGovernorCancelProposal(params) {
15821
- const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
15822
- return prepareContractCall({
15823
- chainId: params.chainId,
15824
- address: params.proposal.governance,
15825
- abi: dtfIndexGovernanceAbi,
15826
- functionName: "cancel",
15827
- args: [
15828
- targets,
15829
- values,
15830
- calldatas,
15831
- descriptionHash
15832
- ]
15833
- });
15834
- }
15835
- function prepareIndexDtfSubmitProposal(params) {
15836
- const targets = params.proposal.targets;
15837
- const calldatas = [...params.proposal.calldatas];
15838
- const values = getZeroValues(targets.length);
15839
- return prepareContractCall({
15840
- chainId: params.chainId,
15841
- address: params.proposal.governance,
15842
- abi: dtfIndexGovernanceAbi,
15843
- functionName: "propose",
15844
- args: [
15845
- targets,
15846
- values,
15847
- calldatas,
15848
- params.proposal.description
15849
- ]
15850
- });
15851
- }
15852
- function prepareIndexDtfSubmitOptimisticProposal(params) {
15853
- const targets = params.proposal.targets;
15854
- const calldatas = [...params.proposal.calldatas];
15855
- const values = getZeroValues(targets.length);
15856
- return prepareContractCall({
15857
- chainId: params.chainId,
15858
- address: params.proposal.governance,
15859
- abi: dtfIndexGovernanceOptimisticAbi,
15860
- functionName: "proposeOptimistic",
15861
- args: [
15862
- targets,
15863
- values,
15864
- calldatas,
15865
- params.proposal.description
15866
- ]
15867
- });
15868
- }
15869
- function getProposalTxArgs(proposal) {
15870
- const targets = proposal.targets;
15871
- return [
15872
- targets,
15873
- getZeroValues(targets.length),
15874
- [...proposal.calldatas],
15875
- hashIndexDtfProposalDescription(proposal.description)
15876
- ];
15877
- }
15878
- function hashIndexDtfProposalDescription(description) {
15879
- return keccak256(toBytes(description));
15880
- }
15881
- function getTimelockOperationId(proposal) {
15882
- if (proposal.timelockId) return proposal.timelockId;
15883
- return calculateLegacyTimelockOperationId(proposal);
15884
- }
15885
- function calculateLegacyTimelockOperationId(proposal) {
15886
- const targets = proposal.targets;
15887
- return keccak256(encodeAbiParameters(TIMELOCK_OPERATION_PARAMS, [
15888
- targets,
15889
- getZeroValues(targets.length),
15890
- [...proposal.calldatas],
15891
- zeroHash,
15892
- getTimelockSalt(proposal.governance, proposal.description)
15893
- ]));
15894
- }
15895
- function getTimelockSalt(governance, description) {
15896
- const governorBytes = hexToBytes(pad(getAddress(governance).toLowerCase(), {
15897
- size: 32,
15898
- dir: "right"
15899
- }));
15900
- const descriptionHashBytes = hexToBytes(keccak256(toBytes(description)));
15901
- const saltBytes = new Uint8Array(32);
15902
- for (let i = 0; i < saltBytes.length; i++) saltBytes[i] = governorBytes[i] ^ descriptionHashBytes[i];
15903
- return bytesToHex(saltBytes);
15904
- }
15905
- const TARGET_BASKET_TOLERANCE = 10n ** 13n;
15906
- const PRICE_ERROR_BY_VOLATILITY = {
15907
- low: .25,
15908
- medium: .5,
15909
- high: .75,
15910
- degen: .9
15911
- };
15912
- const indexDtfBasketTokenSchema = z.object({
15913
- address: z.string().refine(isAddress, "Invalid address"),
15914
- decimals: z.number().int().min(0).max(255).optional(),
15915
- price: z.number().positive().optional(),
15916
- priceError: z.number().min(0).max(.9).optional(),
15917
- priceVolatility: z.enum([
15918
- "low",
15919
- "medium",
15920
- "high",
15921
- "degen"
15922
- ]).optional(),
15923
- maxAuctionSizeUsd: z.number().positive().optional()
15924
- });
15925
- const indexDtfBasketSharesSchema = z.object({
15926
- type: z.literal("shares"),
15927
- tokens: z.array(indexDtfBasketTokenSchema.extend({ share: z.union([z.string(), z.number()]) }))
15928
- });
15929
- const indexDtfBasketUnitsSchema = z.object({
15930
- type: z.literal("units"),
15931
- tokens: z.array(indexDtfBasketTokenSchema.extend({ units: z.union([z.string(), z.number()]) }))
15932
- });
15933
- const indexDtfBasketSchema = z.union([indexDtfBasketSharesSchema, indexDtfBasketUnitsSchema]);
15934
- //#endregion
15935
- //#region src/index-dtf/dtf/basket/validation.ts
15936
- function validateBasketTokens(tokens) {
15937
- if (tokens.length === 0) throw new SdkError({
15938
- code: "INVALID_INPUT",
15939
- message: "Basket must include at least one token"
15940
- });
15941
- assertUniqueAddresses(tokens.map((token) => token.address));
15942
- assertValidBasketAddresses(tokens.map((token) => token.address));
15943
- for (const token of tokens) {
15944
- if (!Number.isInteger(token.decimals) || token.decimals < 0) throw new SdkError({
15945
- code: "INVALID_INPUT",
15946
- message: `Invalid decimals for token ${token.address}`,
15947
- meta: {
15948
- address: token.address,
15949
- decimals: token.decimals
15950
- }
15951
- });
15952
- assertPositiveNumber(token.price, `price for token ${token.address}`);
15953
- }
15954
- }
15955
- function assertValidBasketAddresses(addresses) {
15956
- for (const address of addresses) if (address.toLowerCase() === zeroAddress) throw new SdkError({
15957
- code: "INVALID_INPUT",
15958
- message: "Basket token address cannot be the zero address",
15959
- meta: { address }
15960
- });
15961
- }
15962
- function assertNoDtfBasketToken(dtfAddress, tokens) {
15963
- const dtfKey = dtfAddress.toLowerCase();
15964
- for (const token of tokens) if (token.toLowerCase() === dtfKey) throw new SdkError({
15965
- code: "INVALID_INPUT",
15966
- message: "Basket token cannot be the DTF address",
15967
- meta: {
15968
- address: token,
15969
- dtfAddress
15970
- }
15971
- });
15972
- }
15973
- function validateShares(shares) {
15974
- let total = 0n;
15975
- for (const share of shares) {
15976
- if (share < 0n) throw new SdkError({
15977
- code: "INVALID_INPUT",
15978
- message: "Basket shares must be non-negative"
15979
- });
15980
- total += share;
15981
- }
15982
- if (total < D18n - TARGET_BASKET_TOLERANCE || total > D18n + TARGET_BASKET_TOLERANCE) throw new SdkError({
15983
- code: "INVALID_INPUT",
15984
- message: "Basket shares must add up to 100%",
15985
- meta: { total }
15986
- });
15987
- }
15988
- function assertUniqueAddresses(addresses) {
15989
- const seen = /* @__PURE__ */ new Set();
15990
- for (const address of addresses) {
15991
- const key = getAddress(address).toLowerCase();
15992
- if (seen.has(key)) throw new SdkError({
15993
- code: "INVALID_INPUT",
15994
- message: `Duplicate basket token ${address}`,
15995
- meta: { address }
15996
- });
15997
- seen.add(key);
15998
- }
15999
- }
16000
- function assertPositiveNumber(value, field) {
16001
- if (!Number.isFinite(value) || value <= 0) throw new SdkError({
16002
- code: "INVALID_INPUT",
16003
- message: `${field} must be a positive number`,
16004
- meta: { [field]: value }
16005
- });
16006
- }
16007
- //#endregion
16008
- //#region src/index-dtf/dtf/basket/math.ts
16009
- function getBasketSharesFromUnits(params) {
16010
- validateBasketTokens(params.tokens);
16011
- let hasValue = false;
16012
- for (const unit of params.units) {
16013
- if (unit < 0n) throw new SdkError({
16014
- code: "INVALID_INPUT",
16015
- message: "Basket units must be non-negative"
16016
- });
16017
- if (unit > 0n) hasValue = true;
16018
- }
16019
- if (!hasValue) throw new SdkError({
16020
- code: "INVALID_INPUT",
16021
- message: "Basket units must include at least one positive amount"
16022
- });
16023
- return getBasketDistribution([...params.units], params.tokens.map((token) => token.price), params.tokens.map((token) => BigInt(token.decimals)));
16024
- }
16025
- function getBasketUnitsFromShares(params) {
16026
- assertPositiveNumber(params.targetValueUsd, "targetValueUsd");
16027
- validateBasketTokens(params.tokens);
16028
- validateShares(params.shares);
16029
- return getUnitsFromShares(params.tokens, params.shares, new Decimal(params.targetValueUsd.toString()));
16030
- }
16031
- function getDtfPriceFromBalances(params) {
16032
- if (params.supply <= 0n) throw new SdkError({
16033
- code: "INVALID_INPUT",
16034
- message: "supply must be positive",
16035
- meta: { supply: params.supply }
16036
- });
16037
- validateBasketTokens(params.tokens);
16038
- const totalValue = params.tokens.reduce((sum, token, index) => {
16039
- const wholeTokens = new Decimal(params.balances[index].toString()).div(new Decimal(`1e${token.decimals}`));
16040
- return sum.add(wholeTokens.mul(token.price));
16041
- }, new Decimal(0));
16042
- const supply = new Decimal(params.supply.toString()).div(D18d);
16043
- return totalValue.div(supply).toNumber();
16044
- }
16045
- function buildInitialBasket(params) {
16046
- assertPositiveNumber(params.initialSharePriceUsd, "initialSharePriceUsd");
16047
- if (params.initialShares <= 0n) throw new SdkError({
16048
- code: "INVALID_INPUT",
16049
- message: "initialShares must be positive",
16050
- meta: { initialShares: params.initialShares }
16051
- });
16052
- validateBasketTokens(params.tokens);
16053
- const shares = getBasketShares(params.tokens, params.basket);
16054
- const amounts = params.basket.type === "units" ? getScaledUnits(params.tokens, params.basket.units, getInitialValueUsd(params)) : getUnitsFromShares(params.tokens, shares, getInitialValueUsd(params));
16055
- for (const amount of amounts) if (amount <= 0n) throw new SdkError({
16056
- code: "INVALID_INPUT",
16057
- message: "Initial basket amounts must be positive"
16058
- });
16059
- return {
16060
- assets: params.tokens.map((token) => token.address),
16061
- amounts,
16062
- initialShares: params.initialShares,
16063
- shares
16064
- };
16065
- }
16066
- function getBasketShares(tokens, basket) {
16067
- if (basket.type === "shares") {
16068
- validateShares(basket.shares);
16069
- return [...basket.shares];
16070
- }
16071
- return getBasketSharesFromUnits({
16072
- tokens,
16073
- units: basket.units
16074
- });
16075
- }
16076
- function getInitialValueUsd(params) {
16077
- return new Decimal(params.initialShares.toString()).div(D18d).mul(params.initialSharePriceUsd);
16078
- }
16079
- function getUnitsFromShares(tokens, shares, targetValueUsd) {
16080
- return tokens.map((token, index) => {
16081
- return parseUnits(targetValueUsd.mul(new Decimal(shares[index].toString()).div(D18d)).div(token.price).toFixed(token.decimals), token.decimals);
16082
- });
16083
- }
16084
- function getScaledUnits(tokens, units, targetValueUsd) {
16085
- const currentValueUsd = units.reduce((sum, unit, index) => {
16086
- const token = tokens[index];
16087
- const wholeTokens = new Decimal(unit.toString()).div(new Decimal(`1e${token.decimals}`));
16088
- return sum.add(wholeTokens.mul(token.price));
16089
- }, new Decimal(0));
16090
- if (currentValueUsd.lte(0)) throw new SdkError({
16091
- code: "INVALID_INPUT",
16092
- message: "Basket units must have positive USD value"
16093
- });
16094
- const scale = targetValueUsd.div(currentValueUsd);
16095
- return units.map((unit) => BigInt(new Decimal(unit.toString()).mul(scale).toFixed(0)));
16096
- }
16097
- //#endregion
16098
- //#region src/index-dtf/dtf/basket/rebalance-args.ts
16099
- function buildStartRebalanceArgs(params) {
16100
- if (params.supply <= 0n) throw new SdkError({
16101
- code: "INVALID_INPUT",
16102
- message: "supply must be positive",
16103
- meta: { supply: params.supply }
16104
- });
16105
- if (params.deferWeights && !params.weightControl) throw new SdkError({
16106
- code: "INVALID_INPUT",
16107
- message: "deferWeights is only supported for weight-control baskets"
16108
- });
16109
- validateBasketTokens(params.tokens);
16110
- const targetShares = getBasketShares(params.tokens, params.basket);
16111
- for (const priceError of params.priceErrors) if (priceError < 0 || priceError > .9) throw new SdkError({
16112
- code: "INVALID_INPUT",
16113
- message: "priceErrors must be between 0 and 0.9",
16114
- meta: { priceError }
16115
- });
16116
- for (const maxAuctionSizeUsd of params.maxAuctionSizesUsd) assertPositiveNumber(maxAuctionSizeUsd, "maxAuctionSizeUsd");
16117
- return getStartRebalance(FolioVersion.V5, params.supply, params.tokens.map((token) => token.address), [...params.balances], params.tokens.map((token) => BigInt(token.decimals)), targetShares, params.tokens.map((token) => token.price), [...params.priceErrors], [...params.maxAuctionSizesUsd], params.weightControl, params.deferWeights ?? false);
16118
- }
16119
- //#endregion
16120
- //#region src/index-dtf/dtf/basket/current.ts
16121
- async function getCurrentBalances(client, params) {
16122
- return normalizeCurrentBalances(params.currentBalances ?? await getTotalAssets(client, params));
16123
- }
16124
- async function getDtfForWeightControl(client, params) {
16125
- if (params.weightControl !== void 0) return params.dtf;
16126
- return params.dtf ?? getDtf(client, params);
16127
- }
16128
- function getBasketTokenOrder(currentBalances, inputTokens) {
16129
- const addresses = [];
16130
- const seen = /* @__PURE__ */ new Set();
16131
- const add = (token) => {
16132
- const address = getAddress(token);
16133
- const key = address.toLowerCase();
16134
- if (!seen.has(key)) {
16135
- seen.add(key);
16136
- addresses.push(address);
16137
- }
16138
- };
16139
- for (const token of Object.keys(currentBalances)) add(token);
16140
- for (const token of inputTokens) add(token.address);
16141
- return addresses;
16142
- }
16143
- function normalizeCurrentBalances(input) {
16144
- if (Array.isArray(input)) {
16145
- const result = {};
16146
- for (const item of input) result[getAddress(item.address).toLowerCase()] = item.balance;
16147
- return result;
16148
- }
16149
- if (isTotalAssetsInput(input)) {
16150
- const result = {};
16151
- for (let i = 0; i < input.tokens.length; i++) result[getAddress(input.tokens[i]).toLowerCase()] = input.balances[i] ?? 0n;
16152
- return result;
16153
- }
16154
- const result = {};
16155
- for (const [token, balance] of Object.entries(input)) result[getAddress(token).toLowerCase()] = balance;
16156
- return result;
16157
- }
16158
- function isTotalAssetsInput(input) {
16159
- if (Array.isArray(input)) return false;
16160
- const value = input;
16161
- return Array.isArray(value.tokens) && Array.isArray(value.balances);
16162
- }
16163
- //#endregion
16164
- //#region src/index-dtf/dtf/basket/input.ts
16165
- function getBasketFromInput(input, tokenOrder, tokens) {
16166
- const inputByAddress = new Map(input.tokens.map((token) => [getAddress(token.address).toLowerCase(), token]));
16167
- if (input.type === "shares") {
16168
- const shares = tokenOrder.map((address) => {
16169
- const token = inputByAddress.get(address.toLowerCase());
16170
- return token && "share" in token ? parseShare(token.share) : 0n;
16171
- });
16172
- validateShares(shares);
16173
- return {
16174
- type: "shares",
16175
- shares
16176
- };
16177
- }
16178
- return {
16179
- type: "units",
16180
- units: tokenOrder.map((address, index) => {
16181
- const token = inputByAddress.get(address.toLowerCase());
16182
- return token && "units" in token ? parseTokenUnits(token.units, tokens[index].decimals) : 0n;
16183
- })
16184
- };
16185
- }
16186
- function parseTokenUnits(value, decimals) {
16187
- const units = toDecimal(value, "units");
16188
- if (units.isNegative()) throw new SdkError({
16189
- code: "INVALID_INPUT",
16190
- message: "Basket token units must be non-negative",
16191
- meta: { units: value }
16192
- });
16193
- return parseUnits(units.toFixed(decimals), decimals);
16194
- }
16195
- function parseShare(value) {
16196
- const share = toDecimal(value, "share");
16197
- if (share.isNegative() || share.gt(100)) throw new SdkError({
16198
- code: "INVALID_INPUT",
16199
- message: "Basket token shares must be between 0 and 100",
16200
- meta: { share: value }
16201
- });
16202
- return parseUnits(share.toFixed(16), 16);
16203
- }
16204
- function toDecimal(value, field) {
16205
- try {
16206
- return new Decimal(String(value));
16207
- } catch (cause) {
16208
- throw new SdkError({
16209
- code: "INVALID_INPUT",
16210
- message: `${field} must be a valid number`,
16211
- cause,
16212
- meta: { [field]: value }
16213
- });
16214
- }
16215
- }
16216
- //#endregion
16217
- //#region src/index-dtf/dtf/basket/token-data.ts
16218
- async function getBasketTokens(client, params, tokenOrder, inputTokens) {
16219
- const fetchedTokens = await getTokensData(client.viem.getPublicClient(params.chainId), [...tokenOrder]);
16220
- const decimalsByAddress = /* @__PURE__ */ new Map();
16221
- for (const [address, decimals] of Object.entries(params.tokenDecimals ?? {})) decimalsByAddress.set(getAddress(address).toLowerCase(), decimals);
16222
- for (const token of inputTokens) if (token.decimals !== void 0) decimalsByAddress.set(token.address.toLowerCase(), token.decimals);
16223
- return fetchedTokens.map((token) => ({
16224
- ...token,
16225
- decimals: decimalsByAddress.get(token.address.toLowerCase()) ?? token.decimals
16226
- }));
16227
- }
16228
- async function getBasketPrices(client, params, tokenOrder, inputTokens) {
16229
- const prices = /* @__PURE__ */ new Map();
16230
- for (const [address, price] of Object.entries(params.prices ?? {})) prices.set(getAddress(address).toLowerCase(), price);
16231
- for (const token of inputTokens) if (token.price !== void 0) prices.set(token.address.toLowerCase(), token.price);
16232
- const missing = tokenOrder.filter((address) => prices.get(address.toLowerCase()) === void 0);
16233
- if (missing.length > 0) {
16234
- const fetchedPrices = await getTokenPrices(client, {
16235
- chainId: params.chainId,
16236
- addresses: missing
16237
- });
16238
- for (const token of fetchedPrices) prices.set(token.address.toLowerCase(), token.price);
16239
- }
16240
- return tokenOrder.map((address) => {
16241
- const price = prices.get(address.toLowerCase());
16242
- if (price === void 0 || !Number.isFinite(price) || price <= 0) throw new SdkError({
16243
- code: "INVALID_INPUT",
16244
- message: `Missing price for token ${address}`,
16245
- meta: {
16246
- address,
16247
- chainId: params.chainId
16248
- }
16249
- });
16250
- return price;
16251
- });
16252
- }
16253
- async function getBasketPriceErrors(client, params, tokenOrder, inputTokens) {
16254
- const explicitErrors = /* @__PURE__ */ new Map();
16255
- const explicitVolatilities = /* @__PURE__ */ new Map();
16256
- for (const [address, priceError] of Object.entries(params.priceErrors ?? {})) explicitErrors.set(getAddress(address).toLowerCase(), priceError);
16257
- for (const [address, volatility] of Object.entries(params.priceVolatilities ?? {})) explicitVolatilities.set(getAddress(address).toLowerCase(), volatility);
16258
- for (const token of inputTokens) {
16259
- if (token.priceError !== void 0) explicitErrors.set(token.address.toLowerCase(), token.priceError);
16260
- if (token.priceVolatility !== void 0) explicitVolatilities.set(token.address.toLowerCase(), token.priceVolatility);
16261
- }
16262
- const missingVolatility = tokenOrder.filter((address) => {
16263
- const key = address.toLowerCase();
16264
- return !explicitErrors.has(key) && !explicitVolatilities.has(key);
16265
- });
16266
- const fetchedVolatilities = missingVolatility.length > 0 ? await getTokenVolatilities(client, {
16267
- chainId: params.chainId,
16268
- addresses: missingVolatility
16269
- }) : {};
16270
- const fetchedVolatilityByAddress = new Map(Object.entries(fetchedVolatilities).map(([address, volatility]) => [address.toLowerCase(), volatility]));
16271
- return tokenOrder.map((address) => {
16272
- const key = address.toLowerCase();
16273
- const volatility = explicitVolatilities.get(key) ?? fetchedVolatilityByAddress.get(key) ?? "medium";
16274
- const priceError = explicitErrors.get(key) ?? PRICE_ERROR_BY_VOLATILITY[volatility];
16275
- if (priceError < 0 || priceError > .9) throw new SdkError({
16276
- code: "INVALID_INPUT",
16277
- message: `Invalid price error for token ${address}`,
16278
- meta: {
16279
- address,
16280
- priceError
16281
- }
16282
- });
16283
- return priceError;
16284
- });
16285
- }
16286
- function getMaxAuctionSizes(params, tokenOrder, inputTokens) {
16287
- const inputByAddress = new Map(inputTokens.map((token) => [token.address.toLowerCase(), token]));
16288
- const sizes = /* @__PURE__ */ new Map();
16289
- for (const [address, size] of Object.entries(params.maxAuctionSizesUsd ?? {})) sizes.set(getAddress(address).toLowerCase(), size);
16290
- return tokenOrder.map((address) => {
16291
- const key = address.toLowerCase();
16292
- const size = inputByAddress.get(key)?.maxAuctionSizeUsd ?? sizes.get(key) ?? params.maxAuctionSizeUsd ?? 1e6;
16293
- assertPositiveNumber(size, "maxAuctionSizeUsd");
16294
- return size;
16295
- });
16296
- }
16297
- //#endregion
16298
- //#region src/index-dtf/dtf/basket/start-rebalance.ts
16299
- async function buildIndexDtfStartRebalance(client, params) {
16300
- const address = getAddress(params.address);
16301
- const inputTokens = params.basket.tokens.map((token) => ({
16302
- ...token,
16303
- address: getAddress(token.address)
16304
- }));
16305
- assertUniqueAddresses(inputTokens.map((token) => token.address));
16306
- assertValidBasketAddresses(inputTokens.map((token) => token.address));
16307
- assertNoDtfBasketToken(address, inputTokens.map((token) => token.address));
16308
- const [currentBalances, supply, dtf] = await Promise.all([
16309
- getCurrentBalances(client, params),
16310
- params.supply ?? getTotalSupply(client, params),
16311
- getDtfForWeightControl(client, params)
16312
- ]);
16313
- const tokenOrder = getBasketTokenOrder(currentBalances, inputTokens);
16314
- assertValidBasketAddresses(tokenOrder);
16315
- assertNoDtfBasketToken(address, tokenOrder);
16316
- const [tokens, prices] = await Promise.all([getBasketTokens(client, params, tokenOrder, inputTokens), getBasketPrices(client, params, tokenOrder, inputTokens)]);
16317
- const pricedTokens = tokens.map((token, index) => ({
16318
- ...token,
16319
- price: prices[index]
16320
- }));
16321
- const targetBasket = getBasketFromInput(params.basket, tokenOrder, pricedTokens);
16322
- const [priceErrors, maxAuctionSizesUsd] = await Promise.all([getBasketPriceErrors(client, params, tokenOrder, inputTokens), Promise.resolve(getMaxAuctionSizes(params, tokenOrder, inputTokens))]);
16323
- const weightControl = params.weightControl ?? dtf?.rebalance.weightControl;
16324
- if (weightControl === void 0) throw new SdkError({
16325
- code: "INVALID_INPUT",
16326
- message: "weightControl is required when DTF context is not provided",
16327
- meta: {
16328
- address,
16329
- chainId: params.chainId
16330
- }
16331
- });
16332
- const balances = tokenOrder.map((token) => currentBalances[token.toLowerCase()] ?? 0n);
16333
- const targetShares = getBasketShares(pricedTokens, targetBasket);
16334
- return {
16335
- address,
16336
- chainId: params.chainId,
16337
- tokens: pricedTokens,
16338
- assets: pricedTokens.map((token, index) => ({
16339
- token,
16340
- currentBalance: balances[index],
16341
- targetShare: targetShares[index],
16342
- priceError: priceErrors[index],
16343
- maxAuctionSizeUsd: maxAuctionSizesUsd[index]
16344
- })),
16345
- supply,
16346
- weightControl,
16347
- deferWeights: params.deferWeights ?? false,
16348
- startRebalanceArgs: buildStartRebalanceArgs({
16349
- tokens: pricedTokens,
16350
- supply,
16351
- balances,
16352
- basket: targetBasket,
16353
- priceErrors,
16354
- maxAuctionSizesUsd,
16355
- weightControl,
16356
- deferWeights: params.deferWeights ?? false
16357
- })
16358
- };
16359
- }
16360
- //#endregion
16361
- //#region src/index-dtf/governance/propose/basket.ts
16362
- const MAX_REBALANCE_TTL = 604800n * 4n;
16363
- async function buildIndexDtfBasketProposal(client, params) {
16364
- const windows = getRebalanceWindows(params);
16365
- validateBasketTokenAddresses(params);
16366
- const dtf = await getDtfForProposal(client, params);
16367
- const context = {
16368
- ...await buildIndexDtfStartRebalance(client, {
16369
- ...params,
16370
- ...dtf ? { dtf } : {}
16371
- }),
16372
- chainId: params.chainId,
16373
- ...windows
16374
- };
16375
- const authority = getProposalAuthority(params, dtf);
16376
- const call = prepareIndexDtfBasketRebalance(context);
16377
- return {
16378
- governance: authority.governance,
16379
- targets: [call.to],
16380
- calldatas: [call.data],
16381
- description: params.description ?? "",
16382
- context
16383
- };
16384
- }
16385
- function prepareIndexDtfBasketRebalance(context) {
16386
- const args = getStartRebalanceArgs(context);
16387
- return prepareContractCall({
16388
- chainId: context.chainId,
16389
- address: context.address,
16390
- abi: dtfIndexAbi,
16391
- functionName: "startRebalance",
16392
- args
16393
- });
16394
- }
16395
- async function getDtfForProposal(client, params) {
16396
- if (params.dtf || params.governance && params.weightControl !== void 0) return params.dtf;
16397
- return getDtf(client, params);
16398
- }
16399
- function getStartRebalanceArgs(context) {
16400
- const startRebalanceArgs = context.startRebalanceArgs;
16401
- return [
16402
- startRebalanceArgs.tokens.map((token) => ({
16403
- ...token,
16404
- token: getAddress(token.token)
16405
- })),
16406
- startRebalanceArgs.limits,
16407
- context.auctionLauncherWindow,
16408
- context.ttl
16409
- ];
16410
- }
16411
- function getProposalAuthority(params, dtf) {
16412
- const authority = dtf?.governance.rebalance.primary;
16413
- const resolvedGovernance = params.governance ?? (authority?.type === "governance" ? authority.address : void 0);
16414
- if (!resolvedGovernance) throw new SdkError({
16415
- code: "INVALID_INPUT",
16416
- message: "governance is required to build an Index DTF basket proposal",
16417
- meta: { governance: resolvedGovernance }
16418
- });
16419
- return { governance: resolvedGovernance };
16420
- }
16421
- function validateBasketTokenAddresses(params) {
16422
- const dtfAddress = getAddress(params.address);
16423
- for (const token of params.basket.tokens) {
16424
- const address = getAddress(token.address);
16425
- if (address.toLowerCase() === zeroAddress) throw new SdkError({
16426
- code: "INVALID_INPUT",
16427
- message: "Basket token address cannot be the zero address",
16428
- meta: { address }
16429
- });
16430
- if (address.toLowerCase() === dtfAddress.toLowerCase()) throw new SdkError({
16431
- code: "INVALID_INPUT",
16432
- message: "Basket token cannot be the DTF address",
16433
- meta: {
16434
- address,
16435
- dtfAddress
16436
- }
16437
- });
16438
- }
16439
- }
16440
- function getRebalanceWindows(params) {
16441
- const auctionLauncherWindow = toSeconds(params.auctionLauncherWindow ?? 259200, "auctionLauncherWindow");
16442
- const ttl = params.ttl === void 0 ? auctionLauncherWindow + toSeconds(params.permissionlessWindow ?? 0, "permissionlessWindow") : toSeconds(params.ttl, "ttl", { allowZero: false });
16443
- if (ttl === 0n) throw new SdkError({
16444
- code: "INVALID_INPUT",
16445
- message: "ttl must be a positive number of seconds",
16446
- meta: { ttl }
16447
- });
16448
- if (ttl < auctionLauncherWindow) throw new SdkError({
16449
- code: "INVALID_INPUT",
16450
- message: "ttl must be greater than or equal to auctionLauncherWindow",
16451
- meta: {
16452
- ttl,
16453
- auctionLauncherWindow
16454
- }
16455
- });
16456
- if (ttl > MAX_REBALANCE_TTL) throw new SdkError({
16457
- code: "INVALID_INPUT",
16458
- message: "ttl must be less than or equal to 4 weeks",
16459
- meta: {
16460
- ttl,
16461
- maxTtl: MAX_REBALANCE_TTL
16462
- }
16463
- });
16464
- return {
16465
- auctionLauncherWindow,
16466
- ttl
16467
- };
16468
- }
16469
- function toSeconds(value, field, options = {}) {
16470
- const allowZero = options.allowZero ?? true;
16471
- if (typeof value === "bigint") {
16472
- if (value < 0n || !allowZero && value === 0n) throw new SdkError({
16473
- code: "INVALID_INPUT",
16474
- message: `${field} must be a ${allowZero ? "non-negative" : "positive"} number of seconds`,
16475
- meta: { [field]: value }
16476
- });
16477
- return value;
16478
- }
16479
- if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || !allowZero && value === 0) throw new SdkError({
16480
- code: "INVALID_INPUT",
16481
- message: `${field} must be a ${allowZero ? "non-negative" : "positive"} number of seconds`,
16482
- meta: { [field]: value }
16483
- });
16484
- return BigInt(value);
16485
- }
16486
- //#endregion
16487
- //#region src/index-dtf/governance/propose/settings-governance.ts
16488
- function buildGovernanceCalls({ changes, chainId, governance, quorumDenominator, timelock }) {
16489
- if (!changes) return [];
16490
- if (!governance) throw new SdkError({
16491
- code: "INVALID_INPUT",
16492
- message: "governance is required to build governance settings calls"
16493
- });
16494
- validateGovernanceChanges(changes);
16495
- const calls = [];
16496
- if (changes.votingDelay !== void 0) calls.push(prepareContractCall({
16497
- chainId,
16498
- address: governance,
16499
- abi: dtfIndexGovernanceAbi,
16500
- functionName: "setVotingDelay",
16501
- args: [changes.votingDelay]
16502
- }));
16503
- if (changes.votingPeriod !== void 0) calls.push(prepareContractCall({
16504
- chainId,
16505
- address: governance,
16506
- abi: dtfIndexGovernanceAbi,
16507
- functionName: "setVotingPeriod",
16508
- args: [changes.votingPeriod]
16509
- }));
16510
- if (changes.proposalThreshold !== void 0) calls.push(prepareContractCall({
16511
- chainId,
16512
- address: governance,
16513
- abi: dtfIndexGovernanceAbi,
16514
- functionName: "setProposalThreshold",
16515
- args: [encodePercent(changes.proposalThreshold)]
16516
- }));
16517
- if (changes.quorumPercent !== void 0) {
16518
- if (quorumDenominator === void 0) throw new SdkError({
16519
- code: "INVALID_INPUT",
16520
- message: "quorumDenominator is required to build a quorum proposal"
16521
- });
16522
- calls.push(prepareContractCall({
16523
- chainId,
16524
- address: governance,
16525
- abi: dtfIndexGovernanceAbi,
16526
- functionName: "updateQuorumNumerator",
16527
- args: [getQuorumNumerator(changes.quorumPercent, quorumDenominator)]
16528
- }));
16529
- }
16530
- if (changes.executionDelay !== void 0) {
16531
- if (!timelock) throw new SdkError({
16532
- code: "INVALID_INPUT",
16533
- message: "timelock is required to build an execution delay proposal"
16534
- });
16535
- const functionName = "updateDelay";
16536
- const args = [BigInt(Math.round(changes.executionDelay))];
16537
- calls.push(prepareContractCall({
16538
- chainId,
16539
- address: timelock,
16540
- abi: timelockAbi,
16541
- functionName,
16542
- args
16543
- }));
16544
- }
16545
- return calls;
16546
- }
16547
- function validateGovernanceChanges(changes) {
16548
- if (changes.votingDelay !== void 0) assertNumberRange(changes.votingDelay, "votingDelay", 0);
16549
- if (changes.votingPeriod !== void 0) assertNumberRange(changes.votingPeriod, "votingPeriod", 0);
16550
- if (changes.proposalThreshold !== void 0) assertNumberRange(changes.proposalThreshold, "proposalThreshold", 0, 100);
16551
- if (changes.quorumPercent !== void 0) assertNumberRange(changes.quorumPercent, "quorumPercent", 0, 100);
16552
- if (changes.executionDelay !== void 0) assertNumberRange(changes.executionDelay, "executionDelay", 0);
16553
- }
16554
- function assertNumberRange(value, field, min, max) {
16555
- if (!Number.isFinite(value) || value < min || max !== void 0 && value > max) throw new SdkError({
16556
- code: "INVALID_INPUT",
16557
- message: max === void 0 ? `${field} must be greater than or equal to ${min}` : `${field} must be between ${min} and ${max}`,
16558
- meta: { [field]: value }
16559
- });
16560
- }
16561
- function encodePercent(percentage) {
16562
- return parseEther(new Decimal$1(percentage).div(100).toFixed());
16563
- }
16564
- function getQuorumNumerator(percent, denominator) {
16565
- const basisPoints = Math.round(percent * 100);
16566
- return BigInt(basisPoints) * BigInt(denominator) / 10000n;
16567
- }
16568
- //#endregion
16569
- //#region src/index-dtf/governance/propose/settings-roles.ts
16570
- const GUARDIAN_ROLE = "0xfd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783";
16571
- const BRAND_MANAGER_ROLE = "0x2d8e650da9bd8c373ab2450d770f2ed39549bfc28d3630025cecc51511bcd374";
16572
- const AUCTION_LAUNCHER_ROLE = "0x13ff1b2625181b311f257c723b5e6d366eb318b212d9dd694c48fcf227659df5";
16573
- const CANCELLER_ROLE$1 = keccak256(toBytes("CANCELLER_ROLE"));
16574
- function buildRoleDiffCalls({ abi, chainId, current, next, role, target }) {
16575
- if (!next) return [];
16576
- if (!target) throw new SdkError({
16577
- code: "INVALID_INPUT",
16578
- message: "target is required to build role calls",
16579
- meta: { role }
16580
- });
16581
- const calls = [];
16582
- for (const address of current) if (!next.some((nextAddress) => sameAddress(nextAddress, address))) calls.push(prepareRoleCall(chainId, target, abi, "revokeRole", role, address));
16583
- for (const address of next) if (!current.some((currentAddress) => sameAddress(currentAddress, address))) calls.push(prepareRoleCall(chainId, target, abi, "grantRole", role, address));
16584
- return calls;
16585
- }
16586
- function prepareRoleCall(chainId, target, abi, functionName, role, address) {
16587
- const args = [role, address];
16588
- if (abi === timelockAbi) return prepareContractCall({
16589
- chainId,
16590
- address: target,
16591
- abi: timelockAbi,
16592
- functionName,
16593
- args
16594
- });
16595
- return prepareContractCall({
16596
- chainId,
16597
- address: target,
16598
- abi: dtfIndexAbi,
16599
- functionName,
16600
- args
16601
- });
16602
- }
16603
- //#endregion
16604
- //#region src/index-dtf/governance/propose/settings-shared.ts
16605
- const MAX_TOKEN_NAME_LENGTH = 32;
16606
- const MAX_MINT_FEE = 5;
16607
- const MAX_TVL_FEE = 10;
16608
- const MIN_AUCTION_LENGTH_MINUTES = 15;
16609
- const MAX_AUCTION_LENGTH_MINUTES = 1440;
16610
- function buildSettingsProposal({ calls, calldatas, description, governance, timelock, targets }) {
16611
- if (calls.length === 0) throw new SdkError({
16612
- code: "INVALID_INPUT",
16613
- message: "proposal must include at least one call"
16614
- });
16615
- return {
16616
- governance: getProposalGovernance(governance),
16617
- timelock: getProposalTimelock(timelock),
16618
- targets,
16619
- calldatas,
16620
- description: description ?? ""
16621
- };
16622
- }
16623
- function buildCallPayload({ calls, governance, timelock }) {
16624
- return {
16625
- ...governance ? { governance } : {},
16626
- ...timelock ? { timelock } : {},
16627
- calls,
16628
- targets: calls.map((call) => call.to),
16629
- calldatas: calls.map((call) => call.data)
16630
- };
16631
- }
16632
- async function getDtfIfNeeded(client, params, needed) {
16633
- return params.dtf ?? (needed ? getDtf(client, params) : void 0);
16634
- }
16635
- async function getIndexDtfSettingsVersion(client, params) {
16636
- const version = params.version ?? await getVersion(client, params);
16637
- if (version !== "5.0.0" && version !== "6.0.0") throw new SdkError({
16638
- code: "INVALID_INPUT",
16639
- message: "Unsupported Index DTF settings proposal version",
16640
- meta: { version }
16641
- });
16642
- return version;
16643
- }
16644
- function hasIndexDtfSettingsCall(params) {
16645
- return (params.removeBasketTokens?.length ?? 0) > 0 || params.tokenName !== void 0 || params.mandate !== void 0 || params.mintFee !== void 0 || params.tvlFee !== void 0 || params.auctionLength !== void 0 || params.weightControl !== void 0 || params.priceControl !== void 0 || params.bidsEnabled !== void 0 || params.revenueDistribution !== void 0;
16646
- }
16647
- function getAuthorityGovernance(authority) {
16648
- return authority?.type === "governance" ? authority.governance : void 0;
16649
- }
16650
- function validateDtfSettingsParams(params) {
16651
- if (params.tokenName !== void 0) assertStringLength(params.tokenName, "tokenName", 1, MAX_TOKEN_NAME_LENGTH);
16652
- if (params.mintFee !== void 0) assertNumberRange(params.mintFee, "mintFee", 0, MAX_MINT_FEE);
16653
- if (params.tvlFee !== void 0) assertNumberRange(params.tvlFee, "tvlFee", 0, MAX_TVL_FEE);
16654
- if (params.auctionLength !== void 0) assertNumberRange(params.auctionLength, "auctionLength", MIN_AUCTION_LENGTH_MINUTES, MAX_AUCTION_LENGTH_MINUTES);
16655
- if (params.priceControl !== void 0 && !isPriceControl(params.priceControl)) throw new SdkError({
16656
- code: "INVALID_INPUT",
16657
- message: "priceControl must be 0, 1, or 2",
16658
- meta: { priceControl: params.priceControl }
16659
- });
16660
- }
16661
- function getProposalGovernance(governance) {
16662
- if (!governance) throw new SdkError({
16663
- code: "INVALID_INPUT",
16664
- message: "governance is required to build an Index DTF proposal",
16665
- meta: { governance }
16666
- });
16667
- return governance;
16668
- }
16669
- function getProposalTimelock(timelock) {
16670
- if (!timelock) throw new SdkError({
16671
- code: "INVALID_INPUT",
16672
- message: "timelock is required to build this Index DTF proposal",
16673
- meta: { timelock }
16674
- });
16675
- return timelock;
16676
- }
16677
- function assertStringLength(value, field, minLength, maxLength) {
16678
- if (value.length < minLength || value.length > maxLength) throw new SdkError({
16679
- code: "INVALID_INPUT",
16680
- message: `${field} must be between ${minLength} and ${maxLength} characters`,
16681
- meta: { [field]: value }
16682
- });
16683
- }
16684
- function isPriceControl(value) {
16685
- return Number.isInteger(value) && (value === 0 || value === 1 || value === 2);
16686
- }
16687
- //#endregion
16688
- //#region src/index-dtf/governance/propose/settings-basket.ts
16689
- /** Builds a proposal that changes basket governance settings. */
16690
- async function buildIndexDtfBasketSettingsProposal(client, params) {
16691
- return buildSettingsProposal({
16692
- ...await buildIndexDtfBasketSettingsCalls(client, params),
16693
- description: params.description
16694
- });
16695
- }
16696
- async function buildIndexDtfBasketSettingsCalls(client, params) {
16697
- const rebalanceGovernance = getAuthorityGovernance((await getDtfIfNeeded(client, params, params.dtf === void 0 && (params.governance === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0))))?.governance.rebalance.primary);
16698
- const governance = params.governance ?? rebalanceGovernance?.address;
16699
- const timelock = params.timelock ?? rebalanceGovernance?.timelock.address;
16700
- const currentGuardians = params.currentGuardians ?? rebalanceGovernance?.timelock.guardians ?? [];
16701
- return buildCallPayload({
16702
- governance,
16703
- timelock,
16704
- calls: [...buildGovernanceCalls({
16705
- chainId: params.chainId,
16706
- governance,
16707
- timelock,
16708
- changes: params.governanceChanges,
16709
- quorumDenominator: params.quorumDenominator ?? rebalanceGovernance?.quorumDenominator
16710
- }), ...buildRoleDiffCalls({
16711
- chainId: params.chainId,
16712
- target: timelock,
16713
- role: CANCELLER_ROLE$1,
16714
- current: currentGuardians,
16715
- next: params.guardians,
16716
- abi: timelockAbi
16717
- })]
16718
- });
16719
- }
16720
- //#endregion
16721
- //#region src/index-dtf/governance/propose/settings-dao.ts
16722
- /** Builds a proposal that changes vote-lock DAO settings and rewards. */
16723
- async function buildIndexDtfDaoSettingsProposal(client, params) {
16724
- return buildSettingsProposal({
16725
- ...await buildIndexDtfDaoSettingsCalls(client, params),
16726
- description: params.description
16727
- });
16728
- }
16729
- async function buildIndexDtfDaoSettingsCalls(client, params) {
16730
- const hasRewardChanges = (params.addRewardTokens?.length ?? 0) > 0 || (params.removeRewardTokens?.length ?? 0) > 0;
16731
- const vault = (await getDtfIfNeeded(client, params, params.dtf === void 0 && (params.governance === void 0 || hasRewardChanges && params.stToken === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0))))?.voteLockVault;
16732
- const governance = params.governance ?? vault?.governance?.address;
16733
- const timelock = params.timelock ?? vault?.governance?.timelock.address;
16734
- const stToken = params.stToken ?? vault?.token.address;
16735
- const currentGuardians = params.currentGuardians ?? vault?.governance?.timelock.guardians ?? [];
16736
- const calls = [];
16737
- if (hasRewardChanges && !stToken) throw new SdkError({
16738
- code: "INVALID_INPUT",
16739
- message: "stToken is required to build DAO reward token proposals"
16740
- });
16741
- if (stToken) {
16742
- for (const token of params.removeRewardTokens ?? []) calls.push(prepareRewardTokenCall(params.chainId, stToken, "removeRewardToken", token));
16743
- for (const token of params.addRewardTokens ?? []) calls.push(prepareRewardTokenCall(params.chainId, stToken, "addRewardToken", token));
16744
- }
16745
- calls.push(...buildGovernanceCalls({
16746
- chainId: params.chainId,
16747
- governance,
16748
- timelock,
16749
- changes: params.governanceChanges,
16750
- quorumDenominator: params.quorumDenominator ?? vault?.governance?.quorumDenominator
16751
- }), ...buildRoleDiffCalls({
16752
- chainId: params.chainId,
16753
- target: timelock,
16754
- role: CANCELLER_ROLE$1,
16755
- current: currentGuardians,
16756
- next: params.guardians,
16757
- abi: timelockAbi
16758
- }));
16759
- return buildCallPayload({
16760
- governance,
16761
- timelock,
16762
- calls
16763
- });
16764
- }
16765
- function prepareRewardTokenCall(chainId, target, functionName, token) {
16766
- return prepareContractCall({
16767
- chainId,
16768
- address: target,
16769
- abi: dtfIndexStakingVaultAbi,
16770
- functionName,
16771
- args: [getAddress(token)]
16772
- });
16773
- }
16774
- //#endregion
16775
- //#region src/index-dtf/governance/propose/settings-dtf.ts
16776
- /** Builds a proposal that changes core Index DTF settings. */
16777
- async function buildIndexDtfSettingsProposal(client, params) {
16778
- return buildSettingsProposal({
16779
- ...await buildIndexDtfSettingsCalls(client, params),
16780
- description: params.description
16781
- });
16782
- }
16783
- async function buildIndexDtfSettingsCalls(client, params) {
16784
- validateDtfSettingsParams(params);
16785
- const needsDtf = params.dtf === void 0 && (params.governance === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0) || params.brandManagers !== void 0 || params.auctionLaunchers !== void 0 || params.revenueDistribution !== void 0 || params.weightControl !== void 0 && params.priceControl === void 0 || params.priceControl !== void 0 && params.weightControl === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0);
16786
- const hasIndexDtfCall = hasIndexDtfSettingsCall(params);
16787
- if (hasIndexDtfCall && !needsDtf && params.timelock === void 0 && params.dtf === void 0) throw new SdkError({
16788
- code: "INVALID_INPUT",
16789
- message: "timelock is required to build this Index DTF proposal",
16790
- meta: { timelock: params.timelock }
16791
- });
16792
- const dtf = await getDtfIfNeeded(client, params, needsDtf);
16793
- if (params.revenueDistribution) validateRevenueDistributionInput(dtf, params.revenueDistribution);
16794
- const version = hasIndexDtfCall ? await getIndexDtfSettingsVersion(client, params) : void 0;
16795
- const dtfAddress = getAddress(params.address);
16796
- const adminGovernance = getAuthorityGovernance(dtf?.governance.admin.primary);
16797
- const governance = params.governance ?? adminGovernance?.address;
16798
- const timelock = params.timelock ?? adminGovernance?.timelock.address;
16799
- const currentGuardians = params.currentGuardians ?? adminGovernance?.timelock.guardians ?? [];
16800
- const calls = [];
16801
- if (version !== void 0) calls.push(...buildDtfCalls(dtfAddress, params, version, dtf?.rebalance));
16802
- calls.push(...buildRoleDiffCalls({
16803
- chainId: params.chainId,
16804
- target: timelock ?? dtfAddress,
16805
- role: GUARDIAN_ROLE,
16806
- current: currentGuardians,
16807
- next: params.guardians,
16808
- abi: timelock ? timelockAbi : dtfIndexAbi
16809
- }), ...buildRoleDiffCalls({
16810
- chainId: params.chainId,
16811
- target: dtfAddress,
16812
- role: BRAND_MANAGER_ROLE,
16813
- current: dtf?.roles.metadata.brandManagers ?? [],
16814
- next: params.brandManagers,
16815
- abi: dtfIndexAbi
16816
- }), ...buildRoleDiffCalls({
16817
- chainId: params.chainId,
16818
- target: dtfAddress,
16819
- role: AUCTION_LAUNCHER_ROLE,
16820
- current: dtf?.roles.rebalance.auctionLaunchers ?? [],
16821
- next: params.auctionLaunchers,
16822
- abi: dtfIndexAbi
16823
- }), ...buildGovernanceCalls({
16824
- chainId: params.chainId,
16825
- governance,
16826
- timelock,
16827
- changes: params.governanceChanges,
16828
- quorumDenominator: params.quorumDenominator ?? adminGovernance?.quorumDenominator
16829
- }));
16830
- const revenueCall = version && params.revenueDistribution ? prepareRevenueDistribution(dtfAddress, params.chainId, dtf, params.revenueDistribution, version) : void 0;
16831
- if (revenueCall) calls.push(revenueCall);
16832
- return buildCallPayload({
16833
- governance,
16834
- timelock,
16835
- calls
16836
- });
16837
- }
16838
- function buildDtfCalls(address, params, version, currentRebalanceControl) {
16839
- const calls = [];
16840
- for (const token of params.removeBasketTokens ?? []) calls.push(prepareIndexDtfRemoveFromBasket({
16841
- address,
16842
- chainId: params.chainId,
16843
- token,
16844
- version
16845
- }));
16846
- if (params.tokenName !== void 0) calls.push(prepareIndexDtfSetName({
16847
- address,
16848
- chainId: params.chainId,
16849
- name: params.tokenName,
16850
- version
16851
- }));
16852
- if (params.mandate !== void 0) calls.push(prepareIndexDtfSetMandate({
16853
- address,
16854
- chainId: params.chainId,
16855
- mandate: params.mandate,
16856
- version
16857
- }));
16858
- if (params.mintFee !== void 0) calls.push(prepareIndexDtfSetMintFee({
16859
- address,
16860
- chainId: params.chainId,
16861
- percentage: params.mintFee,
16862
- version
16863
- }));
16864
- if (params.tvlFee !== void 0) calls.push(prepareIndexDtfSetTvlFee({
16865
- address,
16866
- chainId: params.chainId,
16867
- percentage: params.tvlFee,
16868
- version
16869
- }));
16870
- if (params.auctionLength !== void 0) calls.push(prepareIndexDtfSetAuctionLength({
16871
- address,
16872
- chainId: params.chainId,
16873
- auctionLength: params.auctionLength * 60,
16874
- version
16875
- }));
16876
- if (params.weightControl !== void 0 || params.priceControl !== void 0) {
16877
- const weightControl = params.weightControl ?? currentRebalanceControl?.weightControl;
16878
- const priceControl = params.priceControl ?? currentRebalanceControl?.priceControl;
16879
- if (weightControl === void 0) throw new SdkError({
16880
- code: "INVALID_INPUT",
16881
- message: "weightControl is required to build a priceControl settings proposal",
16882
- meta: {
16883
- address,
16884
- chainId: params.chainId
16885
- }
16886
- });
16887
- if (priceControl === void 0) throw new SdkError({
16888
- code: "INVALID_INPUT",
16889
- message: "priceControl is required to build a weightControl settings proposal",
16890
- meta: {
16891
- address,
16892
- chainId: params.chainId
16893
- }
16894
- });
16895
- calls.push(prepareIndexDtfSetRebalanceControl({
16896
- address,
16897
- chainId: params.chainId,
16898
- weightControl,
16899
- priceControl,
16900
- version
16901
- }));
16902
- }
16903
- if (params.bidsEnabled !== void 0) calls.push(prepareIndexDtfSetBidsEnabled({
16904
- address,
16905
- chainId: params.chainId,
16906
- enabled: params.bidsEnabled,
16907
- version
16908
- }));
16909
- return calls;
16910
- }
16911
- //#endregion
16912
- //#region src/index-dtf/governance/propose/settings-types.ts
16913
- const addressSchema = z.string().refine(isAddress, "Invalid address");
16914
- const indexDtfGovernanceChangesSchema = z.object({
16915
- votingDelay: z.coerce.number().min(0).optional(),
16916
- votingPeriod: z.coerce.number().min(0).optional(),
16917
- proposalThreshold: z.coerce.number().min(0).max(100).optional(),
16918
- quorumPercent: z.coerce.number().min(0).max(100).optional(),
16919
- executionDelay: z.coerce.number().min(0).optional()
16920
- });
16921
- const indexDtfBasketSettingsProposalSchema = z.object({
16922
- governanceChanges: indexDtfGovernanceChangesSchema.optional(),
16923
- guardians: z.array(addressSchema).optional()
16924
- });
16925
- const indexDtfDaoSettingsProposalSchema = z.object({
16926
- addRewardTokens: z.array(addressSchema).optional(),
16927
- removeRewardTokens: z.array(addressSchema).optional(),
16928
- governanceChanges: indexDtfGovernanceChangesSchema.optional(),
16929
- guardians: z.array(addressSchema).optional()
16930
- });
16931
- const indexDtfSettingsProposalSchema = z.object({
16932
- tokenName: z.string().min(1).max(32).optional(),
16933
- mandate: z.string().optional(),
16934
- mintFee: z.coerce.number().min(0).max(5).optional(),
16935
- tvlFee: z.coerce.number().min(0).max(10).optional(),
16936
- auctionLength: z.coerce.number().min(15).max(1440).optional(),
16937
- weightControl: z.boolean().optional(),
16938
- priceControl: z.coerce.number().int().min(0).max(2).optional(),
16939
- bidsEnabled: z.boolean().optional(),
16940
- removeBasketTokens: z.array(addressSchema).optional(),
16941
- guardians: z.array(addressSchema).optional(),
16942
- brandManagers: z.array(addressSchema).optional(),
16943
- auctionLaunchers: z.array(addressSchema).optional(),
16944
- governanceChanges: indexDtfGovernanceChangesSchema.optional(),
16945
- version: z.enum(["5.0.0", "6.0.0"]).optional(),
16946
- revenueDistribution: z.object({
16947
- platformFee: z.coerce.number().min(0).lt(100),
16948
- governanceShare: z.coerce.number().min(0).max(100),
16949
- deployerShare: z.coerce.number().min(0).max(100),
16950
- additionalRecipients: z.array(z.object({
16951
- address: addressSchema,
16952
- share: z.coerce.number().min(0).max(100)
16953
- }))
16954
- }).optional()
16955
- });
15876
+ //#region src/index-dtf/abis/selector-registry.ts
15877
+ const selectorRegistryAbi = [
15878
+ {
15879
+ type: "function",
15880
+ name: "governor",
15881
+ inputs: [],
15882
+ outputs: [{
15883
+ name: "",
15884
+ type: "address",
15885
+ internalType: "address"
15886
+ }],
15887
+ stateMutability: "view"
15888
+ },
15889
+ {
15890
+ type: "function",
15891
+ name: "isAllowed",
15892
+ inputs: [{
15893
+ name: "target",
15894
+ type: "address",
15895
+ internalType: "address"
15896
+ }, {
15897
+ name: "selector",
15898
+ type: "bytes4",
15899
+ internalType: "bytes4"
15900
+ }],
15901
+ outputs: [{
15902
+ name: "",
15903
+ type: "bool",
15904
+ internalType: "bool"
15905
+ }],
15906
+ stateMutability: "view"
15907
+ },
15908
+ {
15909
+ type: "function",
15910
+ name: "registerSelectors",
15911
+ inputs: [{
15912
+ name: "selectorData",
15913
+ type: "tuple[]",
15914
+ internalType: "struct IOptimisticSelectorRegistry.SelectorData[]",
15915
+ components: [{
15916
+ name: "target",
15917
+ type: "address",
15918
+ internalType: "address"
15919
+ }, {
15920
+ name: "selectors",
15921
+ type: "bytes4[]",
15922
+ internalType: "bytes4[]"
15923
+ }]
15924
+ }],
15925
+ outputs: [],
15926
+ stateMutability: "nonpayable"
15927
+ },
15928
+ {
15929
+ type: "function",
15930
+ name: "selectorsAllowed",
15931
+ inputs: [{
15932
+ name: "target",
15933
+ type: "address",
15934
+ internalType: "address"
15935
+ }],
15936
+ outputs: [{
15937
+ name: "allowedSelectors4",
15938
+ type: "bytes4[]",
15939
+ internalType: "bytes4[]"
15940
+ }],
15941
+ stateMutability: "view"
15942
+ },
15943
+ {
15944
+ type: "function",
15945
+ name: "targets",
15946
+ inputs: [],
15947
+ outputs: [{
15948
+ name: "",
15949
+ type: "address[]",
15950
+ internalType: "address[]"
15951
+ }],
15952
+ stateMutability: "view"
15953
+ },
15954
+ {
15955
+ type: "function",
15956
+ name: "unregisterSelectors",
15957
+ inputs: [{
15958
+ name: "selectorData",
15959
+ type: "tuple[]",
15960
+ internalType: "struct IOptimisticSelectorRegistry.SelectorData[]",
15961
+ components: [{
15962
+ name: "target",
15963
+ type: "address",
15964
+ internalType: "address"
15965
+ }, {
15966
+ name: "selectors",
15967
+ type: "bytes4[]",
15968
+ internalType: "bytes4[]"
15969
+ }]
15970
+ }],
15971
+ outputs: [],
15972
+ stateMutability: "nonpayable"
15973
+ }
15974
+ ];
16956
15975
  //#endregion
16957
15976
  //#region src/index-dtf/abis/dtf-admin-proposal.ts
16958
15977
  const dtfAdminProposalAbi = [{
@@ -23688,435 +22707,1762 @@ const dtfIndexProposalAbi = [
23688
22707
  }
23689
22708
  ]
23690
22709
  }
23691
- ].flatMap(({ abi }) => abi);
22710
+ ].flatMap(({ abi }) => abi);
22711
+ //#endregion
22712
+ //#region src/index-dtf/abis/upgrade-spell-proposal.ts
22713
+ const upgradeSpellProposalAbi = [
22714
+ {
22715
+ type: "function",
22716
+ name: "cast",
22717
+ inputs: [{
22718
+ name: "folio",
22719
+ type: "address"
22720
+ }, {
22721
+ name: "proxyAdmin",
22722
+ type: "address"
22723
+ }],
22724
+ outputs: [],
22725
+ stateMutability: "nonpayable"
22726
+ },
22727
+ {
22728
+ type: "function",
22729
+ name: "upgradeFolioGovernance",
22730
+ inputs: [
22731
+ {
22732
+ name: "folio",
22733
+ type: "address"
22734
+ },
22735
+ {
22736
+ name: "proxyAdmin",
22737
+ type: "address"
22738
+ },
22739
+ {
22740
+ name: "oldOwnerGovernor",
22741
+ type: "address"
22742
+ },
22743
+ {
22744
+ name: "oldTradingGovernor",
22745
+ type: "address"
22746
+ },
22747
+ {
22748
+ name: "ownerGuardians",
22749
+ type: "address[]"
22750
+ },
22751
+ {
22752
+ name: "tradingGuardians",
22753
+ type: "address[]"
22754
+ },
22755
+ {
22756
+ name: "deploymentNonce",
22757
+ type: "bytes32"
22758
+ }
22759
+ ],
22760
+ outputs: [{
22761
+ name: "newOwnerGovernor",
22762
+ type: "address"
22763
+ }, {
22764
+ name: "newTradingGovernor",
22765
+ type: "address"
22766
+ }],
22767
+ stateMutability: "nonpayable"
22768
+ },
22769
+ {
22770
+ type: "function",
22771
+ name: "upgradeStakingVaultGovernance",
22772
+ inputs: [
22773
+ {
22774
+ name: "stakingVault",
22775
+ type: "address"
22776
+ },
22777
+ {
22778
+ name: "oldGovernor",
22779
+ type: "address"
22780
+ },
22781
+ {
22782
+ name: "guardians",
22783
+ type: "address[]"
22784
+ },
22785
+ {
22786
+ name: "deploymentNonce",
22787
+ type: "bytes32"
22788
+ }
22789
+ ],
22790
+ outputs: [{
22791
+ name: "newGovernor",
22792
+ type: "address"
22793
+ }],
22794
+ stateMutability: "nonpayable"
22795
+ },
22796
+ {
22797
+ type: "function",
22798
+ name: "upgradeFolio",
22799
+ inputs: [
22800
+ {
22801
+ name: "folio",
22802
+ type: "address"
22803
+ },
22804
+ {
22805
+ name: "folioProxyAdmin",
22806
+ type: "address"
22807
+ },
22808
+ {
22809
+ name: "newStakingVault",
22810
+ type: "address"
22811
+ },
22812
+ {
22813
+ name: "oldFolioGovernor",
22814
+ type: "address"
22815
+ },
22816
+ {
22817
+ name: "tradingGovernor",
22818
+ type: "address"
22819
+ },
22820
+ {
22821
+ name: "optimisticParams",
22822
+ type: "tuple",
22823
+ components: [
22824
+ {
22825
+ name: "vetoDelay",
22826
+ type: "uint48"
22827
+ },
22828
+ {
22829
+ name: "vetoPeriod",
22830
+ type: "uint32"
22831
+ },
22832
+ {
22833
+ name: "vetoThreshold",
22834
+ type: "uint256"
22835
+ }
22836
+ ]
22837
+ },
22838
+ {
22839
+ name: "optimisticProposers",
22840
+ type: "address[]"
22841
+ },
22842
+ {
22843
+ name: "guardians",
22844
+ type: "address[]"
22845
+ },
22846
+ {
22847
+ name: "newFeeRecipient",
22848
+ type: "address"
22849
+ },
22850
+ {
22851
+ name: "deploymentNonce",
22852
+ type: "bytes32"
22853
+ }
22854
+ ],
22855
+ outputs: [{
22856
+ name: "newDeployment",
22857
+ type: "tuple",
22858
+ components: [
22859
+ {
22860
+ name: "stakingVault",
22861
+ type: "address"
22862
+ },
22863
+ {
22864
+ name: "newGovernor",
22865
+ type: "address"
22866
+ },
22867
+ {
22868
+ name: "newTimelock",
22869
+ type: "address"
22870
+ },
22871
+ {
22872
+ name: "newSelectorRegistry",
22873
+ type: "address"
22874
+ }
22875
+ ]
22876
+ }],
22877
+ stateMutability: "nonpayable"
22878
+ }
22879
+ ];
22880
+ //#endregion
22881
+ //#region src/index-dtf/governance/contract-map.ts
22882
+ const EXTRA_PROPOSAL_CONTRACTS = [
22883
+ {
22884
+ contract: "GovernanceSpell_31_03_2025",
22885
+ abi: upgradeSpellProposalAbi,
22886
+ addresses: {
22887
+ 1: "0x4491b242f15f8dc9c6dfbb9a08edbbaae2623199",
22888
+ 8453: "0x587cefb69473ad467993c6dd3a8f202bf1ef5e2a"
22889
+ }
22890
+ },
22891
+ {
22892
+ contract: "V4 Upgrade Spell",
22893
+ abi: upgradeSpellProposalAbi,
22894
+ addresses: {
22895
+ 1: "0x7498c6aB0669A09DE7B9185ba72A98fa3Ca39cC9",
22896
+ 8453: "0x4720dbCAEEF5834AEf590781F93d70fD1e3AcADB"
22897
+ }
22898
+ },
22899
+ {
22900
+ contract: "V5 Upgrade Spell",
22901
+ abi: upgradeSpellProposalAbi,
22902
+ addresses: {
22903
+ 1: "0x044B6F685FB8D0c3fd56D92FCBE5F0Ad947d2D53",
22904
+ 8453: "0x04B3eD311C68dfB0649D9faf695115F23DcbB540",
22905
+ 56: "0xe8e67a366e5166c442B6D376ADc772b93CdE7825"
22906
+ }
22907
+ },
22908
+ {
22909
+ contract: "Reserve Optimistic Governance Spell",
22910
+ abi: upgradeSpellProposalAbi,
22911
+ addresses: {
22912
+ 1: "0x082E701456cd702fBE5797Ab515e6B00580E5a14",
22913
+ 8453: "0x0aDc69041a2B086f8772aCcE2A754f410F211bed",
22914
+ 56: "0x02Ee6862cF431D7CEaa78112D635D2Be7DdFC178"
22915
+ }
22916
+ }
22917
+ ];
22918
+ function buildProposalContractMap({ chainId, dtf, proposalGovernance }) {
22919
+ const contracts = /* @__PURE__ */ new Map();
22920
+ addContract(contracts, dtf.address, "Index DTF", dtfIndexProposalAbi);
22921
+ addContract(contracts, dtf.proxyAdmin, "ProxyAdmin", dtfAdminProposalAbi);
22922
+ const hasSharedOwnerAndBasketGovernance = dtf.ownerGovernance && dtf.tradingGovernance && dtf.ownerGovernance.address.toLowerCase() === dtf.tradingGovernance.address.toLowerCase();
22923
+ for (const governance of dtf.legacyAdminGovernance) addContract(contracts, governance, "Legacy Owner Governance", dtfIndexGovernanceProposalAbi);
22924
+ for (const governance of dtf.legacyTradingGovernance) addContract(contracts, governance, "Legacy Basket Governance", dtfIndexGovernanceProposalAbi);
22925
+ if (hasSharedOwnerAndBasketGovernance) {
22926
+ addContract(contracts, dtf.ownerGovernance.address, "Owner/Basket Governance", dtfIndexGovernanceProposalAbi);
22927
+ addContract(contracts, dtf.ownerGovernance.timelock, "Owner/Basket Governance Timelock", timelockAbi);
22928
+ } else if (dtf.ownerGovernance) {
22929
+ addContract(contracts, dtf.ownerGovernance.address, "Owner Governance", dtfIndexGovernanceProposalAbi);
22930
+ addContract(contracts, dtf.ownerGovernance.timelock, "Owner Governance Timelock", timelockAbi);
22931
+ }
22932
+ if (!hasSharedOwnerAndBasketGovernance && dtf.tradingGovernance) {
22933
+ addContract(contracts, dtf.tradingGovernance.address, "Basket Governance", dtfIndexGovernanceProposalAbi);
22934
+ addContract(contracts, dtf.tradingGovernance.timelock, "Basket Governance Timelock", timelockAbi);
22935
+ }
22936
+ addContract(contracts, dtf.stakingToken.address, "Lock Vault", dtfIndexStakingVaultAbi);
22937
+ for (const governance of dtf.stakingToken.legacyGovernance) addContract(contracts, governance, "Legacy Lock Governance", dtfIndexGovernanceProposalAbi);
22938
+ if (dtf.stakingToken.governance) {
22939
+ addContract(contracts, dtf.stakingToken.governance.address, "Lock Governance", dtfIndexGovernanceProposalAbi);
22940
+ addContract(contracts, dtf.stakingToken.governance.timelock, "Lock Governance Timelock", timelockAbi);
22941
+ }
22942
+ if (proposalGovernance) {
22943
+ addContract(contracts, proposalGovernance.address, getGovernanceContractName(proposalGovernance.timelock.type), dtfIndexGovernanceProposalAbi);
22944
+ addContract(contracts, proposalGovernance.timelock.address, getTimelockContractName(proposalGovernance.timelock.type), timelockAbi);
22945
+ }
22946
+ for (const extraContract of EXTRA_PROPOSAL_CONTRACTS) addContract(contracts, extraContract.addresses[chainId], extraContract.contract, extraContract.abi);
22947
+ return contracts;
22948
+ }
22949
+ function getContractAliases(contractMap) {
22950
+ const aliases = {};
22951
+ for (const contract of contractMap.values()) aliases[contract.target] = contract.contract;
22952
+ return aliases;
22953
+ }
22954
+ function addContract(contracts, target, contract, abi) {
22955
+ if (!target) return;
22956
+ const address = getAddress(target);
22957
+ const key = address.toLowerCase();
22958
+ if (contracts.has(key)) return;
22959
+ contracts.set(key, {
22960
+ target: address,
22961
+ contract,
22962
+ abi
22963
+ });
22964
+ }
22965
+ function getGovernanceContractName(type) {
22966
+ if (type === "OWNER") return "Owner Governance";
22967
+ if (type === "TRADING") return "Basket Governance";
22968
+ if (type === "VOTE_LOCKING") return "Lock Governance";
22969
+ return "Governance";
22970
+ }
22971
+ function getTimelockContractName(type) {
22972
+ if (type === "OWNER") return "Owner Governance Timelock";
22973
+ if (type === "TRADING") return "Basket Governance Timelock";
22974
+ if (type === "VOTE_LOCKING") return "Lock Governance Timelock";
22975
+ return "Governance Timelock";
22976
+ }
22977
+ //#endregion
22978
+ //#region src/index-dtf/governance/decoder.ts
22979
+ const UNKNOWN_CONTRACT = "Unknown";
22980
+ const FALLBACK_DECODERS = [{
22981
+ contract: "Selector Registry",
22982
+ abi: selectorRegistryAbi
22983
+ }];
22984
+ function decodeIndexDtfProposalCalldatas({ targets, calldatas, contractMap }) {
22985
+ if (targets.length !== calldatas.length) throw new Error("Index DTF proposal targets and calldatas length mismatch");
22986
+ const calls = [];
22987
+ const unknownCalls = [];
22988
+ const dataByContract = [];
22989
+ const unknownContracts = [];
22990
+ const dataGroupMap = /* @__PURE__ */ new Map();
22991
+ const unknownGroupMap = /* @__PURE__ */ new Map();
22992
+ for (let i = 0; i < targets.length; i++) {
22993
+ const target = targets[i];
22994
+ const callData = calldatas[i];
22995
+ const targetAddress = getAddress(target);
22996
+ const targetKey = targetAddress.toLowerCase();
22997
+ const contractDecoder = contractMap.get(targetKey);
22998
+ if (!contractDecoder) {
22999
+ const fallbackDecoded = decodeFallbackProposalCalldata(i, targetAddress, callData);
23000
+ if (fallbackDecoded) {
23001
+ calls.push(fallbackDecoded);
23002
+ pushDecodedContractGroup(dataByContract, dataGroupMap, fallbackDecoded);
23003
+ continue;
23004
+ }
23005
+ const unknownCall = {
23006
+ index: i,
23007
+ target: targetAddress,
23008
+ contract: UNKNOWN_CONTRACT,
23009
+ callData
23010
+ };
23011
+ unknownCalls.push(unknownCall);
23012
+ pushUnknownContractGroup(unknownContracts, unknownGroupMap, unknownCall);
23013
+ continue;
23014
+ }
23015
+ const decoded = decodeProposalCalldata(contractDecoder, i, targetAddress, callData);
23016
+ if (decoded) {
23017
+ calls.push(decoded);
23018
+ pushDecodedContractGroup(dataByContract, dataGroupMap, decoded);
23019
+ } else {
23020
+ const unknownCall = {
23021
+ index: i,
23022
+ target: targetAddress,
23023
+ contract: contractDecoder.contract,
23024
+ callData
23025
+ };
23026
+ unknownCalls.push(unknownCall);
23027
+ pushUnknownContractGroup(unknownContracts, unknownGroupMap, unknownCall);
23028
+ }
23029
+ }
23030
+ return {
23031
+ contracts: getContractAliases(contractMap),
23032
+ dataByContract,
23033
+ unknownContracts,
23034
+ calls,
23035
+ unknownCalls
23036
+ };
23037
+ }
23038
+ async function decodeIndexDtfProposal(client, params) {
23039
+ const contractMap = buildProposalContractMap({
23040
+ chainId: params.chainId,
23041
+ dtf: params.dtf,
23042
+ ...params.proposalGovernance ? { proposalGovernance: params.proposalGovernance } : {}
23043
+ });
23044
+ const decoded = decodeIndexDtfProposalCalldatas({
23045
+ targets: params.targets,
23046
+ calldatas: params.calldatas,
23047
+ contractMap
23048
+ });
23049
+ if (decoded.unknownCalls.length === 0) return decoded;
23050
+ const explorer = client.explorer;
23051
+ if (!explorer) return decoded;
23052
+ const externalContractMap = await getExternalAbiContractMap(explorer, params.chainId, decoded.unknownCalls, contractMap);
23053
+ if (!externalContractMap) return decoded;
23054
+ return decodeIndexDtfProposalCalldatas({
23055
+ targets: params.targets,
23056
+ calldatas: params.calldatas,
23057
+ contractMap: externalContractMap
23058
+ });
23059
+ }
23060
+ async function getExternalAbiContractMap(explorer, chainId, unknownCalls, contractMap) {
23061
+ const targets = [...new Set(unknownCalls.map((call) => getAddress(call.target)))];
23062
+ const withMetadata = (await Promise.all(targets.map(async (target) => ({
23063
+ target,
23064
+ metadata: await explorer.getContractMetadata({
23065
+ chainId,
23066
+ address: target
23067
+ })
23068
+ })))).filter((entry) => entry.metadata !== null);
23069
+ if (withMetadata.length === 0) return null;
23070
+ const externalContractMap = new Map(contractMap);
23071
+ for (const { target, metadata } of withMetadata) {
23072
+ const key = target.toLowerCase();
23073
+ const existing = externalContractMap.get(key);
23074
+ externalContractMap.set(key, {
23075
+ target,
23076
+ contract: existing?.contract ?? metadata.contractName,
23077
+ abi: existing ? [...existing.abi, ...metadata.abi] : metadata.abi
23078
+ });
23079
+ }
23080
+ return externalContractMap;
23081
+ }
23082
+ function decodeProposalCalldata(contractDecoder, index, target, callData) {
23083
+ const decoded = tryDecodeCalldata(contractDecoder.abi, callData);
23084
+ if (!decoded) return;
23085
+ return {
23086
+ index,
23087
+ target,
23088
+ contract: contractDecoder.contract,
23089
+ functionName: decoded.functionName,
23090
+ signature: decoded.signature,
23091
+ parameters: decoded.parameters,
23092
+ params: decoded.params,
23093
+ callData
23094
+ };
23095
+ }
23096
+ function tryDecodeCalldata(abi, callData) {
23097
+ try {
23098
+ const { args, functionName } = decodeFunctionData({
23099
+ abi,
23100
+ data: callData
23101
+ });
23102
+ const abiItem = getAbiItem({
23103
+ abi,
23104
+ args,
23105
+ name: functionName
23106
+ });
23107
+ const parameters = abiItem && "inputs" in abiItem ? abiItem.inputs.map((input) => formatAbiInput(input)) : [];
23108
+ const functionNameString = String(functionName);
23109
+ return {
23110
+ functionName: functionNameString,
23111
+ signature: `${functionNameString}(${parameters.join(", ")})`,
23112
+ parameters,
23113
+ params: [...args ?? []]
23114
+ };
23115
+ } catch {
23116
+ return;
23117
+ }
23118
+ }
23119
+ function decodeFallbackProposalCalldata(index, target, callData) {
23120
+ for (const fallbackDecoder of FALLBACK_DECODERS) {
23121
+ const decoded = decodeProposalCalldata({
23122
+ ...fallbackDecoder,
23123
+ target
23124
+ }, index, target, callData);
23125
+ if (decoded) return decoded;
23126
+ }
23127
+ }
23128
+ function formatAbiInput(input) {
23129
+ if (!input.name) return input.type;
23130
+ return `${input.name}: ${input.type}`;
23131
+ }
23132
+ function pushDecodedContractGroup(groups, groupMap, call) {
23133
+ const key = call.target.toLowerCase();
23134
+ let group = groupMap.get(key);
23135
+ if (!group) {
23136
+ group = {
23137
+ target: call.target,
23138
+ contract: call.contract,
23139
+ calls: []
23140
+ };
23141
+ groupMap.set(key, group);
23142
+ groups.push(group);
23143
+ }
23144
+ group.calls.push(call);
23145
+ }
23146
+ function pushUnknownContractGroup(groups, groupMap, call) {
23147
+ const key = call.target.toLowerCase();
23148
+ let group = groupMap.get(key);
23149
+ if (!group) {
23150
+ group = {
23151
+ target: call.target,
23152
+ contract: call.contract,
23153
+ calls: []
23154
+ };
23155
+ groupMap.set(key, group);
23156
+ groups.push(group);
23157
+ }
23158
+ group.calls.push(call);
23159
+ }
23160
+ //#endregion
23161
+ //#region src/index-dtf/governance/guardians.ts
23162
+ async function getGuardians(client, params) {
23163
+ const dtf = "dtf" in params ? params.dtf : await getDtf(client, params);
23164
+ const owner = mapGuardianGroup(dtf.governance.admin.primary);
23165
+ const basket = mapGuardianGroup(dtf.governance.rebalance.primary);
23166
+ const dao = mapGuardianGroup(dtf.governance.voteLock);
23167
+ return {
23168
+ owner,
23169
+ basket,
23170
+ dao,
23171
+ all: dedupeAddresses([
23172
+ ...owner.guardians,
23173
+ ...basket.guardians,
23174
+ ...dao.guardians
23175
+ ])
23176
+ };
23177
+ }
23178
+ //#endregion
23179
+ //#region src/index-dtf/governance/legacy-vote-lock.ts
23180
+ async function getLegacyVoteLocks(client, params) {
23181
+ const context = await getLegacyVoteLockContext(client, params);
23182
+ const legacyGovernance = context?.legacyGovernance.filter((governance) => governance.toLowerCase() !== zeroAddress);
23183
+ if (!context || !legacyGovernance || legacyGovernance.length === 0) return [];
23184
+ const legacyVoteLocks = await Promise.all(legacyGovernance.map((governance) => readLegacyVoteLock(client, context.chainId, governance)));
23185
+ const currentVoteLock = context.currentVoteLock.toLowerCase();
23186
+ const result = [];
23187
+ for (const voteLock of legacyVoteLocks) {
23188
+ if (!voteLock) continue;
23189
+ const address = voteLock;
23190
+ if (address.toLowerCase() === currentVoteLock) continue;
23191
+ if (!result.some((existing) => existing.toLowerCase() === address.toLowerCase())) result.push(address);
23192
+ }
23193
+ return result;
23194
+ }
23195
+ async function readLegacyVoteLock(client, chainId, governance) {
23196
+ try {
23197
+ return await client.viem.readContract({
23198
+ chainId,
23199
+ address: governance,
23200
+ abi: dtfIndexGovernanceAbi,
23201
+ functionName: "token"
23202
+ });
23203
+ } catch (error) {
23204
+ if (isUnreadableLegacyGovernance(error)) return null;
23205
+ throw error;
23206
+ }
23207
+ }
23208
+ async function getLegacyVoteLockContext(client, params) {
23209
+ if ("currentVoteLock" in params) return {
23210
+ chainId: params.chainId,
23211
+ currentVoteLock: getAddress(params.currentVoteLock),
23212
+ legacyGovernance: params.legacyGovernance.map((address) => getAddress(address))
23213
+ };
23214
+ const dtf = "dtf" in params ? params.dtf : await getDtf(client, params);
23215
+ if (!dtf.voteLockVault) return null;
23216
+ return {
23217
+ chainId: dtf.chainId,
23218
+ currentVoteLock: dtf.voteLockVault.token.address,
23219
+ legacyGovernance: dtf.voteLockVault.legacyGovernance
23220
+ };
23221
+ }
23222
+ function isUnreadableLegacyGovernance(error) {
23223
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
23224
+ return message.includes("returned no data") || message.includes("function \"token\" reverted");
23225
+ }
23226
+ //#endregion
23227
+ //#region src/index-dtf/governance/proposal-actions.ts
23228
+ const TIMELOCK_OPERATION_PARAMS = parseAbiParameters("address[], uint256[], bytes[], bytes32, bytes32");
23229
+ function prepareIndexDtfVote(params) {
23230
+ return prepareContractCall({
23231
+ chainId: params.chainId,
23232
+ address: params.governance,
23233
+ abi: dtfIndexGovernanceAbi,
23234
+ functionName: "castVote",
23235
+ args: [BigInt(params.proposalId), params.support]
23236
+ });
23237
+ }
23238
+ function prepareIndexDtfVoteWithReason(params) {
23239
+ return prepareContractCall({
23240
+ chainId: params.chainId,
23241
+ address: params.governance,
23242
+ abi: dtfIndexGovernanceAbi,
23243
+ functionName: "castVoteWithReason",
23244
+ args: [
23245
+ BigInt(params.proposalId),
23246
+ params.support,
23247
+ params.reason
23248
+ ]
23249
+ });
23250
+ }
23251
+ function prepareIndexDtfVoteWithReasonAndParams(params) {
23252
+ return prepareContractCall({
23253
+ chainId: params.chainId,
23254
+ address: params.governance,
23255
+ abi: dtfIndexGovernanceAbi,
23256
+ functionName: "castVoteWithReasonAndParams",
23257
+ args: [
23258
+ BigInt(params.proposalId),
23259
+ params.support,
23260
+ params.reason,
23261
+ params.voteParams
23262
+ ]
23263
+ });
23264
+ }
23265
+ function prepareIndexDtfQueueProposal(params) {
23266
+ const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
23267
+ return prepareContractCall({
23268
+ chainId: params.chainId,
23269
+ address: params.proposal.governance,
23270
+ abi: dtfIndexGovernanceAbi,
23271
+ functionName: "queue",
23272
+ args: [
23273
+ targets,
23274
+ values,
23275
+ calldatas,
23276
+ descriptionHash
23277
+ ]
23278
+ });
23279
+ }
23280
+ function prepareIndexDtfExecuteProposal(params) {
23281
+ const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
23282
+ return prepareContractCall({
23283
+ chainId: params.chainId,
23284
+ address: params.proposal.governance,
23285
+ abi: dtfIndexGovernanceAbi,
23286
+ functionName: "execute",
23287
+ args: [
23288
+ targets,
23289
+ values,
23290
+ calldatas,
23291
+ descriptionHash
23292
+ ]
23293
+ });
23294
+ }
23295
+ function prepareIndexDtfCancelProposal(params) {
23296
+ if (!params.proposal.timelock) throw new SdkError({
23297
+ code: "INVALID_INPUT",
23298
+ message: "timelock is required to cancel a proposal"
23299
+ });
23300
+ return prepareContractCall({
23301
+ chainId: params.chainId,
23302
+ address: params.proposal.timelock,
23303
+ abi: timelockAbi,
23304
+ functionName: "cancel",
23305
+ args: [getTimelockOperationId(params.proposal)]
23306
+ });
23307
+ }
23308
+ function prepareIndexDtfGovernorCancelProposal(params) {
23309
+ const [targets, values, calldatas, descriptionHash] = getProposalTxArgs(params.proposal);
23310
+ return prepareContractCall({
23311
+ chainId: params.chainId,
23312
+ address: params.proposal.governance,
23313
+ abi: dtfIndexGovernanceAbi,
23314
+ functionName: "cancel",
23315
+ args: [
23316
+ targets,
23317
+ values,
23318
+ calldatas,
23319
+ descriptionHash
23320
+ ]
23321
+ });
23322
+ }
23323
+ function prepareIndexDtfSubmitProposal(params) {
23324
+ const targets = params.proposal.targets;
23325
+ const calldatas = [...params.proposal.calldatas];
23326
+ const values = getZeroValues(targets.length);
23327
+ return prepareContractCall({
23328
+ chainId: params.chainId,
23329
+ address: params.proposal.governance,
23330
+ abi: dtfIndexGovernanceAbi,
23331
+ functionName: "propose",
23332
+ args: [
23333
+ targets,
23334
+ values,
23335
+ calldatas,
23336
+ params.proposal.description
23337
+ ]
23338
+ });
23339
+ }
23340
+ function prepareIndexDtfSubmitOptimisticProposal(params) {
23341
+ const targets = params.proposal.targets;
23342
+ const calldatas = [...params.proposal.calldatas];
23343
+ const values = getZeroValues(targets.length);
23344
+ return prepareContractCall({
23345
+ chainId: params.chainId,
23346
+ address: params.proposal.governance,
23347
+ abi: dtfIndexGovernanceOptimisticAbi,
23348
+ functionName: "proposeOptimistic",
23349
+ args: [
23350
+ targets,
23351
+ values,
23352
+ calldatas,
23353
+ params.proposal.description
23354
+ ]
23355
+ });
23356
+ }
23357
+ function getProposalTxArgs(proposal) {
23358
+ const targets = proposal.targets;
23359
+ return [
23360
+ targets,
23361
+ getZeroValues(targets.length),
23362
+ [...proposal.calldatas],
23363
+ hashIndexDtfProposalDescription(proposal.description)
23364
+ ];
23365
+ }
23366
+ function hashIndexDtfProposalDescription(description) {
23367
+ return keccak256(toBytes(description));
23368
+ }
23369
+ function getTimelockOperationId(proposal) {
23370
+ if (proposal.timelockId) return proposal.timelockId;
23371
+ return calculateLegacyTimelockOperationId(proposal);
23372
+ }
23373
+ function calculateLegacyTimelockOperationId(proposal) {
23374
+ const targets = proposal.targets;
23375
+ return keccak256(encodeAbiParameters(TIMELOCK_OPERATION_PARAMS, [
23376
+ targets,
23377
+ getZeroValues(targets.length),
23378
+ [...proposal.calldatas],
23379
+ zeroHash,
23380
+ getTimelockSalt(proposal.governance, proposal.description)
23381
+ ]));
23382
+ }
23383
+ function getTimelockSalt(governance, description) {
23384
+ const governorBytes = hexToBytes(pad(getAddress(governance).toLowerCase(), {
23385
+ size: 32,
23386
+ dir: "right"
23387
+ }));
23388
+ const descriptionHashBytes = hexToBytes(keccak256(toBytes(description)));
23389
+ const saltBytes = new Uint8Array(32);
23390
+ for (let i = 0; i < saltBytes.length; i++) saltBytes[i] = governorBytes[i] ^ descriptionHashBytes[i];
23391
+ return bytesToHex(saltBytes);
23392
+ }
23393
+ const TARGET_BASKET_TOLERANCE = 10n ** 13n;
23394
+ const PRICE_ERROR_BY_VOLATILITY = {
23395
+ low: .25,
23396
+ medium: .5,
23397
+ high: .75,
23398
+ degen: .9
23399
+ };
23400
+ const indexDtfBasketTokenSchema = z.object({
23401
+ address: z.string().refine(isAddress, "Invalid address"),
23402
+ decimals: z.number().int().min(0).max(255).optional(),
23403
+ price: z.number().positive().optional(),
23404
+ priceError: z.number().min(0).max(.9).optional(),
23405
+ priceVolatility: z.enum([
23406
+ "low",
23407
+ "medium",
23408
+ "high",
23409
+ "degen"
23410
+ ]).optional(),
23411
+ maxAuctionSizeUsd: z.number().positive().optional()
23412
+ });
23413
+ const indexDtfBasketSharesSchema = z.object({
23414
+ type: z.literal("shares"),
23415
+ tokens: z.array(indexDtfBasketTokenSchema.extend({ share: z.union([z.string(), z.number()]) }))
23416
+ });
23417
+ const indexDtfBasketUnitsSchema = z.object({
23418
+ type: z.literal("units"),
23419
+ tokens: z.array(indexDtfBasketTokenSchema.extend({ units: z.union([z.string(), z.number()]) }))
23420
+ });
23421
+ const indexDtfBasketSchema = z.union([indexDtfBasketSharesSchema, indexDtfBasketUnitsSchema]);
23422
+ //#endregion
23423
+ //#region src/index-dtf/dtf/basket/validation.ts
23424
+ function validateBasketTokens(tokens) {
23425
+ if (tokens.length === 0) throw new SdkError({
23426
+ code: "INVALID_INPUT",
23427
+ message: "Basket must include at least one token"
23428
+ });
23429
+ assertUniqueAddresses(tokens.map((token) => token.address));
23430
+ assertValidBasketAddresses(tokens.map((token) => token.address));
23431
+ for (const token of tokens) {
23432
+ if (!Number.isInteger(token.decimals) || token.decimals < 0) throw new SdkError({
23433
+ code: "INVALID_INPUT",
23434
+ message: `Invalid decimals for token ${token.address}`,
23435
+ meta: {
23436
+ address: token.address,
23437
+ decimals: token.decimals
23438
+ }
23439
+ });
23440
+ assertPositiveNumber(token.price, `price for token ${token.address}`);
23441
+ }
23442
+ }
23443
+ function assertValidBasketAddresses(addresses) {
23444
+ for (const address of addresses) if (address.toLowerCase() === zeroAddress) throw new SdkError({
23445
+ code: "INVALID_INPUT",
23446
+ message: "Basket token address cannot be the zero address",
23447
+ meta: { address }
23448
+ });
23449
+ }
23450
+ function assertNoDtfBasketToken(dtfAddress, tokens) {
23451
+ const dtfKey = dtfAddress.toLowerCase();
23452
+ for (const token of tokens) if (token.toLowerCase() === dtfKey) throw new SdkError({
23453
+ code: "INVALID_INPUT",
23454
+ message: "Basket token cannot be the DTF address",
23455
+ meta: {
23456
+ address: token,
23457
+ dtfAddress
23458
+ }
23459
+ });
23460
+ }
23461
+ function validateShares(shares) {
23462
+ let total = 0n;
23463
+ for (const share of shares) {
23464
+ if (share < 0n) throw new SdkError({
23465
+ code: "INVALID_INPUT",
23466
+ message: "Basket shares must be non-negative"
23467
+ });
23468
+ total += share;
23469
+ }
23470
+ if (total < D18n - TARGET_BASKET_TOLERANCE || total > D18n + TARGET_BASKET_TOLERANCE) throw new SdkError({
23471
+ code: "INVALID_INPUT",
23472
+ message: "Basket shares must add up to 100%",
23473
+ meta: { total }
23474
+ });
23475
+ }
23476
+ function assertUniqueAddresses(addresses) {
23477
+ const seen = /* @__PURE__ */ new Set();
23478
+ for (const address of addresses) {
23479
+ const key = getAddress(address).toLowerCase();
23480
+ if (seen.has(key)) throw new SdkError({
23481
+ code: "INVALID_INPUT",
23482
+ message: `Duplicate basket token ${address}`,
23483
+ meta: { address }
23484
+ });
23485
+ seen.add(key);
23486
+ }
23487
+ }
23488
+ function assertPositiveNumber(value, field) {
23489
+ if (!Number.isFinite(value) || value <= 0) throw new SdkError({
23490
+ code: "INVALID_INPUT",
23491
+ message: `${field} must be a positive number`,
23492
+ meta: { [field]: value }
23493
+ });
23494
+ }
23692
23495
  //#endregion
23693
- //#region src/index-dtf/abis/upgrade-spell-proposal.ts
23694
- const upgradeSpellProposalAbi = [
23695
- {
23696
- type: "function",
23697
- name: "cast",
23698
- inputs: [{
23699
- name: "folio",
23700
- type: "address"
23701
- }, {
23702
- name: "proxyAdmin",
23703
- type: "address"
23704
- }],
23705
- outputs: [],
23706
- stateMutability: "nonpayable"
23707
- },
23708
- {
23709
- type: "function",
23710
- name: "upgradeFolioGovernance",
23711
- inputs: [
23712
- {
23713
- name: "folio",
23714
- type: "address"
23715
- },
23716
- {
23717
- name: "proxyAdmin",
23718
- type: "address"
23719
- },
23720
- {
23721
- name: "oldOwnerGovernor",
23722
- type: "address"
23723
- },
23724
- {
23725
- name: "oldTradingGovernor",
23726
- type: "address"
23727
- },
23728
- {
23729
- name: "ownerGuardians",
23730
- type: "address[]"
23731
- },
23732
- {
23733
- name: "tradingGuardians",
23734
- type: "address[]"
23735
- },
23736
- {
23737
- name: "deploymentNonce",
23738
- type: "bytes32"
23739
- }
23740
- ],
23741
- outputs: [{
23742
- name: "newOwnerGovernor",
23743
- type: "address"
23744
- }, {
23745
- name: "newTradingGovernor",
23746
- type: "address"
23747
- }],
23748
- stateMutability: "nonpayable"
23749
- },
23750
- {
23751
- type: "function",
23752
- name: "upgradeStakingVaultGovernance",
23753
- inputs: [
23754
- {
23755
- name: "stakingVault",
23756
- type: "address"
23757
- },
23758
- {
23759
- name: "oldGovernor",
23760
- type: "address"
23761
- },
23762
- {
23763
- name: "guardians",
23764
- type: "address[]"
23765
- },
23766
- {
23767
- name: "deploymentNonce",
23768
- type: "bytes32"
23769
- }
23770
- ],
23771
- outputs: [{
23772
- name: "newGovernor",
23773
- type: "address"
23774
- }],
23775
- stateMutability: "nonpayable"
23496
+ //#region src/index-dtf/dtf/basket/math.ts
23497
+ function getBasketSharesFromUnits(params) {
23498
+ validateBasketTokens(params.tokens);
23499
+ let hasValue = false;
23500
+ for (const unit of params.units) {
23501
+ if (unit < 0n) throw new SdkError({
23502
+ code: "INVALID_INPUT",
23503
+ message: "Basket units must be non-negative"
23504
+ });
23505
+ if (unit > 0n) hasValue = true;
23776
23506
  }
23777
- ];
23507
+ if (!hasValue) throw new SdkError({
23508
+ code: "INVALID_INPUT",
23509
+ message: "Basket units must include at least one positive amount"
23510
+ });
23511
+ return getBasketDistribution([...params.units], params.tokens.map((token) => token.price), params.tokens.map((token) => BigInt(token.decimals)));
23512
+ }
23513
+ function getBasketUnitsFromShares(params) {
23514
+ assertPositiveNumber(params.targetValueUsd, "targetValueUsd");
23515
+ validateBasketTokens(params.tokens);
23516
+ validateShares(params.shares);
23517
+ return getUnitsFromShares(params.tokens, params.shares, new Decimal(params.targetValueUsd.toString()));
23518
+ }
23519
+ function getDtfPriceFromBalances(params) {
23520
+ if (params.supply <= 0n) throw new SdkError({
23521
+ code: "INVALID_INPUT",
23522
+ message: "supply must be positive",
23523
+ meta: { supply: params.supply }
23524
+ });
23525
+ validateBasketTokens(params.tokens);
23526
+ const totalValue = params.tokens.reduce((sum, token, index) => {
23527
+ const wholeTokens = new Decimal(params.balances[index].toString()).div(new Decimal(`1e${token.decimals}`));
23528
+ return sum.add(wholeTokens.mul(token.price));
23529
+ }, new Decimal(0));
23530
+ const supply = new Decimal(params.supply.toString()).div(D18d);
23531
+ return totalValue.div(supply).toNumber();
23532
+ }
23533
+ function buildInitialBasket(params) {
23534
+ assertPositiveNumber(params.initialSharePriceUsd, "initialSharePriceUsd");
23535
+ if (params.initialShares <= 0n) throw new SdkError({
23536
+ code: "INVALID_INPUT",
23537
+ message: "initialShares must be positive",
23538
+ meta: { initialShares: params.initialShares }
23539
+ });
23540
+ validateBasketTokens(params.tokens);
23541
+ const shares = getBasketShares(params.tokens, params.basket);
23542
+ const amounts = params.basket.type === "units" ? getScaledUnits(params.tokens, params.basket.units, getInitialValueUsd(params)) : getUnitsFromShares(params.tokens, shares, getInitialValueUsd(params));
23543
+ for (const amount of amounts) if (amount <= 0n) throw new SdkError({
23544
+ code: "INVALID_INPUT",
23545
+ message: "Initial basket amounts must be positive"
23546
+ });
23547
+ return {
23548
+ assets: params.tokens.map((token) => token.address),
23549
+ amounts,
23550
+ initialShares: params.initialShares,
23551
+ shares
23552
+ };
23553
+ }
23554
+ function getBasketShares(tokens, basket) {
23555
+ if (basket.type === "shares") {
23556
+ validateShares(basket.shares);
23557
+ return [...basket.shares];
23558
+ }
23559
+ return getBasketSharesFromUnits({
23560
+ tokens,
23561
+ units: basket.units
23562
+ });
23563
+ }
23564
+ function getInitialValueUsd(params) {
23565
+ return new Decimal(params.initialShares.toString()).div(D18d).mul(params.initialSharePriceUsd);
23566
+ }
23567
+ function getUnitsFromShares(tokens, shares, targetValueUsd) {
23568
+ return tokens.map((token, index) => {
23569
+ return parseUnits(targetValueUsd.mul(new Decimal(shares[index].toString()).div(D18d)).div(token.price).toFixed(token.decimals), token.decimals);
23570
+ });
23571
+ }
23572
+ function getScaledUnits(tokens, units, targetValueUsd) {
23573
+ const currentValueUsd = units.reduce((sum, unit, index) => {
23574
+ const token = tokens[index];
23575
+ const wholeTokens = new Decimal(unit.toString()).div(new Decimal(`1e${token.decimals}`));
23576
+ return sum.add(wholeTokens.mul(token.price));
23577
+ }, new Decimal(0));
23578
+ if (currentValueUsd.lte(0)) throw new SdkError({
23579
+ code: "INVALID_INPUT",
23580
+ message: "Basket units must have positive USD value"
23581
+ });
23582
+ const scale = targetValueUsd.div(currentValueUsd);
23583
+ return units.map((unit) => BigInt(new Decimal(unit.toString()).mul(scale).toFixed(0)));
23584
+ }
23778
23585
  //#endregion
23779
- //#region src/index-dtf/governance/contract-map.ts
23780
- const EXTRA_PROPOSAL_CONTRACTS = [
23781
- {
23782
- contract: "GovernanceSpell_31_03_2025",
23783
- abi: upgradeSpellProposalAbi,
23784
- addresses: {
23785
- 1: "0x4491b242f15f8dc9c6dfbb9a08edbbaae2623199",
23786
- 8453: "0x587cefb69473ad467993c6dd3a8f202bf1ef5e2a"
23787
- }
23788
- },
23789
- {
23790
- contract: "V4 Upgrade Spell",
23791
- abi: upgradeSpellProposalAbi,
23792
- addresses: {
23793
- 1: "0x7498c6aB0669A09DE7B9185ba72A98fa3Ca39cC9",
23794
- 8453: "0x4720dbCAEEF5834AEf590781F93d70fD1e3AcADB"
23795
- }
23796
- },
23797
- {
23798
- contract: "V5 Upgrade Spell",
23799
- abi: upgradeSpellProposalAbi,
23800
- addresses: {
23801
- 1: "0x044B6F685FB8D0c3fd56D92FCBE5F0Ad947d2D53",
23802
- 8453: "0x04B3eD311C68dfB0649D9faf695115F23DcbB540",
23803
- 56: "0xe8e67a366e5166c442B6D376ADc772b93CdE7825"
23586
+ //#region src/index-dtf/dtf/basket/rebalance-args.ts
23587
+ function buildStartRebalanceArgs(params) {
23588
+ if (params.supply <= 0n) throw new SdkError({
23589
+ code: "INVALID_INPUT",
23590
+ message: "supply must be positive",
23591
+ meta: { supply: params.supply }
23592
+ });
23593
+ if (params.deferWeights && !params.weightControl) throw new SdkError({
23594
+ code: "INVALID_INPUT",
23595
+ message: "deferWeights is only supported for weight-control baskets"
23596
+ });
23597
+ validateBasketTokens(params.tokens);
23598
+ const targetShares = getBasketShares(params.tokens, params.basket);
23599
+ for (const priceError of params.priceErrors) if (priceError < 0 || priceError > .9) throw new SdkError({
23600
+ code: "INVALID_INPUT",
23601
+ message: "priceErrors must be between 0 and 0.9",
23602
+ meta: { priceError }
23603
+ });
23604
+ for (const maxAuctionSizeUsd of params.maxAuctionSizesUsd) assertPositiveNumber(maxAuctionSizeUsd, "maxAuctionSizeUsd");
23605
+ return getStartRebalance(FolioVersion.V5, params.supply, params.tokens.map((token) => token.address), [...params.balances], params.tokens.map((token) => BigInt(token.decimals)), targetShares, params.tokens.map((token) => token.price), [...params.priceErrors], [...params.maxAuctionSizesUsd], params.weightControl, params.deferWeights ?? false);
23606
+ }
23607
+ //#endregion
23608
+ //#region src/index-dtf/dtf/basket/current.ts
23609
+ async function getCurrentBalances(client, params) {
23610
+ return normalizeCurrentBalances(params.currentBalances ?? await getTotalAssets(client, params));
23611
+ }
23612
+ async function getDtfForWeightControl(client, params) {
23613
+ if (params.weightControl !== void 0) return params.dtf;
23614
+ return params.dtf ?? getDtf(client, params);
23615
+ }
23616
+ function getBasketTokenOrder(currentBalances, inputTokens) {
23617
+ const addresses = [];
23618
+ const seen = /* @__PURE__ */ new Set();
23619
+ const add = (token) => {
23620
+ const address = getAddress(token);
23621
+ const key = address.toLowerCase();
23622
+ if (!seen.has(key)) {
23623
+ seen.add(key);
23624
+ addresses.push(address);
23804
23625
  }
23626
+ };
23627
+ for (const token of Object.keys(currentBalances)) add(token);
23628
+ for (const token of inputTokens) add(token.address);
23629
+ return addresses;
23630
+ }
23631
+ function normalizeCurrentBalances(input) {
23632
+ if (Array.isArray(input)) {
23633
+ const result = {};
23634
+ for (const item of input) result[getAddress(item.address).toLowerCase()] = item.balance;
23635
+ return result;
23636
+ }
23637
+ if (isTotalAssetsInput(input)) {
23638
+ const result = {};
23639
+ for (let i = 0; i < input.tokens.length; i++) result[getAddress(input.tokens[i]).toLowerCase()] = input.balances[i] ?? 0n;
23640
+ return result;
23805
23641
  }
23806
- ];
23807
- function buildProposalContractMap({ chainId, dtf, proposalGovernance }) {
23808
- const contracts = /* @__PURE__ */ new Map();
23809
- addContract(contracts, dtf.address, "Index DTF", dtfIndexProposalAbi);
23810
- addContract(contracts, dtf.proxyAdmin, "ProxyAdmin", dtfAdminProposalAbi);
23811
- const hasSharedOwnerAndBasketGovernance = dtf.ownerGovernance && dtf.tradingGovernance && dtf.ownerGovernance.address.toLowerCase() === dtf.tradingGovernance.address.toLowerCase();
23812
- for (const governance of dtf.legacyAdminGovernance) addContract(contracts, governance, "Legacy Owner Governance", dtfIndexGovernanceProposalAbi);
23813
- for (const governance of dtf.legacyTradingGovernance) addContract(contracts, governance, "Legacy Basket Governance", dtfIndexGovernanceProposalAbi);
23814
- if (hasSharedOwnerAndBasketGovernance) {
23815
- addContract(contracts, dtf.ownerGovernance.address, "Owner/Basket Governance", dtfIndexGovernanceProposalAbi);
23816
- addContract(contracts, dtf.ownerGovernance.timelock, "Owner/Basket Governance Timelock", timelockAbi);
23817
- } else if (dtf.ownerGovernance) {
23818
- addContract(contracts, dtf.ownerGovernance.address, "Owner Governance", dtfIndexGovernanceProposalAbi);
23819
- addContract(contracts, dtf.ownerGovernance.timelock, "Owner Governance Timelock", timelockAbi);
23642
+ const result = {};
23643
+ for (const [token, balance] of Object.entries(input)) result[getAddress(token).toLowerCase()] = balance;
23644
+ return result;
23645
+ }
23646
+ function isTotalAssetsInput(input) {
23647
+ if (Array.isArray(input)) return false;
23648
+ const value = input;
23649
+ return Array.isArray(value.tokens) && Array.isArray(value.balances);
23650
+ }
23651
+ //#endregion
23652
+ //#region src/index-dtf/dtf/basket/input.ts
23653
+ function getBasketFromInput(input, tokenOrder, tokens) {
23654
+ const inputByAddress = new Map(input.tokens.map((token) => [getAddress(token.address).toLowerCase(), token]));
23655
+ if (input.type === "shares") {
23656
+ const shares = tokenOrder.map((address) => {
23657
+ const token = inputByAddress.get(address.toLowerCase());
23658
+ return token && "share" in token ? parseShare(token.share) : 0n;
23659
+ });
23660
+ validateShares(shares);
23661
+ return {
23662
+ type: "shares",
23663
+ shares
23664
+ };
23820
23665
  }
23821
- if (!hasSharedOwnerAndBasketGovernance && dtf.tradingGovernance) {
23822
- addContract(contracts, dtf.tradingGovernance.address, "Basket Governance", dtfIndexGovernanceProposalAbi);
23823
- addContract(contracts, dtf.tradingGovernance.timelock, "Basket Governance Timelock", timelockAbi);
23666
+ return {
23667
+ type: "units",
23668
+ units: tokenOrder.map((address, index) => {
23669
+ const token = inputByAddress.get(address.toLowerCase());
23670
+ return token && "units" in token ? parseTokenUnits(token.units, tokens[index].decimals) : 0n;
23671
+ })
23672
+ };
23673
+ }
23674
+ function parseTokenUnits(value, decimals) {
23675
+ const units = toDecimal(value, "units");
23676
+ if (units.isNegative()) throw new SdkError({
23677
+ code: "INVALID_INPUT",
23678
+ message: "Basket token units must be non-negative",
23679
+ meta: { units: value }
23680
+ });
23681
+ return parseUnits(units.toFixed(decimals), decimals);
23682
+ }
23683
+ function parseShare(value) {
23684
+ const share = toDecimal(value, "share");
23685
+ if (share.isNegative() || share.gt(100)) throw new SdkError({
23686
+ code: "INVALID_INPUT",
23687
+ message: "Basket token shares must be between 0 and 100",
23688
+ meta: { share: value }
23689
+ });
23690
+ return parseUnits(share.toFixed(16), 16);
23691
+ }
23692
+ function toDecimal(value, field) {
23693
+ try {
23694
+ return new Decimal(String(value));
23695
+ } catch (cause) {
23696
+ throw new SdkError({
23697
+ code: "INVALID_INPUT",
23698
+ message: `${field} must be a valid number`,
23699
+ cause,
23700
+ meta: { [field]: value }
23701
+ });
23824
23702
  }
23825
- addContract(contracts, dtf.stakingToken.address, "Lock Vault", dtfIndexStakingVaultAbi);
23826
- for (const governance of dtf.stakingToken.legacyGovernance) addContract(contracts, governance, "Legacy Lock Governance", dtfIndexGovernanceProposalAbi);
23827
- if (dtf.stakingToken.governance) {
23828
- addContract(contracts, dtf.stakingToken.governance.address, "Lock Governance", dtfIndexGovernanceProposalAbi);
23829
- addContract(contracts, dtf.stakingToken.governance.timelock, "Lock Governance Timelock", timelockAbi);
23703
+ }
23704
+ //#endregion
23705
+ //#region src/index-dtf/dtf/basket/token-data.ts
23706
+ async function getBasketTokens(client, params, tokenOrder, inputTokens) {
23707
+ const fetchedTokens = await getTokensData(client.viem.getPublicClient(params.chainId), [...tokenOrder]);
23708
+ const decimalsByAddress = /* @__PURE__ */ new Map();
23709
+ for (const [address, decimals] of Object.entries(params.tokenDecimals ?? {})) decimalsByAddress.set(getAddress(address).toLowerCase(), decimals);
23710
+ for (const token of inputTokens) if (token.decimals !== void 0) decimalsByAddress.set(token.address.toLowerCase(), token.decimals);
23711
+ return fetchedTokens.map((token) => ({
23712
+ ...token,
23713
+ decimals: decimalsByAddress.get(token.address.toLowerCase()) ?? token.decimals
23714
+ }));
23715
+ }
23716
+ async function getBasketPrices(client, params, tokenOrder, inputTokens) {
23717
+ const prices = /* @__PURE__ */ new Map();
23718
+ for (const [address, price] of Object.entries(params.prices ?? {})) prices.set(getAddress(address).toLowerCase(), price);
23719
+ for (const token of inputTokens) if (token.price !== void 0) prices.set(token.address.toLowerCase(), token.price);
23720
+ const missing = tokenOrder.filter((address) => prices.get(address.toLowerCase()) === void 0);
23721
+ if (missing.length > 0) {
23722
+ const fetchedPrices = await getTokenPrices(client, {
23723
+ chainId: params.chainId,
23724
+ addresses: missing
23725
+ });
23726
+ for (const token of fetchedPrices) prices.set(token.address.toLowerCase(), token.price);
23830
23727
  }
23831
- if (proposalGovernance) {
23832
- addContract(contracts, proposalGovernance.address, getGovernanceContractName(proposalGovernance.timelock.type), dtfIndexGovernanceProposalAbi);
23833
- addContract(contracts, proposalGovernance.timelock.address, getTimelockContractName(proposalGovernance.timelock.type), timelockAbi);
23728
+ return tokenOrder.map((address) => {
23729
+ const price = prices.get(address.toLowerCase());
23730
+ if (price === void 0 || !Number.isFinite(price) || price <= 0) throw new SdkError({
23731
+ code: "INVALID_INPUT",
23732
+ message: `Missing price for token ${address}`,
23733
+ meta: {
23734
+ address,
23735
+ chainId: params.chainId
23736
+ }
23737
+ });
23738
+ return price;
23739
+ });
23740
+ }
23741
+ async function getBasketPriceErrors(client, params, tokenOrder, inputTokens) {
23742
+ const explicitErrors = /* @__PURE__ */ new Map();
23743
+ const explicitVolatilities = /* @__PURE__ */ new Map();
23744
+ for (const [address, priceError] of Object.entries(params.priceErrors ?? {})) explicitErrors.set(getAddress(address).toLowerCase(), priceError);
23745
+ for (const [address, volatility] of Object.entries(params.priceVolatilities ?? {})) explicitVolatilities.set(getAddress(address).toLowerCase(), volatility);
23746
+ for (const token of inputTokens) {
23747
+ if (token.priceError !== void 0) explicitErrors.set(token.address.toLowerCase(), token.priceError);
23748
+ if (token.priceVolatility !== void 0) explicitVolatilities.set(token.address.toLowerCase(), token.priceVolatility);
23834
23749
  }
23835
- for (const extraContract of EXTRA_PROPOSAL_CONTRACTS) addContract(contracts, extraContract.addresses[chainId], extraContract.contract, extraContract.abi);
23836
- return contracts;
23750
+ const missingVolatility = tokenOrder.filter((address) => {
23751
+ const key = address.toLowerCase();
23752
+ return !explicitErrors.has(key) && !explicitVolatilities.has(key);
23753
+ });
23754
+ const fetchedVolatilities = missingVolatility.length > 0 ? await getTokenVolatilities(client, {
23755
+ chainId: params.chainId,
23756
+ addresses: missingVolatility
23757
+ }) : {};
23758
+ const fetchedVolatilityByAddress = new Map(Object.entries(fetchedVolatilities).map(([address, volatility]) => [address.toLowerCase(), volatility]));
23759
+ return tokenOrder.map((address) => {
23760
+ const key = address.toLowerCase();
23761
+ const volatility = explicitVolatilities.get(key) ?? fetchedVolatilityByAddress.get(key) ?? "medium";
23762
+ const priceError = explicitErrors.get(key) ?? PRICE_ERROR_BY_VOLATILITY[volatility];
23763
+ if (priceError < 0 || priceError > .9) throw new SdkError({
23764
+ code: "INVALID_INPUT",
23765
+ message: `Invalid price error for token ${address}`,
23766
+ meta: {
23767
+ address,
23768
+ priceError
23769
+ }
23770
+ });
23771
+ return priceError;
23772
+ });
23773
+ }
23774
+ function getMaxAuctionSizes(params, tokenOrder, inputTokens) {
23775
+ const inputByAddress = new Map(inputTokens.map((token) => [token.address.toLowerCase(), token]));
23776
+ const sizes = /* @__PURE__ */ new Map();
23777
+ for (const [address, size] of Object.entries(params.maxAuctionSizesUsd ?? {})) sizes.set(getAddress(address).toLowerCase(), size);
23778
+ return tokenOrder.map((address) => {
23779
+ const key = address.toLowerCase();
23780
+ const size = inputByAddress.get(key)?.maxAuctionSizeUsd ?? sizes.get(key) ?? params.maxAuctionSizeUsd ?? 1e6;
23781
+ assertPositiveNumber(size, "maxAuctionSizeUsd");
23782
+ return size;
23783
+ });
23784
+ }
23785
+ //#endregion
23786
+ //#region src/index-dtf/dtf/basket/start-rebalance.ts
23787
+ async function buildIndexDtfStartRebalance(client, params) {
23788
+ const address = getAddress(params.address);
23789
+ const inputTokens = params.basket.tokens.map((token) => ({
23790
+ ...token,
23791
+ address: getAddress(token.address)
23792
+ }));
23793
+ assertUniqueAddresses(inputTokens.map((token) => token.address));
23794
+ assertValidBasketAddresses(inputTokens.map((token) => token.address));
23795
+ assertNoDtfBasketToken(address, inputTokens.map((token) => token.address));
23796
+ const [currentBalances, supply, dtf] = await Promise.all([
23797
+ getCurrentBalances(client, params),
23798
+ params.supply ?? getTotalSupply(client, params),
23799
+ getDtfForWeightControl(client, params)
23800
+ ]);
23801
+ const tokenOrder = getBasketTokenOrder(currentBalances, inputTokens);
23802
+ assertValidBasketAddresses(tokenOrder);
23803
+ assertNoDtfBasketToken(address, tokenOrder);
23804
+ const [tokens, prices] = await Promise.all([getBasketTokens(client, params, tokenOrder, inputTokens), getBasketPrices(client, params, tokenOrder, inputTokens)]);
23805
+ const pricedTokens = tokens.map((token, index) => ({
23806
+ ...token,
23807
+ price: prices[index]
23808
+ }));
23809
+ const targetBasket = getBasketFromInput(params.basket, tokenOrder, pricedTokens);
23810
+ const [priceErrors, maxAuctionSizesUsd] = await Promise.all([getBasketPriceErrors(client, params, tokenOrder, inputTokens), Promise.resolve(getMaxAuctionSizes(params, tokenOrder, inputTokens))]);
23811
+ const weightControl = params.weightControl ?? dtf?.rebalance.weightControl;
23812
+ if (weightControl === void 0) throw new SdkError({
23813
+ code: "INVALID_INPUT",
23814
+ message: "weightControl is required when DTF context is not provided",
23815
+ meta: {
23816
+ address,
23817
+ chainId: params.chainId
23818
+ }
23819
+ });
23820
+ const balances = tokenOrder.map((token) => currentBalances[token.toLowerCase()] ?? 0n);
23821
+ const targetShares = getBasketShares(pricedTokens, targetBasket);
23822
+ return {
23823
+ address,
23824
+ chainId: params.chainId,
23825
+ tokens: pricedTokens,
23826
+ assets: pricedTokens.map((token, index) => ({
23827
+ token,
23828
+ currentBalance: balances[index],
23829
+ targetShare: targetShares[index],
23830
+ priceError: priceErrors[index],
23831
+ maxAuctionSizeUsd: maxAuctionSizesUsd[index]
23832
+ })),
23833
+ supply,
23834
+ weightControl,
23835
+ deferWeights: params.deferWeights ?? false,
23836
+ startRebalanceArgs: buildStartRebalanceArgs({
23837
+ tokens: pricedTokens,
23838
+ supply,
23839
+ balances,
23840
+ basket: targetBasket,
23841
+ priceErrors,
23842
+ maxAuctionSizesUsd,
23843
+ weightControl,
23844
+ deferWeights: params.deferWeights ?? false
23845
+ })
23846
+ };
23847
+ }
23848
+ //#endregion
23849
+ //#region src/index-dtf/governance/propose/basket.ts
23850
+ const MAX_REBALANCE_TTL = 604800n * 4n;
23851
+ async function buildIndexDtfBasketProposal(client, params) {
23852
+ const windows = getRebalanceWindows(params);
23853
+ validateBasketTokenAddresses(params);
23854
+ const dtf = await getDtfForProposal(client, params);
23855
+ const context = {
23856
+ ...await buildIndexDtfStartRebalance(client, {
23857
+ ...params,
23858
+ ...dtf ? { dtf } : {}
23859
+ }),
23860
+ chainId: params.chainId,
23861
+ ...windows
23862
+ };
23863
+ const authority = getProposalAuthority(params, dtf);
23864
+ const call = prepareIndexDtfBasketRebalance(context);
23865
+ return {
23866
+ governance: authority.governance,
23867
+ targets: [call.to],
23868
+ calldatas: [call.data],
23869
+ description: params.description ?? "",
23870
+ context
23871
+ };
23837
23872
  }
23838
- function getContractAliases(contractMap) {
23839
- const aliases = {};
23840
- for (const contract of contractMap.values()) aliases[contract.target] = contract.contract;
23841
- return aliases;
23873
+ function prepareIndexDtfBasketRebalance(context) {
23874
+ const args = getStartRebalanceArgs(context);
23875
+ return prepareContractCall({
23876
+ chainId: context.chainId,
23877
+ address: context.address,
23878
+ abi: dtfIndexAbi,
23879
+ functionName: "startRebalance",
23880
+ args
23881
+ });
23842
23882
  }
23843
- function addContract(contracts, target, contract, abi) {
23844
- if (!target) return;
23845
- const address = getAddress(target);
23846
- const key = address.toLowerCase();
23847
- if (contracts.has(key)) return;
23848
- contracts.set(key, {
23849
- target: address,
23850
- contract,
23851
- abi
23883
+ async function getDtfForProposal(client, params) {
23884
+ if (params.dtf || params.governance && params.weightControl !== void 0) return params.dtf;
23885
+ return getDtf(client, params);
23886
+ }
23887
+ function getStartRebalanceArgs(context) {
23888
+ const startRebalanceArgs = context.startRebalanceArgs;
23889
+ return [
23890
+ startRebalanceArgs.tokens.map((token) => ({
23891
+ ...token,
23892
+ token: getAddress(token.token)
23893
+ })),
23894
+ startRebalanceArgs.limits,
23895
+ context.auctionLauncherWindow,
23896
+ context.ttl
23897
+ ];
23898
+ }
23899
+ function getProposalAuthority(params, dtf) {
23900
+ const authority = dtf?.governance.rebalance.primary;
23901
+ const resolvedGovernance = params.governance ?? (authority?.type === "governance" ? authority.address : void 0);
23902
+ if (!resolvedGovernance) throw new SdkError({
23903
+ code: "INVALID_INPUT",
23904
+ message: "governance is required to build an Index DTF basket proposal",
23905
+ meta: { governance: resolvedGovernance }
23852
23906
  });
23907
+ return { governance: resolvedGovernance };
23853
23908
  }
23854
- function getGovernanceContractName(type) {
23855
- if (type === "OWNER") return "Owner Governance";
23856
- if (type === "TRADING") return "Basket Governance";
23857
- if (type === "VOTE_LOCKING") return "Lock Governance";
23858
- return "Governance";
23909
+ function validateBasketTokenAddresses(params) {
23910
+ const dtfAddress = getAddress(params.address);
23911
+ for (const token of params.basket.tokens) {
23912
+ const address = getAddress(token.address);
23913
+ if (address.toLowerCase() === zeroAddress) throw new SdkError({
23914
+ code: "INVALID_INPUT",
23915
+ message: "Basket token address cannot be the zero address",
23916
+ meta: { address }
23917
+ });
23918
+ if (address.toLowerCase() === dtfAddress.toLowerCase()) throw new SdkError({
23919
+ code: "INVALID_INPUT",
23920
+ message: "Basket token cannot be the DTF address",
23921
+ meta: {
23922
+ address,
23923
+ dtfAddress
23924
+ }
23925
+ });
23926
+ }
23859
23927
  }
23860
- function getTimelockContractName(type) {
23861
- if (type === "OWNER") return "Owner Governance Timelock";
23862
- if (type === "TRADING") return "Basket Governance Timelock";
23863
- if (type === "VOTE_LOCKING") return "Lock Governance Timelock";
23864
- return "Governance Timelock";
23928
+ function getRebalanceWindows(params) {
23929
+ const auctionLauncherWindow = toSeconds(params.auctionLauncherWindow ?? 259200, "auctionLauncherWindow");
23930
+ const ttl = params.ttl === void 0 ? auctionLauncherWindow + toSeconds(params.permissionlessWindow ?? 0, "permissionlessWindow") : toSeconds(params.ttl, "ttl", { allowZero: false });
23931
+ if (ttl === 0n) throw new SdkError({
23932
+ code: "INVALID_INPUT",
23933
+ message: "ttl must be a positive number of seconds",
23934
+ meta: { ttl }
23935
+ });
23936
+ if (ttl < auctionLauncherWindow) throw new SdkError({
23937
+ code: "INVALID_INPUT",
23938
+ message: "ttl must be greater than or equal to auctionLauncherWindow",
23939
+ meta: {
23940
+ ttl,
23941
+ auctionLauncherWindow
23942
+ }
23943
+ });
23944
+ if (ttl > MAX_REBALANCE_TTL) throw new SdkError({
23945
+ code: "INVALID_INPUT",
23946
+ message: "ttl must be less than or equal to 4 weeks",
23947
+ meta: {
23948
+ ttl,
23949
+ maxTtl: MAX_REBALANCE_TTL
23950
+ }
23951
+ });
23952
+ return {
23953
+ auctionLauncherWindow,
23954
+ ttl
23955
+ };
23956
+ }
23957
+ function toSeconds(value, field, options = {}) {
23958
+ const allowZero = options.allowZero ?? true;
23959
+ if (typeof value === "bigint") {
23960
+ if (value < 0n || !allowZero && value === 0n) throw new SdkError({
23961
+ code: "INVALID_INPUT",
23962
+ message: `${field} must be a ${allowZero ? "non-negative" : "positive"} number of seconds`,
23963
+ meta: { [field]: value }
23964
+ });
23965
+ return value;
23966
+ }
23967
+ if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0 || !allowZero && value === 0) throw new SdkError({
23968
+ code: "INVALID_INPUT",
23969
+ message: `${field} must be a ${allowZero ? "non-negative" : "positive"} number of seconds`,
23970
+ meta: { [field]: value }
23971
+ });
23972
+ return BigInt(value);
23865
23973
  }
23866
23974
  //#endregion
23867
- //#region src/index-dtf/abis/selector-registry.ts
23868
- const selectorRegistryAbi = [
23869
- {
23870
- type: "function",
23871
- name: "governor",
23872
- inputs: [],
23873
- outputs: [{
23874
- name: "",
23875
- type: "address",
23876
- internalType: "address"
23877
- }],
23878
- stateMutability: "view"
23879
- },
23880
- {
23881
- type: "function",
23882
- name: "isAllowed",
23883
- inputs: [{
23884
- name: "target",
23885
- type: "address",
23886
- internalType: "address"
23887
- }, {
23888
- name: "selector",
23889
- type: "bytes4",
23890
- internalType: "bytes4"
23891
- }],
23892
- outputs: [{
23893
- name: "",
23894
- type: "bool",
23895
- internalType: "bool"
23896
- }],
23897
- stateMutability: "view"
23898
- },
23899
- {
23900
- type: "function",
23901
- name: "registerSelectors",
23902
- inputs: [{
23903
- name: "selectorData",
23904
- type: "tuple[]",
23905
- internalType: "struct IOptimisticSelectorRegistry.SelectorData[]",
23906
- components: [{
23907
- name: "target",
23908
- type: "address",
23909
- internalType: "address"
23910
- }, {
23911
- name: "selectors",
23912
- type: "bytes4[]",
23913
- internalType: "bytes4[]"
23914
- }]
23915
- }],
23916
- outputs: [],
23917
- stateMutability: "nonpayable"
23918
- },
23919
- {
23920
- type: "function",
23921
- name: "selectorsAllowed",
23922
- inputs: [{
23923
- name: "target",
23924
- type: "address",
23925
- internalType: "address"
23926
- }],
23927
- outputs: [{
23928
- name: "allowedSelectors4",
23929
- type: "bytes4[]",
23930
- internalType: "bytes4[]"
23931
- }],
23932
- stateMutability: "view"
23933
- },
23934
- {
23935
- type: "function",
23936
- name: "targets",
23937
- inputs: [],
23938
- outputs: [{
23939
- name: "",
23940
- type: "address[]",
23941
- internalType: "address[]"
23942
- }],
23943
- stateMutability: "view"
23944
- },
23945
- {
23946
- type: "function",
23947
- name: "unregisterSelectors",
23948
- inputs: [{
23949
- name: "selectorData",
23950
- type: "tuple[]",
23951
- internalType: "struct IOptimisticSelectorRegistry.SelectorData[]",
23952
- components: [{
23953
- name: "target",
23954
- type: "address",
23955
- internalType: "address"
23956
- }, {
23957
- name: "selectors",
23958
- type: "bytes4[]",
23959
- internalType: "bytes4[]"
23960
- }]
23961
- }],
23962
- outputs: [],
23963
- stateMutability: "nonpayable"
23975
+ //#region src/index-dtf/governance/propose/settings-governance.ts
23976
+ function buildGovernanceCalls({ changes, chainId, governance, quorumDenominator, timelock }) {
23977
+ if (!changes) return [];
23978
+ if (!governance) throw new SdkError({
23979
+ code: "INVALID_INPUT",
23980
+ message: "governance is required to build governance settings calls"
23981
+ });
23982
+ validateGovernanceChanges(changes);
23983
+ const calls = [];
23984
+ if (changes.votingDelay !== void 0) calls.push(prepareContractCall({
23985
+ chainId,
23986
+ address: governance,
23987
+ abi: dtfIndexGovernanceAbi,
23988
+ functionName: "setVotingDelay",
23989
+ args: [changes.votingDelay]
23990
+ }));
23991
+ if (changes.votingPeriod !== void 0) calls.push(prepareContractCall({
23992
+ chainId,
23993
+ address: governance,
23994
+ abi: dtfIndexGovernanceAbi,
23995
+ functionName: "setVotingPeriod",
23996
+ args: [changes.votingPeriod]
23997
+ }));
23998
+ if (changes.proposalThreshold !== void 0) calls.push(prepareContractCall({
23999
+ chainId,
24000
+ address: governance,
24001
+ abi: dtfIndexGovernanceAbi,
24002
+ functionName: "setProposalThreshold",
24003
+ args: [encodePercent(changes.proposalThreshold)]
24004
+ }));
24005
+ if (changes.quorumPercent !== void 0) {
24006
+ if (quorumDenominator === void 0) throw new SdkError({
24007
+ code: "INVALID_INPUT",
24008
+ message: "quorumDenominator is required to build a quorum proposal"
24009
+ });
24010
+ calls.push(prepareContractCall({
24011
+ chainId,
24012
+ address: governance,
24013
+ abi: dtfIndexGovernanceAbi,
24014
+ functionName: "updateQuorumNumerator",
24015
+ args: [getQuorumNumerator(changes.quorumPercent, quorumDenominator)]
24016
+ }));
23964
24017
  }
23965
- ];
24018
+ if (changes.executionDelay !== void 0) {
24019
+ if (!timelock) throw new SdkError({
24020
+ code: "INVALID_INPUT",
24021
+ message: "timelock is required to build an execution delay proposal"
24022
+ });
24023
+ const functionName = "updateDelay";
24024
+ const args = [BigInt(Math.round(changes.executionDelay))];
24025
+ calls.push(prepareContractCall({
24026
+ chainId,
24027
+ address: timelock,
24028
+ abi: timelockAbi,
24029
+ functionName,
24030
+ args
24031
+ }));
24032
+ }
24033
+ return calls;
24034
+ }
24035
+ function validateGovernanceChanges(changes) {
24036
+ if (changes.votingDelay !== void 0) assertNumberRange(changes.votingDelay, "votingDelay", 0);
24037
+ if (changes.votingPeriod !== void 0) assertNumberRange(changes.votingPeriod, "votingPeriod", 0);
24038
+ if (changes.proposalThreshold !== void 0) assertNumberRange(changes.proposalThreshold, "proposalThreshold", 0, 100);
24039
+ if (changes.quorumPercent !== void 0) assertNumberRange(changes.quorumPercent, "quorumPercent", 0, 100);
24040
+ if (changes.executionDelay !== void 0) assertNumberRange(changes.executionDelay, "executionDelay", 0);
24041
+ }
24042
+ function assertNumberRange(value, field, min, max) {
24043
+ if (!Number.isFinite(value) || value < min || max !== void 0 && value > max) throw new SdkError({
24044
+ code: "INVALID_INPUT",
24045
+ message: max === void 0 ? `${field} must be greater than or equal to ${min}` : `${field} must be between ${min} and ${max}`,
24046
+ meta: { [field]: value }
24047
+ });
24048
+ }
24049
+ function encodePercent(percentage) {
24050
+ return parseEther(new Decimal$1(percentage).div(100).toFixed());
24051
+ }
24052
+ function getQuorumNumerator(percent, denominator) {
24053
+ const basisPoints = Math.round(percent * 100);
24054
+ return BigInt(basisPoints) * BigInt(denominator) / 10000n;
24055
+ }
23966
24056
  //#endregion
23967
- //#region src/index-dtf/governance/decoder.ts
23968
- const UNKNOWN_CONTRACT = "Unknown";
23969
- const FALLBACK_DECODERS = [{
23970
- contract: "Selector Registry",
23971
- abi: selectorRegistryAbi
23972
- }];
23973
- function decodeIndexDtfProposalCalldatas({ targets, calldatas, contractMap }) {
24057
+ //#region src/index-dtf/governance/propose/settings-roles.ts
24058
+ const GUARDIAN_ROLE = "0xfd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783";
24059
+ const BRAND_MANAGER_ROLE = "0x2d8e650da9bd8c373ab2450d770f2ed39549bfc28d3630025cecc51511bcd374";
24060
+ const AUCTION_LAUNCHER_ROLE = "0x13ff1b2625181b311f257c723b5e6d366eb318b212d9dd694c48fcf227659df5";
24061
+ const CANCELLER_ROLE$1 = keccak256(toBytes("CANCELLER_ROLE"));
24062
+ function buildRoleDiffCalls({ abi, chainId, current, next, role, target }) {
24063
+ if (!next) return [];
24064
+ if (!target) throw new SdkError({
24065
+ code: "INVALID_INPUT",
24066
+ message: "target is required to build role calls",
24067
+ meta: { role }
24068
+ });
23974
24069
  const calls = [];
23975
- const unknownCalls = [];
23976
- const dataByContract = [];
23977
- const unknownContracts = [];
23978
- const dataGroupMap = /* @__PURE__ */ new Map();
23979
- const unknownGroupMap = /* @__PURE__ */ new Map();
23980
- for (let i = 0; i < targets.length; i++) {
23981
- const target = targets[i];
23982
- const callData = calldatas[i];
23983
- const targetAddress = getAddress(target);
23984
- const targetKey = targetAddress.toLowerCase();
23985
- const contractDecoder = contractMap.get(targetKey);
23986
- if (!contractDecoder) {
23987
- const fallbackDecoded = decodeFallbackProposalCalldata(i, targetAddress, callData);
23988
- if (fallbackDecoded) {
23989
- calls.push(fallbackDecoded);
23990
- pushDecodedContractGroup(dataByContract, dataGroupMap, fallbackDecoded);
23991
- continue;
23992
- }
23993
- const unknownCall = {
23994
- index: i,
23995
- target: targetAddress,
23996
- contract: UNKNOWN_CONTRACT,
23997
- callData
23998
- };
23999
- unknownCalls.push(unknownCall);
24000
- pushUnknownContractGroup(unknownContracts, unknownGroupMap, unknownCall);
24001
- continue;
24002
- }
24003
- const decoded = decodeProposalCalldata(contractDecoder, i, targetAddress, callData);
24004
- if (decoded) {
24005
- calls.push(decoded);
24006
- pushDecodedContractGroup(dataByContract, dataGroupMap, decoded);
24007
- } else {
24008
- const unknownCall = {
24009
- index: i,
24010
- target: targetAddress,
24011
- contract: contractDecoder.contract,
24012
- callData
24013
- };
24014
- unknownCalls.push(unknownCall);
24015
- pushUnknownContractGroup(unknownContracts, unknownGroupMap, unknownCall);
24016
- }
24017
- }
24070
+ for (const address of current) if (!next.some((nextAddress) => sameAddress(nextAddress, address))) calls.push(prepareRoleCall(chainId, target, abi, "revokeRole", role, address));
24071
+ for (const address of next) if (!current.some((currentAddress) => sameAddress(currentAddress, address))) calls.push(prepareRoleCall(chainId, target, abi, "grantRole", role, address));
24072
+ return calls;
24073
+ }
24074
+ function prepareRoleCall(chainId, target, abi, functionName, role, address) {
24075
+ const args = [role, address];
24076
+ if (abi === timelockAbi) return prepareContractCall({
24077
+ chainId,
24078
+ address: target,
24079
+ abi: timelockAbi,
24080
+ functionName,
24081
+ args
24082
+ });
24083
+ return prepareContractCall({
24084
+ chainId,
24085
+ address: target,
24086
+ abi: dtfIndexAbi,
24087
+ functionName,
24088
+ args
24089
+ });
24090
+ }
24091
+ //#endregion
24092
+ //#region src/index-dtf/governance/propose/settings-shared.ts
24093
+ const MAX_TOKEN_NAME_LENGTH = 32;
24094
+ const MAX_MINT_FEE = 5;
24095
+ const MAX_TVL_FEE = 10;
24096
+ const MIN_AUCTION_LENGTH_MINUTES = 15;
24097
+ const MAX_AUCTION_LENGTH_MINUTES = 1440;
24098
+ function buildSettingsProposal({ calls, calldatas, description, governance, timelock, targets }) {
24099
+ if (calls.length === 0) throw new SdkError({
24100
+ code: "INVALID_INPUT",
24101
+ message: "proposal must include at least one call"
24102
+ });
24018
24103
  return {
24019
- contracts: getContractAliases(contractMap),
24020
- dataByContract,
24021
- unknownContracts,
24022
- calls,
24023
- unknownCalls
24104
+ governance: getProposalGovernance(governance),
24105
+ timelock: getProposalTimelock(timelock),
24106
+ targets,
24107
+ calldatas,
24108
+ description: description ?? ""
24024
24109
  };
24025
24110
  }
24026
- function decodeProposalCalldata(contractDecoder, index, target, callData) {
24027
- const decoded = tryDecodeCalldata(contractDecoder.abi, callData);
24028
- if (!decoded) return;
24111
+ function buildCallPayload({ calls, governance, timelock }) {
24029
24112
  return {
24030
- index,
24031
- target,
24032
- contract: contractDecoder.contract,
24033
- functionName: decoded.functionName,
24034
- signature: decoded.signature,
24035
- parameters: decoded.parameters,
24036
- params: decoded.params,
24037
- callData
24113
+ ...governance ? { governance } : {},
24114
+ ...timelock ? { timelock } : {},
24115
+ calls,
24116
+ targets: calls.map((call) => call.to),
24117
+ calldatas: calls.map((call) => call.data)
24038
24118
  };
24039
24119
  }
24040
- function tryDecodeCalldata(abi, callData) {
24041
- try {
24042
- const { args, functionName } = decodeFunctionData({
24043
- abi,
24044
- data: callData
24045
- });
24046
- const abiItem = getAbiItem({
24047
- abi,
24048
- args,
24049
- name: functionName
24050
- });
24051
- const parameters = abiItem && "inputs" in abiItem ? abiItem.inputs.map((input) => formatAbiInput(input)) : [];
24052
- const functionNameString = String(functionName);
24053
- return {
24054
- functionName: functionNameString,
24055
- signature: `${functionNameString}(${parameters.join(", ")})`,
24056
- parameters,
24057
- params: [...args ?? []]
24058
- };
24059
- } catch {
24060
- return;
24120
+ async function getDtfIfNeeded(client, params, needed) {
24121
+ return params.dtf ?? (needed ? getDtf(client, params) : void 0);
24122
+ }
24123
+ async function getIndexDtfSettingsVersion(client, params) {
24124
+ const version = params.version ?? await getVersion(client, params);
24125
+ if (version !== "5.0.0" && version !== "6.0.0") throw new SdkError({
24126
+ code: "INVALID_INPUT",
24127
+ message: "Unsupported Index DTF settings proposal version",
24128
+ meta: { version }
24129
+ });
24130
+ return version;
24131
+ }
24132
+ function hasIndexDtfSettingsCall(params) {
24133
+ return (params.removeBasketTokens?.length ?? 0) > 0 || params.tokenName !== void 0 || params.mandate !== void 0 || params.mintFee !== void 0 || params.tvlFee !== void 0 || params.auctionLength !== void 0 || params.weightControl !== void 0 || params.priceControl !== void 0 || params.bidsEnabled !== void 0 || params.revenueDistribution !== void 0;
24134
+ }
24135
+ function getAuthorityGovernance(authority) {
24136
+ return authority?.type === "governance" ? authority.governance : void 0;
24137
+ }
24138
+ function validateDtfSettingsParams(params) {
24139
+ if (params.tokenName !== void 0) assertStringLength(params.tokenName, "tokenName", 1, MAX_TOKEN_NAME_LENGTH);
24140
+ if (params.mintFee !== void 0) assertNumberRange(params.mintFee, "mintFee", 0, MAX_MINT_FEE);
24141
+ if (params.tvlFee !== void 0) assertNumberRange(params.tvlFee, "tvlFee", 0, MAX_TVL_FEE);
24142
+ if (params.auctionLength !== void 0) assertNumberRange(params.auctionLength, "auctionLength", MIN_AUCTION_LENGTH_MINUTES, MAX_AUCTION_LENGTH_MINUTES);
24143
+ if (params.priceControl !== void 0 && !isPriceControl(params.priceControl)) throw new SdkError({
24144
+ code: "INVALID_INPUT",
24145
+ message: "priceControl must be 0, 1, or 2",
24146
+ meta: { priceControl: params.priceControl }
24147
+ });
24148
+ }
24149
+ function getProposalGovernance(governance) {
24150
+ if (!governance) throw new SdkError({
24151
+ code: "INVALID_INPUT",
24152
+ message: "governance is required to build an Index DTF proposal",
24153
+ meta: { governance }
24154
+ });
24155
+ return governance;
24156
+ }
24157
+ function getProposalTimelock(timelock) {
24158
+ if (!timelock) throw new SdkError({
24159
+ code: "INVALID_INPUT",
24160
+ message: "timelock is required to build this Index DTF proposal",
24161
+ meta: { timelock }
24162
+ });
24163
+ return timelock;
24164
+ }
24165
+ function assertStringLength(value, field, minLength, maxLength) {
24166
+ if (value.length < minLength || value.length > maxLength) throw new SdkError({
24167
+ code: "INVALID_INPUT",
24168
+ message: `${field} must be between ${minLength} and ${maxLength} characters`,
24169
+ meta: { [field]: value }
24170
+ });
24171
+ }
24172
+ function isPriceControl(value) {
24173
+ return Number.isInteger(value) && (value === 0 || value === 1 || value === 2);
24174
+ }
24175
+ //#endregion
24176
+ //#region src/index-dtf/governance/propose/settings-basket.ts
24177
+ /** Builds a proposal that changes basket governance settings. */
24178
+ async function buildIndexDtfBasketSettingsProposal(client, params) {
24179
+ return buildSettingsProposal({
24180
+ ...await buildIndexDtfBasketSettingsCalls(client, params),
24181
+ description: params.description
24182
+ });
24183
+ }
24184
+ async function buildIndexDtfBasketSettingsCalls(client, params) {
24185
+ const rebalanceGovernance = getAuthorityGovernance((await getDtfIfNeeded(client, params, params.dtf === void 0 && (params.governance === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0))))?.governance.rebalance.primary);
24186
+ const governance = params.governance ?? rebalanceGovernance?.address;
24187
+ const timelock = params.timelock ?? rebalanceGovernance?.timelock.address;
24188
+ const currentGuardians = params.currentGuardians ?? rebalanceGovernance?.timelock.guardians ?? [];
24189
+ return buildCallPayload({
24190
+ governance,
24191
+ timelock,
24192
+ calls: [...buildGovernanceCalls({
24193
+ chainId: params.chainId,
24194
+ governance,
24195
+ timelock,
24196
+ changes: params.governanceChanges,
24197
+ quorumDenominator: params.quorumDenominator ?? rebalanceGovernance?.quorumDenominator
24198
+ }), ...buildRoleDiffCalls({
24199
+ chainId: params.chainId,
24200
+ target: timelock,
24201
+ role: CANCELLER_ROLE$1,
24202
+ current: currentGuardians,
24203
+ next: params.guardians,
24204
+ abi: timelockAbi
24205
+ })]
24206
+ });
24207
+ }
24208
+ //#endregion
24209
+ //#region src/index-dtf/governance/propose/settings-dao.ts
24210
+ /** Builds a proposal that changes vote-lock DAO settings and rewards. */
24211
+ async function buildIndexDtfDaoSettingsProposal(client, params) {
24212
+ return buildSettingsProposal({
24213
+ ...await buildIndexDtfDaoSettingsCalls(client, params),
24214
+ description: params.description
24215
+ });
24216
+ }
24217
+ async function buildIndexDtfDaoSettingsCalls(client, params) {
24218
+ const hasRewardChanges = (params.addRewardTokens?.length ?? 0) > 0 || (params.removeRewardTokens?.length ?? 0) > 0;
24219
+ const vault = (await getDtfIfNeeded(client, params, params.dtf === void 0 && (params.governance === void 0 || hasRewardChanges && params.stToken === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0))))?.voteLockVault;
24220
+ const governance = params.governance ?? vault?.governance?.address;
24221
+ const timelock = params.timelock ?? vault?.governance?.timelock.address;
24222
+ const stToken = params.stToken ?? vault?.token.address;
24223
+ const currentGuardians = params.currentGuardians ?? vault?.governance?.timelock.guardians ?? [];
24224
+ const calls = [];
24225
+ if (hasRewardChanges && !stToken) throw new SdkError({
24226
+ code: "INVALID_INPUT",
24227
+ message: "stToken is required to build DAO reward token proposals"
24228
+ });
24229
+ if (stToken) {
24230
+ for (const token of params.removeRewardTokens ?? []) calls.push(prepareRewardTokenCall(params.chainId, stToken, "removeRewardToken", token));
24231
+ for (const token of params.addRewardTokens ?? []) calls.push(prepareRewardTokenCall(params.chainId, stToken, "addRewardToken", token));
24061
24232
  }
24233
+ calls.push(...buildGovernanceCalls({
24234
+ chainId: params.chainId,
24235
+ governance,
24236
+ timelock,
24237
+ changes: params.governanceChanges,
24238
+ quorumDenominator: params.quorumDenominator ?? vault?.governance?.quorumDenominator
24239
+ }), ...buildRoleDiffCalls({
24240
+ chainId: params.chainId,
24241
+ target: timelock,
24242
+ role: CANCELLER_ROLE$1,
24243
+ current: currentGuardians,
24244
+ next: params.guardians,
24245
+ abi: timelockAbi
24246
+ }));
24247
+ return buildCallPayload({
24248
+ governance,
24249
+ timelock,
24250
+ calls
24251
+ });
24062
24252
  }
24063
- function decodeFallbackProposalCalldata(index, target, callData) {
24064
- for (const fallbackDecoder of FALLBACK_DECODERS) {
24065
- const decoded = decodeProposalCalldata({
24066
- ...fallbackDecoder,
24067
- target
24068
- }, index, target, callData);
24069
- if (decoded) return decoded;
24070
- }
24253
+ function prepareRewardTokenCall(chainId, target, functionName, token) {
24254
+ return prepareContractCall({
24255
+ chainId,
24256
+ address: target,
24257
+ abi: dtfIndexStakingVaultAbi,
24258
+ functionName,
24259
+ args: [getAddress(token)]
24260
+ });
24071
24261
  }
24072
- function formatAbiInput(input) {
24073
- if (!input.name) return input.type;
24074
- return `${input.name}: ${input.type}`;
24262
+ //#endregion
24263
+ //#region src/index-dtf/governance/propose/settings-dtf.ts
24264
+ /** Builds a proposal that changes core Index DTF settings. */
24265
+ async function buildIndexDtfSettingsProposal(client, params) {
24266
+ return buildSettingsProposal({
24267
+ ...await buildIndexDtfSettingsCalls(client, params),
24268
+ description: params.description
24269
+ });
24075
24270
  }
24076
- function pushDecodedContractGroup(groups, groupMap, call) {
24077
- const key = call.target.toLowerCase();
24078
- let group = groupMap.get(key);
24079
- if (!group) {
24080
- group = {
24081
- target: call.target,
24082
- contract: call.contract,
24083
- calls: []
24084
- };
24085
- groupMap.set(key, group);
24086
- groups.push(group);
24087
- }
24088
- group.calls.push(call);
24271
+ async function buildIndexDtfSettingsCalls(client, params) {
24272
+ validateDtfSettingsParams(params);
24273
+ const needsDtf = params.dtf === void 0 && (params.governance === void 0 || params.governanceChanges?.executionDelay !== void 0 && params.timelock === void 0 || params.guardians !== void 0 && (params.timelock === void 0 || params.currentGuardians === void 0) || params.brandManagers !== void 0 || params.auctionLaunchers !== void 0 || params.revenueDistribution !== void 0 || params.weightControl !== void 0 && params.priceControl === void 0 || params.priceControl !== void 0 && params.weightControl === void 0 || params.governanceChanges?.quorumPercent !== void 0 && params.quorumDenominator === void 0);
24274
+ const hasIndexDtfCall = hasIndexDtfSettingsCall(params);
24275
+ if (hasIndexDtfCall && !needsDtf && params.timelock === void 0 && params.dtf === void 0) throw new SdkError({
24276
+ code: "INVALID_INPUT",
24277
+ message: "timelock is required to build this Index DTF proposal",
24278
+ meta: { timelock: params.timelock }
24279
+ });
24280
+ const dtf = await getDtfIfNeeded(client, params, needsDtf);
24281
+ if (params.revenueDistribution) validateRevenueDistributionInput(dtf, params.revenueDistribution);
24282
+ const version = hasIndexDtfCall ? await getIndexDtfSettingsVersion(client, params) : void 0;
24283
+ const dtfAddress = getAddress(params.address);
24284
+ const adminGovernance = getAuthorityGovernance(dtf?.governance.admin.primary);
24285
+ const governance = params.governance ?? adminGovernance?.address;
24286
+ const timelock = params.timelock ?? adminGovernance?.timelock.address;
24287
+ const currentGuardians = params.currentGuardians ?? adminGovernance?.timelock.guardians ?? [];
24288
+ const calls = [];
24289
+ if (version !== void 0) calls.push(...buildDtfCalls(dtfAddress, params, version, dtf?.rebalance));
24290
+ calls.push(...buildRoleDiffCalls({
24291
+ chainId: params.chainId,
24292
+ target: timelock ?? dtfAddress,
24293
+ role: GUARDIAN_ROLE,
24294
+ current: currentGuardians,
24295
+ next: params.guardians,
24296
+ abi: timelock ? timelockAbi : dtfIndexAbi
24297
+ }), ...buildRoleDiffCalls({
24298
+ chainId: params.chainId,
24299
+ target: dtfAddress,
24300
+ role: BRAND_MANAGER_ROLE,
24301
+ current: dtf?.roles.metadata.brandManagers ?? [],
24302
+ next: params.brandManagers,
24303
+ abi: dtfIndexAbi
24304
+ }), ...buildRoleDiffCalls({
24305
+ chainId: params.chainId,
24306
+ target: dtfAddress,
24307
+ role: AUCTION_LAUNCHER_ROLE,
24308
+ current: dtf?.roles.rebalance.auctionLaunchers ?? [],
24309
+ next: params.auctionLaunchers,
24310
+ abi: dtfIndexAbi
24311
+ }), ...buildGovernanceCalls({
24312
+ chainId: params.chainId,
24313
+ governance,
24314
+ timelock,
24315
+ changes: params.governanceChanges,
24316
+ quorumDenominator: params.quorumDenominator ?? adminGovernance?.quorumDenominator
24317
+ }));
24318
+ const revenueCall = version && params.revenueDistribution ? prepareRevenueDistribution(dtfAddress, params.chainId, dtf, params.revenueDistribution, version) : void 0;
24319
+ if (revenueCall) calls.push(revenueCall);
24320
+ return buildCallPayload({
24321
+ governance,
24322
+ timelock,
24323
+ calls
24324
+ });
24089
24325
  }
24090
- function pushUnknownContractGroup(groups, groupMap, call) {
24091
- const key = call.target.toLowerCase();
24092
- let group = groupMap.get(key);
24093
- if (!group) {
24094
- group = {
24095
- target: call.target,
24096
- contract: call.contract,
24097
- calls: []
24098
- };
24099
- groupMap.set(key, group);
24100
- groups.push(group);
24326
+ function buildDtfCalls(address, params, version, currentRebalanceControl) {
24327
+ const calls = [];
24328
+ for (const token of params.removeBasketTokens ?? []) calls.push(prepareIndexDtfRemoveFromBasket({
24329
+ address,
24330
+ chainId: params.chainId,
24331
+ token,
24332
+ version
24333
+ }));
24334
+ if (params.tokenName !== void 0) calls.push(prepareIndexDtfSetName({
24335
+ address,
24336
+ chainId: params.chainId,
24337
+ name: params.tokenName,
24338
+ version
24339
+ }));
24340
+ if (params.mandate !== void 0) calls.push(prepareIndexDtfSetMandate({
24341
+ address,
24342
+ chainId: params.chainId,
24343
+ mandate: params.mandate,
24344
+ version
24345
+ }));
24346
+ if (params.mintFee !== void 0) calls.push(prepareIndexDtfSetMintFee({
24347
+ address,
24348
+ chainId: params.chainId,
24349
+ percentage: params.mintFee,
24350
+ version
24351
+ }));
24352
+ if (params.tvlFee !== void 0) calls.push(prepareIndexDtfSetTvlFee({
24353
+ address,
24354
+ chainId: params.chainId,
24355
+ percentage: params.tvlFee,
24356
+ version
24357
+ }));
24358
+ if (params.auctionLength !== void 0) calls.push(prepareIndexDtfSetAuctionLength({
24359
+ address,
24360
+ chainId: params.chainId,
24361
+ auctionLength: params.auctionLength * 60,
24362
+ version
24363
+ }));
24364
+ if (params.weightControl !== void 0 || params.priceControl !== void 0) {
24365
+ const weightControl = params.weightControl ?? currentRebalanceControl?.weightControl;
24366
+ const priceControl = params.priceControl ?? currentRebalanceControl?.priceControl;
24367
+ if (weightControl === void 0) throw new SdkError({
24368
+ code: "INVALID_INPUT",
24369
+ message: "weightControl is required to build a priceControl settings proposal",
24370
+ meta: {
24371
+ address,
24372
+ chainId: params.chainId
24373
+ }
24374
+ });
24375
+ if (priceControl === void 0) throw new SdkError({
24376
+ code: "INVALID_INPUT",
24377
+ message: "priceControl is required to build a weightControl settings proposal",
24378
+ meta: {
24379
+ address,
24380
+ chainId: params.chainId
24381
+ }
24382
+ });
24383
+ calls.push(prepareIndexDtfSetRebalanceControl({
24384
+ address,
24385
+ chainId: params.chainId,
24386
+ weightControl,
24387
+ priceControl,
24388
+ version
24389
+ }));
24101
24390
  }
24102
- group.calls.push(call);
24391
+ if (params.bidsEnabled !== void 0) calls.push(prepareIndexDtfSetBidsEnabled({
24392
+ address,
24393
+ chainId: params.chainId,
24394
+ enabled: params.bidsEnabled,
24395
+ version
24396
+ }));
24397
+ return calls;
24103
24398
  }
24104
24399
  //#endregion
24400
+ //#region src/index-dtf/governance/propose/settings-types.ts
24401
+ const addressSchema = z.string().refine(isAddress, "Invalid address");
24402
+ const indexDtfGovernanceChangesSchema = z.object({
24403
+ votingDelay: z.coerce.number().min(0).optional(),
24404
+ votingPeriod: z.coerce.number().min(0).optional(),
24405
+ proposalThreshold: z.coerce.number().min(0).max(100).optional(),
24406
+ quorumPercent: z.coerce.number().min(0).max(100).optional(),
24407
+ executionDelay: z.coerce.number().min(0).optional()
24408
+ });
24409
+ const indexDtfBasketSettingsProposalSchema = z.object({
24410
+ governanceChanges: indexDtfGovernanceChangesSchema.optional(),
24411
+ guardians: z.array(addressSchema).optional()
24412
+ });
24413
+ const indexDtfDaoSettingsProposalSchema = z.object({
24414
+ addRewardTokens: z.array(addressSchema).optional(),
24415
+ removeRewardTokens: z.array(addressSchema).optional(),
24416
+ governanceChanges: indexDtfGovernanceChangesSchema.optional(),
24417
+ guardians: z.array(addressSchema).optional()
24418
+ });
24419
+ const indexDtfSettingsProposalSchema = z.object({
24420
+ tokenName: z.string().min(1).max(32).optional(),
24421
+ mandate: z.string().optional(),
24422
+ mintFee: z.coerce.number().min(0).max(5).optional(),
24423
+ tvlFee: z.coerce.number().min(0).max(10).optional(),
24424
+ auctionLength: z.coerce.number().min(15).max(1440).optional(),
24425
+ weightControl: z.boolean().optional(),
24426
+ priceControl: z.coerce.number().int().min(0).max(2).optional(),
24427
+ bidsEnabled: z.boolean().optional(),
24428
+ removeBasketTokens: z.array(addressSchema).optional(),
24429
+ guardians: z.array(addressSchema).optional(),
24430
+ brandManagers: z.array(addressSchema).optional(),
24431
+ auctionLaunchers: z.array(addressSchema).optional(),
24432
+ governanceChanges: indexDtfGovernanceChangesSchema.optional(),
24433
+ version: z.enum(["5.0.0", "6.0.0"]).optional(),
24434
+ revenueDistribution: z.object({
24435
+ platformFee: z.coerce.number().min(0).lt(100),
24436
+ governanceShare: z.coerce.number().min(0).max(100),
24437
+ deployerShare: z.coerce.number().min(0).max(100),
24438
+ additionalRecipients: z.array(z.object({
24439
+ address: addressSchema,
24440
+ share: z.coerce.number().min(0).max(100)
24441
+ }))
24442
+ }).optional()
24443
+ });
24444
+ //#endregion
24105
24445
  //#region src/index-dtf/governance/mapper.ts
24446
+ const MAX_UINT256 = (1n << 256n) - 1n;
24106
24447
  function mapIndexDtfProposalSummary(proposal, chainId, dtf) {
24107
24448
  const executionETA = toOptionalNumber(proposal.executionETA);
24108
24449
  const executionTime = toOptionalNumber(proposal.executionTime);
24109
24450
  const executionBlock = toOptionalNumber(proposal.executionBlock);
24451
+ const isOptimistic = !!proposal.isOptimistic;
24452
+ const optimistic = mapOptimisticProposalContext(proposal);
24453
+ const vetoThreshold = optimistic?.vetoThreshold ?? mapOptionalBigInt(proposal.vetoThreshold);
24110
24454
  return {
24111
24455
  id: proposal.id,
24112
24456
  chainId,
24113
24457
  governance: getAddress(proposal.governance.id),
24114
24458
  timelock: getAddress(proposal.governance.timelock.id),
24459
+ voteToken: getAddress(proposal.governance.token.id),
24115
24460
  proposer: getAddress(proposal.proposer.address),
24116
24461
  description: proposal.description,
24117
24462
  state: proposal.state,
24118
- ...proposal.isOptimistic === null || proposal.isOptimistic === void 0 ? {} : { isOptimistic: proposal.isOptimistic },
24119
- ...proposal.vetoThreshold ? { vetoThreshold: BigInt(proposal.vetoThreshold) } : {},
24463
+ isOptimistic,
24464
+ ...vetoThreshold === void 0 ? {} : { vetoThreshold },
24465
+ ...optimistic === void 0 ? {} : { optimistic },
24120
24466
  creationTime: Number(proposal.creationTime),
24121
24467
  creationBlock: Number(proposal.creationBlock),
24122
24468
  voteStart: Number(proposal.voteStart),
@@ -24135,7 +24481,9 @@ function mapIndexDtfProposalSummary(proposal, chainId, dtf) {
24135
24481
  };
24136
24482
  }
24137
24483
  function mapIndexDtfProposal(proposal, dtf, chainId) {
24484
+ const txnHash = toHex(proposal.txnHash);
24138
24485
  const queueBlock = toOptionalNumber(proposal.queueBlock);
24486
+ const queueTxnHash = proposal.queueTxnHash ? toHex(proposal.queueTxnHash) : void 0;
24139
24487
  const queueTime = toOptionalNumber(proposal.queueTime);
24140
24488
  const cancellationTime = toOptionalNumber(proposal.cancellationTime);
24141
24489
  const executionTxnHash = proposal.executionTxnHash ? toHex(proposal.executionTxnHash) : void 0;
@@ -24156,13 +24504,66 @@ function mapIndexDtfProposal(proposal, dtf, chainId) {
24156
24504
  forDelegateVotes: Number(proposal.forDelegateVotes),
24157
24505
  againstDelegateVotes: Number(proposal.againstDelegateVotes),
24158
24506
  abstainDelegateVotes: Number(proposal.abstainDelegateVotes),
24507
+ txnHash,
24159
24508
  ...proposal.timelockId ? { timelockId: toHex(proposal.timelockId) } : {},
24160
24509
  ...queueBlock === void 0 ? {} : { queueBlock },
24510
+ ...queueTxnHash === void 0 ? {} : { queueTxnHash },
24161
24511
  ...queueTime === void 0 ? {} : { queueTime },
24162
24512
  ...cancellationTime === void 0 ? {} : { cancellationTime },
24163
24513
  ...executionTxnHash === void 0 ? {} : { executionTxnHash }
24164
24514
  };
24165
24515
  }
24516
+ function mapIndexDtfProposalVotingSnapshot(proposal) {
24517
+ const isOptimistic = !!proposal.isOptimistic;
24518
+ const optimistic = mapOptimisticProposalContext(proposal);
24519
+ const vetoThreshold = optimistic?.vetoThreshold ?? mapOptionalBigInt(proposal.vetoThreshold);
24520
+ return {
24521
+ id: proposal.id,
24522
+ governance: getAddress(proposal.governance.id),
24523
+ voteToken: getAddress(proposal.governance.token.id),
24524
+ state: proposal.state,
24525
+ isOptimistic,
24526
+ ...vetoThreshold === void 0 ? {} : { vetoThreshold },
24527
+ ...optimistic === void 0 ? {} : { optimistic },
24528
+ voteStart: Number(proposal.voteStart),
24529
+ voteEnd: Number(proposal.voteEnd),
24530
+ quorumVotes: mapAmount(proposal.quorumVotes),
24531
+ forWeightedVotes: mapAmount(proposal.forWeightedVotes),
24532
+ againstWeightedVotes: mapAmount(proposal.againstWeightedVotes),
24533
+ abstainWeightedVotes: mapAmount(proposal.abstainWeightedVotes),
24534
+ votes: proposal.votes.map((vote) => ({
24535
+ voter: getAddress(vote.voter.address),
24536
+ choice: vote.choice,
24537
+ weight: mapAmount(vote.weight)
24538
+ }))
24539
+ };
24540
+ }
24541
+ function mapOptimisticProposalContext(proposal) {
24542
+ if (!proposal.isOptimistic) return;
24543
+ const vetoThreshold = mapOptimisticVetoThreshold(proposal.vetoThreshold);
24544
+ const vetoThresholdVotes = mapVetoThreshold(proposal.vetoThresholdVotes);
24545
+ if (proposal.optimisticSnapshot === null || proposal.optimisticSnapshot === void 0 || proposal.optimisticSnapshotSupply === null || proposal.optimisticSnapshotSupply === void 0 || vetoThreshold === void 0 || vetoThresholdVotes === void 0) return;
24546
+ return {
24547
+ proposalId: proposal.id,
24548
+ voteToken: getAddress(proposal.governance.token.id),
24549
+ snapshot: BigInt(proposal.optimisticSnapshot),
24550
+ snapshotSupply: mapAmount(proposal.optimisticSnapshotSupply),
24551
+ vetoThreshold,
24552
+ vetoThresholdVotes: mapAmount(vetoThresholdVotes)
24553
+ };
24554
+ }
24555
+ function mapVetoThreshold(value) {
24556
+ const vetoThreshold = mapOptionalBigInt(value);
24557
+ return vetoThreshold === MAX_UINT256 ? void 0 : vetoThreshold;
24558
+ }
24559
+ function mapOptimisticVetoThreshold(value) {
24560
+ const vetoThreshold = mapVetoThreshold(value);
24561
+ return vetoThreshold === 0n ? void 0 : vetoThreshold;
24562
+ }
24563
+ function mapOptionalBigInt(value) {
24564
+ if (value === null || value === void 0) return;
24565
+ return BigInt(value);
24566
+ }
24166
24567
  function mapDtfProposalContractContext(dtf) {
24167
24568
  const ownerGovernance = dtf.ownerGovernance ? mapGovernanceWithTimelock(dtf.ownerGovernance) : void 0;
24168
24569
  const tradingGovernance = dtf.tradingGovernance ? mapGovernanceWithTimelock(dtf.tradingGovernance) : void 0;
@@ -24208,7 +24609,11 @@ function toHex(value) {
24208
24609
  }
24209
24610
  //#endregion
24210
24611
  //#region src/index-dtf/governance/proposals.ts
24612
+ const CHALLENGE_DESCRIPTION_PREFIX = "Confirmation For:";
24211
24613
  async function getProposals(client, params) {
24614
+ return (await getProposalList(client, params)).proposals;
24615
+ }
24616
+ async function getProposalList(client, params) {
24212
24617
  const limit = params.limit ?? 100;
24213
24618
  if (params.governanceAddresses) {
24214
24619
  const governanceIds = normalizeGovernanceIds(params.governanceAddresses);
@@ -24216,7 +24621,7 @@ async function getProposals(client, params) {
24216
24621
  address: getAddress(params.address),
24217
24622
  chainId: params.chainId
24218
24623
  } : void 0;
24219
- return getProposalsByGovernanceIds(client, params.chainId, governanceIds, limit, params.includeOptimisticState ?? false, dtf);
24624
+ return getProposalListByGovernanceIds(client, params.chainId, governanceIds, limit, dtf);
24220
24625
  }
24221
24626
  if (params.dtf) {
24222
24627
  const dtf = {
@@ -24224,27 +24629,28 @@ async function getProposals(client, params) {
24224
24629
  chainId: params.dtf.chainId
24225
24630
  };
24226
24631
  const governanceIds = normalizeGovernanceIds(getProposalGovernanceAddresses(params.dtf));
24227
- return getProposalsByGovernanceIds(client, dtf.chainId, governanceIds, limit, params.includeOptimisticState ?? false, dtf);
24632
+ return getProposalListByGovernanceIds(client, dtf.chainId, governanceIds, limit, dtf);
24228
24633
  }
24229
24634
  const dtf = {
24230
24635
  address: getAddress(params.address),
24231
24636
  chainId: params.chainId
24232
24637
  };
24233
24638
  const governanceIds = await fetchDtfProposalGovernanceIds(client, dtf);
24234
- return getProposalsByGovernanceIds(client, dtf.chainId, governanceIds, limit, params.includeOptimisticState ?? false, dtf);
24639
+ return getProposalListByGovernanceIds(client, dtf.chainId, governanceIds, limit, dtf);
24235
24640
  }
24236
24641
  async function getAllProposals(client, params) {
24642
+ const limit = params.limit ?? 100;
24237
24643
  const where = getProposalFilter(params.states);
24238
24644
  const { proposals } = await client.subgraph.queryIndex({
24239
24645
  chainId: params.chainId,
24240
24646
  query: GetAllIndexDtfProposalsDocument,
24241
24647
  variables: {
24242
- limit: params.limit ?? 100,
24648
+ limit,
24243
24649
  offset: params.offset ?? 0,
24244
24650
  ...where ? { where } : {}
24245
24651
  }
24246
24652
  });
24247
- return finalizeProposalSummaries(client, proposals.map((proposal) => mapIndexDtfProposalSummary(proposal, params.chainId)), params.includeOptimisticState ?? false);
24653
+ return withProposalSummaryState(proposals.map((proposal) => mapIndexDtfProposalSummary(proposal, params.chainId)));
24248
24654
  }
24249
24655
  async function getProposal(client, params) {
24250
24656
  const { proposalId, address, chainId } = params;
@@ -24266,25 +24672,94 @@ async function getProposal(client, params) {
24266
24672
  }
24267
24673
  });
24268
24674
  const governedDtf = dtf;
24269
- const parsedProposal = await withOptionalOptimisticProposalContext(client, mapIndexDtfProposal(proposal, governedDtf, chainId));
24270
- const proposalWithVoteState = withVoteState(parsedProposal, getCurrentTime());
24271
- const contractMap = buildProposalContractMap({
24272
- chainId,
24273
- dtf: mapDtfProposalContractContext(governedDtf),
24274
- proposalGovernance: mapProposalGovernanceContractContext(proposal.governance)
24275
- });
24675
+ const timestamp = getCurrentTime();
24676
+ const parsedProposal = mapIndexDtfProposal(proposal, governedDtf, chainId);
24677
+ const proposalWithOptimisticContext = await withOptimisticContext(client, parsedProposal, timestamp);
24678
+ const challengedProposalId = await getChallengedProposalId(client, proposalWithOptimisticContext);
24679
+ const proposalWithVoteState = withVoteState(challengedProposalId ? {
24680
+ ...proposalWithOptimisticContext,
24681
+ wasChallenged: true,
24682
+ challengedProposalId
24683
+ } : proposalWithOptimisticContext, timestamp);
24276
24684
  const decodedData = decodeIndexDtfProposalCalldatas({
24277
24685
  targets: parsedProposal.targets,
24278
24686
  calldatas: parsedProposal.calldatas,
24279
- contractMap
24687
+ contractMap: buildProposalContractMap({
24688
+ chainId,
24689
+ dtf: mapDtfProposalContractContext(governedDtf),
24690
+ proposalGovernance: mapProposalGovernanceContractContext(proposal.governance)
24691
+ })
24280
24692
  });
24281
24693
  return {
24282
24694
  ...proposalWithVoteState,
24283
24695
  decoded: decodedData
24284
24696
  };
24285
24697
  }
24286
- async function getProposalsByGovernanceIds(client, chainId, governanceIds, limit, includeOptimisticState, dtf) {
24287
- if (governanceIds.length === 0) return [];
24698
+ async function getChallengedProposalId(client, proposal) {
24699
+ if (proposal.isOptimistic) return;
24700
+ const challengeDescription = getChallengeDescription(proposal.description);
24701
+ if (!challengeDescription) return;
24702
+ try {
24703
+ const { proposals } = await client.subgraph.queryIndex({
24704
+ chainId: proposal.chainId,
24705
+ query: GetIndexDtfProposalChallengeDocument,
24706
+ variables: {
24707
+ governanceId: proposal.governance.toLowerCase(),
24708
+ description: challengeDescription,
24709
+ creationBlock: proposal.creationBlock.toString()
24710
+ }
24711
+ });
24712
+ return proposals[0]?.id;
24713
+ } catch {
24714
+ return;
24715
+ }
24716
+ }
24717
+ async function withOptimisticContext(client, proposal, timestamp) {
24718
+ const hasVotes = proposal.votes.length > 0;
24719
+ if (!proposal.isOptimistic || proposal.vetoThreshold === void 0 || timestamp <= proposal.voteStart || timestamp >= proposal.voteEnd || hasVotes) return proposal;
24720
+ try {
24721
+ const optimistic = await getOptimisticProposalContext(client, {
24722
+ chainId: proposal.chainId,
24723
+ governance: proposal.governance,
24724
+ proposalId: proposal.id,
24725
+ isOptimistic: true,
24726
+ voteToken: proposal.voteToken,
24727
+ snapshot: BigInt(proposal.voteStart),
24728
+ vetoThreshold: proposal.vetoThreshold
24729
+ });
24730
+ if (!optimistic) return proposal;
24731
+ return {
24732
+ ...proposal,
24733
+ vetoThreshold: optimistic.vetoThreshold,
24734
+ optimistic
24735
+ };
24736
+ } catch {
24737
+ return proposal;
24738
+ }
24739
+ }
24740
+ async function getProposalVotingSnapshot(client, params) {
24741
+ const { proposal } = await client.subgraph.queryIndex({
24742
+ chainId: params.chainId,
24743
+ query: GetIndexDtfProposalVotingSnapshotDocument,
24744
+ variables: { proposalId: params.proposalId }
24745
+ });
24746
+ if (!proposal) throw new SdkError({
24747
+ code: "RECORD_NOT_FOUND",
24748
+ message: `Index DTF proposal not found: ${params.proposalId} on chain ${params.chainId}`,
24749
+ meta: {
24750
+ chainId: params.chainId,
24751
+ entity: "indexDtfProposal",
24752
+ id: params.proposalId
24753
+ }
24754
+ });
24755
+ const timestamp = getCurrentTime();
24756
+ return withVoteState(mapIndexDtfProposalVotingSnapshot(proposal), timestamp);
24757
+ }
24758
+ async function getProposalListByGovernanceIds(client, chainId, governanceIds, limit, dtf) {
24759
+ if (governanceIds.length === 0) return {
24760
+ proposals: [],
24761
+ proposalCount: 0
24762
+ };
24288
24763
  const { governances } = await client.subgraph.queryIndex({
24289
24764
  chainId,
24290
24765
  query: GetIndexDtfProposalsDocument,
@@ -24293,29 +24768,53 @@ async function getProposalsByGovernanceIds(client, chainId, governanceIds, limit
24293
24768
  limit
24294
24769
  }
24295
24770
  });
24296
- const timestamp = getCurrentTime();
24297
- return finalizeProposalSummaries(client, governances.flatMap((governance) => governance.proposals).map((proposal) => mapIndexDtfProposalSummary(proposal, chainId, dtf)).sort((a, b) => b.creationTime - a.creationTime).slice(0, limit), includeOptimisticState, timestamp);
24298
- }
24299
- async function finalizeProposalSummaries(client, proposals, includeOptimisticState, timestamp = getCurrentTime()) {
24300
- if (!includeOptimisticState) return proposals.map((proposal) => withVoteState(proposal, timestamp));
24301
- return (await Promise.all(proposals.map((proposal) => withOptionalOptimisticProposalContext(client, proposal)))).map((proposal) => withVoteState(proposal, timestamp));
24302
- }
24303
- async function withOptionalOptimisticProposalContext(client, proposal) {
24304
- if (proposal.isOptimistic === false) return proposal;
24305
- const optimistic = await getOptimisticProposalContext(client, {
24306
- chainId: proposal.chainId,
24307
- governance: proposal.governance,
24308
- proposalId: proposal.id,
24309
- ...proposal.isOptimistic === void 0 ? {} : { isOptimistic: proposal.isOptimistic }
24310
- });
24311
- if (!optimistic) return proposal;
24771
+ const proposalCount = getProposalCount(governances);
24312
24772
  return {
24313
- ...proposal,
24314
- isOptimistic: true,
24315
- voteToken: optimistic.voteToken,
24316
- optimistic
24773
+ proposals: withProposalSummaryState(governances.flatMap((governance) => governance.proposals).map((proposal) => mapIndexDtfProposalSummary(proposal, chainId, dtf)).sort((a, b) => b.creationTime - a.creationTime).slice(0, limit)),
24774
+ proposalCount
24317
24775
  };
24318
24776
  }
24777
+ function getProposalCount(governances) {
24778
+ return governances.reduce((count, governance) => count + Number(governance.proposalCount), 0);
24779
+ }
24780
+ function withProposalSummaryState(proposals, timestamp = getCurrentTime()) {
24781
+ return withChallengeState(proposals.map((proposal) => withVoteState(proposal, timestamp)));
24782
+ }
24783
+ function withChallengeState(proposals) {
24784
+ const optimisticProposals = proposals.filter((proposal) => proposal.isOptimistic === true);
24785
+ const challengeMatches = /* @__PURE__ */ new Map();
24786
+ for (const proposal of proposals) {
24787
+ if (proposal.isOptimistic === true) continue;
24788
+ const confirmationDescription = getChallengeDescription(proposal.description);
24789
+ if (!confirmationDescription) continue;
24790
+ let challengedProposalId;
24791
+ let challengedProposal;
24792
+ for (const optimisticProposal of optimisticProposals) {
24793
+ if (optimisticProposal.creationBlock > proposal.creationBlock) continue;
24794
+ if (optimisticProposal.governance.toLowerCase() !== proposal.governance.toLowerCase()) continue;
24795
+ if (confirmationDescription === optimisticProposal.description) {
24796
+ if (!challengedProposal || optimisticProposal.creationBlock > challengedProposal.creationBlock) {
24797
+ challengedProposal = optimisticProposal;
24798
+ challengedProposalId = optimisticProposal.id;
24799
+ }
24800
+ }
24801
+ }
24802
+ if (challengedProposalId) challengeMatches.set(proposal.id, challengedProposalId);
24803
+ }
24804
+ return proposals.map((proposal) => {
24805
+ if (!challengeMatches.has(proposal.id)) return proposal;
24806
+ return {
24807
+ ...proposal,
24808
+ wasChallenged: true,
24809
+ challengedProposalId: challengeMatches.get(proposal.id)
24810
+ };
24811
+ });
24812
+ }
24813
+ function getChallengeDescription(description) {
24814
+ if (!description.startsWith(CHALLENGE_DESCRIPTION_PREFIX)) return;
24815
+ const challengeDescription = description.slice(17).trim();
24816
+ return challengeDescription.length > 0 ? challengeDescription : void 0;
24817
+ }
24319
24818
  function getProposalFilter(states) {
24320
24819
  if (!states || states.length === 0) return;
24321
24820
  return { state_in: [...states] };
@@ -24366,6 +24865,22 @@ async function getSelectorRegistryIsAllowed(client, params) {
24366
24865
  args: [getAddress(params.target), normalizeSelector(params.selector)]
24367
24866
  });
24368
24867
  }
24868
+ async function getOptimisticSelectors(client, params) {
24869
+ const targets = await getSelectorRegistryTargets(client, params);
24870
+ const optimisticSelectors = [];
24871
+ for (const target of targets) {
24872
+ const normalizedTarget = getAddress(target);
24873
+ const selectors = await getSelectorRegistryAllowedSelectors(client, {
24874
+ ...params,
24875
+ target: normalizedTarget
24876
+ });
24877
+ for (const selector of selectors) optimisticSelectors.push({
24878
+ target: normalizedTarget,
24879
+ selector: normalizeSelector(selector)
24880
+ });
24881
+ }
24882
+ return optimisticSelectors;
24883
+ }
24369
24884
  function prepareSelectorRegistryRegisterSelectors(params) {
24370
24885
  return prepareContractCall({
24371
24886
  chainId: params.chainId,
@@ -24407,8 +24922,7 @@ async function getVoterState(client, params) {
24407
24922
  address: stToken,
24408
24923
  abi: dtfIndexStakingVaultAbi
24409
24924
  };
24410
- const publicClient = client.viem.getPublicClient(params.chainId);
24411
- const [delegate, balance, votingPower, voteSupply] = await publicClient.multicall({
24925
+ const [delegate, balance, votingPower, voteSupply] = await client.viem.getPublicClient(params.chainId).multicall({
24412
24926
  allowFailure: false,
24413
24927
  contracts: [
24414
24928
  {
@@ -24432,22 +24946,7 @@ async function getVoterState(client, params) {
24432
24946
  }
24433
24947
  ]
24434
24948
  });
24435
- const [optimisticDelegateResult, optimisticVotingPowerResult] = await publicClient.multicall({
24436
- allowFailure: true,
24437
- contracts: [{
24438
- address: stToken,
24439
- abi: dtfIndexStakingVaultOptimisticAbi,
24440
- functionName: "optimisticDelegates",
24441
- args: [account]
24442
- }, {
24443
- address: stToken,
24444
- abi: dtfIndexStakingVaultOptimisticAbi,
24445
- functionName: "getOptimisticVotes",
24446
- args: [account]
24447
- }]
24448
- });
24449
- const optimisticDelegate = getOptionalOptimisticResult(optimisticDelegateResult);
24450
- const optimisticVotingPower = getOptionalOptimisticResult(optimisticVotingPowerResult);
24949
+ const [optimisticDelegate, optimisticVotingPower] = await readOptionalCurrentOptimisticVoterState(client, params.chainId, stToken, account);
24451
24950
  const mappedOptimisticVotingPower = optimisticVotingPower === null ? null : mapAmount(optimisticVotingPower);
24452
24951
  return {
24453
24952
  account,
@@ -24455,6 +24954,7 @@ async function getVoterState(client, params) {
24455
24954
  optimisticDelegate,
24456
24955
  balance: mapAmount(balance),
24457
24956
  votingPower: mapAmount(votingPower),
24957
+ votingWeight: voteSupply === 0n ? 0 : Number(votingPower) / Number(voteSupply) * 100,
24458
24958
  optimisticVotingPower: mappedOptimisticVotingPower,
24459
24959
  voteSupply: mapAmount(voteSupply),
24460
24960
  isSelfDelegated: delegate.toLowerCase() === account.toLowerCase(),
@@ -24466,22 +24966,51 @@ async function getVoterState(client, params) {
24466
24966
  async function getProposerState(client, params) {
24467
24967
  const governance = getAddress(params.governance);
24468
24968
  const account = getAddress(params.account);
24469
- const timepoint = params.timepoint ?? await getLatestBlockTimepoint(client.viem, params.chainId);
24969
+ const publicClient = client.viem.getPublicClient(params.chainId);
24470
24970
  const baseCall = {
24471
24971
  address: governance,
24472
24972
  abi: dtfIndexGovernanceAbi
24473
24973
  };
24474
- const [votingPower, proposalThreshold] = await client.viem.getPublicClient(params.chainId).multicall({
24974
+ if (params.timepoint !== void 0) {
24975
+ const [votingPower, proposalThreshold] = await publicClient.multicall({
24976
+ allowFailure: false,
24977
+ contracts: [{
24978
+ ...baseCall,
24979
+ functionName: "getVotes",
24980
+ args: [account, params.timepoint]
24981
+ }, {
24982
+ ...baseCall,
24983
+ functionName: "proposalThreshold"
24984
+ }]
24985
+ });
24986
+ return {
24987
+ account,
24988
+ governance,
24989
+ votingPower: mapAmount(votingPower),
24990
+ proposalThreshold: mapAmount(proposalThreshold),
24991
+ canPropose: votingPower >= proposalThreshold
24992
+ };
24993
+ }
24994
+ const [clock, proposalThreshold] = await publicClient.multicall({
24475
24995
  allowFailure: false,
24476
24996
  contracts: [{
24477
24997
  ...baseCall,
24478
- functionName: "getVotes",
24479
- args: [account, timepoint]
24998
+ functionName: "clock"
24480
24999
  }, {
24481
25000
  ...baseCall,
24482
25001
  functionName: "proposalThreshold"
24483
25002
  }]
24484
25003
  });
25004
+ const clockTimepoint = typeof clock === "bigint" ? clock : BigInt(clock);
25005
+ const timepoint = clockTimepoint > 0n ? clockTimepoint - 1n : 0n;
25006
+ const [votingPower] = await publicClient.multicall({
25007
+ allowFailure: false,
25008
+ contracts: [{
25009
+ ...baseCall,
25010
+ functionName: "getVotes",
25011
+ args: [account, timepoint]
25012
+ }]
25013
+ });
24485
25014
  return {
24486
25015
  account,
24487
25016
  governance,
@@ -24491,12 +25020,14 @@ async function getProposerState(client, params) {
24491
25020
  };
24492
25021
  }
24493
25022
  async function getProposalVotes(client, params) {
24494
- const [againstVotes, forVotes, abstainVotes] = await client.viem.readContract({
24495
- chainId: params.chainId,
24496
- address: getAddress(params.governance),
24497
- abi: dtfIndexGovernanceAbi,
24498
- functionName: "proposalVotes",
24499
- args: [BigInt(params.proposalId)]
25023
+ const [[againstVotes, forVotes, abstainVotes]] = await client.viem.getPublicClient(params.chainId).multicall({
25024
+ allowFailure: false,
25025
+ contracts: [{
25026
+ address: getAddress(params.governance),
25027
+ abi: dtfIndexGovernanceAbi,
25028
+ functionName: "proposalVotes",
25029
+ args: [BigInt(params.proposalId)]
25030
+ }]
24500
25031
  });
24501
25032
  return {
24502
25033
  againstVotes: mapAmount(againstVotes),
@@ -24505,19 +25036,14 @@ async function getProposalVotes(client, params) {
24505
25036
  };
24506
25037
  }
24507
25038
  async function getProposalVoterState(client, params) {
25039
+ if (params.proposal.isOptimistic === true) return getUnifiedOptimisticProposalVoterState(client, params);
25040
+ return getStandardProposalVoterState(client, params);
25041
+ }
25042
+ async function getStandardProposalVoterState(client, params) {
24508
25043
  const account = getAddress(params.account);
24509
- const latestTimepoint = await getLatestBlockTimepoint(client.viem, params.chainId);
24510
25044
  const governance = getAddress(params.governance);
24511
- const standardTimepoint = BigInt(Math.max(params.proposal.voteStart - 1, 0));
24512
- const timepoint = latestTimepoint < standardTimepoint ? latestTimepoint : standardTimepoint;
24513
- const votingPower = await client.viem.readContract({
24514
- chainId: params.chainId,
24515
- address: governance,
24516
- abi: dtfIndexGovernanceAbi,
24517
- functionName: "getVotes",
24518
- args: [account, timepoint]
24519
- });
24520
25045
  const vote = getAccountProposalVote(params.proposal.votes, account);
25046
+ const votingPower = await readStandardProposalVotingPower(client, params.chainId, governance, account, params.proposal.voteStart);
24521
25047
  return {
24522
25048
  account,
24523
25049
  votingPower: mapAmount(votingPower),
@@ -24526,11 +25052,22 @@ async function getProposalVoterState(client, params) {
24526
25052
  hasVotingPower: votingPower > 0n
24527
25053
  };
24528
25054
  }
25055
+ async function getUnifiedOptimisticProposalVoterState(client, params) {
25056
+ const account = getAddress(params.account);
25057
+ const optimisticVotingPower = await readProposalOptimisticVotingPower(client, params.chainId, account, params.proposal);
25058
+ const vote = getAccountProposalVote(params.proposal.votes, account);
25059
+ const votingPower = mapAmount(optimisticVotingPower ?? 0n);
25060
+ return {
25061
+ account,
25062
+ votingPower,
25063
+ vote,
25064
+ hasVoted: vote !== null,
25065
+ hasVotingPower: votingPower.raw > 0n
25066
+ };
25067
+ }
24529
25068
  async function getOptimisticProposalVoterState(client, params) {
24530
25069
  const account = getAddress(params.account);
24531
- const latestTimepoint = await getLatestBlockTimepoint(client.viem, params.chainId);
24532
- const governance = getAddress(params.governance);
24533
- const optimisticVotingPower = await readPastOptimisticVotes(client, params.chainId, await getProposalVoteToken(client, params.chainId, governance, params.proposal.voteToken), account, getOptimisticProposalTimepoint(latestTimepoint, params.proposal));
25070
+ const optimisticVotingPower = await readProposalOptimisticVotingPower(client, params.chainId, account, params.proposal);
24534
25071
  const vote = getAccountProposalVote(params.proposal.votes, account);
24535
25072
  return {
24536
25073
  account,
@@ -24540,41 +25077,92 @@ async function getOptimisticProposalVoterState(client, params) {
24540
25077
  hasOptimisticVotingPower: (optimisticVotingPower ?? 0n) > 0n
24541
25078
  };
24542
25079
  }
24543
- function getOptimisticProposalTimepoint(latestTimepoint, proposal) {
24544
- const optimisticTimepoint = proposal.optimistic?.snapshot ?? BigInt(proposal.voteStart);
24545
- return latestTimepoint < optimisticTimepoint ? latestTimepoint : optimisticTimepoint;
24546
- }
24547
25080
  function getOptionalOptimisticResult(result) {
24548
25081
  if (result.status === "success") return result.result;
24549
25082
  if (isUnsupportedVoteLockOptimisticReadError(result.error)) return null;
24550
25083
  throw result.error;
24551
25084
  }
25085
+ async function readOptionalCurrentOptimisticVoterState(client, chainId, stToken, account) {
25086
+ try {
25087
+ const [delegateResult, votingPowerResult] = await client.viem.getPublicClient(chainId).multicall({
25088
+ allowFailure: true,
25089
+ contracts: [{
25090
+ address: stToken,
25091
+ abi: dtfIndexStakingVaultOptimisticAbi,
25092
+ functionName: "optimisticDelegates",
25093
+ args: [account]
25094
+ }, {
25095
+ address: stToken,
25096
+ abi: dtfIndexStakingVaultOptimisticAbi,
25097
+ functionName: "getOptimisticVotes",
25098
+ args: [account]
25099
+ }]
25100
+ });
25101
+ return [getOptionalOptimisticResult(delegateResult), getOptionalOptimisticResult(votingPowerResult)];
25102
+ } catch (error) {
25103
+ if (isUnsupportedVoteLockOptimisticReadError(error)) return [null, null];
25104
+ throw error;
25105
+ }
25106
+ }
24552
25107
  function getAccountProposalVote(votes, account) {
24553
25108
  const normalizedAccount = account.toLowerCase();
24554
25109
  return votes.find((proposalVote) => proposalVote.voter.toLowerCase() === normalizedAccount)?.choice ?? null;
24555
25110
  }
24556
- async function getProposalVoteToken(client, chainId, governance, voteToken) {
24557
- if (voteToken) return getAddress(voteToken);
24558
- return client.viem.readContract({
24559
- chainId,
24560
- address: governance,
24561
- abi: dtfIndexGovernanceOptimisticAbi,
24562
- functionName: "token"
25111
+ async function readProposalOptimisticVotingPower(client, chainId, account, proposal) {
25112
+ const voteToken = getAddress(proposal.optimistic?.voteToken ?? proposal.voteToken);
25113
+ return readPastOptimisticVotes(client, chainId, voteToken, account, await getPastVoteTimepoint(client, chainId, voteToken, proposal.optimistic?.snapshot ?? BigInt(proposal.voteStart)));
25114
+ }
25115
+ async function readStandardProposalVotingPower(client, chainId, governance, account, voteStart) {
25116
+ const snapshotTimepoint = BigInt(Math.max(voteStart - 1, 0));
25117
+ const publicClient = client.viem.getPublicClient(chainId);
25118
+ const [clock] = await publicClient.multicall({
25119
+ allowFailure: false,
25120
+ contracts: [{
25121
+ address: governance,
25122
+ abi: dtfIndexGovernanceAbi,
25123
+ functionName: "clock"
25124
+ }]
24563
25125
  });
25126
+ const clockTimepoint = typeof clock === "bigint" ? clock : BigInt(clock);
25127
+ const latestSafeTimepoint = clockTimepoint > 0n ? clockTimepoint - 1n : 0n;
25128
+ const timepoint = snapshotTimepoint > latestSafeTimepoint ? latestSafeTimepoint : snapshotTimepoint;
25129
+ const [votingPower] = await publicClient.multicall({
25130
+ allowFailure: false,
25131
+ contracts: [{
25132
+ address: governance,
25133
+ abi: dtfIndexGovernanceAbi,
25134
+ functionName: "getVotes",
25135
+ args: [account, timepoint]
25136
+ }]
25137
+ });
25138
+ return votingPower;
25139
+ }
25140
+ async function getPastVoteTimepoint(client, chainId, voteToken, snapshotTimepoint) {
25141
+ const [clock] = await client.viem.getPublicClient(chainId).multicall({
25142
+ allowFailure: false,
25143
+ contracts: [{
25144
+ address: voteToken,
25145
+ abi: dtfIndexStakingVaultAbi,
25146
+ functionName: "clock"
25147
+ }]
25148
+ });
25149
+ const clockTimepoint = typeof clock === "bigint" ? clock : BigInt(clock);
25150
+ const latestSafeTimepoint = clockTimepoint > 0n ? clockTimepoint - 1n : 0n;
25151
+ return snapshotTimepoint > latestSafeTimepoint ? latestSafeTimepoint : snapshotTimepoint;
24564
25152
  }
24565
25153
  async function readPastOptimisticVotes(client, chainId, voteToken, account, timepoint) {
24566
- try {
24567
- return await client.viem.readContract({
24568
- chainId,
25154
+ const [votingPowerResult] = await client.viem.getPublicClient(chainId).multicall({
25155
+ allowFailure: true,
25156
+ contracts: [{
24569
25157
  address: voteToken,
24570
25158
  abi: dtfIndexStakingVaultOptimisticAbi,
24571
25159
  functionName: "getPastOptimisticVotes",
24572
25160
  args: [account, timepoint]
24573
- }) ?? null;
24574
- } catch (error) {
24575
- if (!isUnsupportedVoteLockOptimisticReadError(error)) throw error;
24576
- return null;
24577
- }
25161
+ }]
25162
+ });
25163
+ if (votingPowerResult.status === "success") return votingPowerResult.result ?? null;
25164
+ if (isUnsupportedVoteLockOptimisticReadError(votingPowerResult.error)) return null;
25165
+ throw votingPowerResult.error;
24578
25166
  }
24579
25167
  //#endregion
24580
25168
  //#region src/index-dtf/governance/namespace.ts
@@ -24582,7 +25170,10 @@ async function readPastOptimisticVotes(client, chainId, voteToken, account, time
24582
25170
  function createIndexDtfGovernanceNamespace(client) {
24583
25171
  return {
24584
25172
  getProposals: (params) => getProposals(client, params),
25173
+ getProposalList: (params) => getProposalList(client, params),
24585
25174
  getProposal: (params) => getProposal(client, params),
25175
+ decodeProposalCalldatas: (params) => decodeIndexDtfProposal(client, params),
25176
+ getProposalVotingSnapshot: (params) => getProposalVotingSnapshot(client, params),
24586
25177
  getAllProposals: (params) => getAllProposals(client, params),
24587
25178
  getDelegates: (params) => getDelegates(client, params),
24588
25179
  getGuardians: (params) => getGuardians(client, params),
@@ -24591,6 +25182,7 @@ function createIndexDtfGovernanceNamespace(client) {
24591
25182
  getOptimisticGovernance: (params) => getOptimisticGovernance(client, params),
24592
25183
  getOptimisticProposalContext: (params) => getOptimisticProposalContext(client, params),
24593
25184
  getOptimisticTimelockRoles: (params) => getOptimisticTimelockRoles(client, params),
25185
+ getOptimisticSelectors: (params) => getOptimisticSelectors(client, params),
24594
25186
  getOptimisticVotes: (params) => getOptimisticVotes(client, params),
24595
25187
  getPastOptimisticVotes: (params) => getPastOptimisticVotes(client, params),
24596
25188
  getProposalThrottleCharges: (params) => getProposalThrottleCharges(client, params),
@@ -25112,11 +25704,20 @@ function createIndexDtfGovernanceRef(client, params) {
25112
25704
  address,
25113
25705
  chainId
25114
25706
  }),
25707
+ getProposalList: (options = {}) => getProposalList(client, {
25708
+ ...options,
25709
+ address,
25710
+ chainId
25711
+ }),
25115
25712
  getProposal: (proposalId) => getProposal(client, {
25116
25713
  proposalId,
25117
25714
  address,
25118
25715
  chainId
25119
25716
  }),
25717
+ getProposalVotingSnapshot: (proposalId) => getProposalVotingSnapshot(client, {
25718
+ chainId,
25719
+ proposalId
25720
+ }),
25120
25721
  getDelegates: (options) => getDelegates(client, {
25121
25722
  ...options,
25122
25723
  chainId
@@ -25803,7 +26404,7 @@ async function getVoteLockState(client, params) {
25803
26404
  chainId: params.chainId,
25804
26405
  addresses: [underlying.address]
25805
26406
  });
25806
- const [balanceResult, allowanceResult, delegateResult, maxWithdrawResult, unstakingDelayResult, unstakingManagerResult, optimisticDelegateResult, optimisticVotingPowerResult] = await client.viem.getPublicClient(params.chainId).multicall({
26407
+ const [balanceResult, allowanceResult, delegateResult, maxWithdrawResult, unstakingDelayResult, unstakingManagerResult] = await client.viem.getPublicClient(params.chainId).multicall({
25807
26408
  allowFailure: true,
25808
26409
  contracts: [
25809
26410
  {
@@ -25839,31 +26440,16 @@ async function getVoteLockState(client, params) {
25839
26440
  address: stToken,
25840
26441
  abi: dtfIndexStakingVaultAbi,
25841
26442
  functionName: "unstakingManager"
25842
- },
25843
- {
25844
- address: stToken,
25845
- abi: dtfIndexStakingVaultOptimisticAbi,
25846
- functionName: "optimisticDelegates",
25847
- args: [account]
25848
- },
25849
- {
25850
- address: stToken,
25851
- abi: dtfIndexStakingVaultOptimisticAbi,
25852
- functionName: "getOptimisticVotes",
25853
- args: [account]
25854
26443
  }
25855
26444
  ]
25856
26445
  });
26446
+ const [optimisticDelegate, optimisticVotingPower] = await readOptionalOptimisticVoteLockState(client, params.chainId, stToken, account);
25857
26447
  if (balanceResult.status === "failure") throw balanceResult.error;
25858
26448
  if (allowanceResult.status === "failure") throw allowanceResult.error;
25859
26449
  if (delegateResult.status === "failure") throw delegateResult.error;
25860
26450
  if (maxWithdrawResult.status === "failure") throw maxWithdrawResult.error;
25861
26451
  if (unstakingDelayResult.status === "failure") throw unstakingDelayResult.error;
25862
26452
  if (unstakingManagerResult.status === "failure") throw unstakingManagerResult.error;
25863
- if (optimisticDelegateResult.status === "failure" && !isUnsupportedVoteLockOptimisticReadError(optimisticDelegateResult.error)) throw optimisticDelegateResult.error;
25864
- if (optimisticVotingPowerResult.status === "failure" && !isUnsupportedVoteLockOptimisticReadError(optimisticVotingPowerResult.error)) throw optimisticVotingPowerResult.error;
25865
- const optimisticDelegate = optimisticDelegateResult.status === "success" ? optimisticDelegateResult.result : null;
25866
- const optimisticVotingPower = optimisticVotingPowerResult.status === "success" ? optimisticVotingPowerResult.result : null;
25867
26453
  return {
25868
26454
  stToken,
25869
26455
  underlying,
@@ -25880,6 +26466,33 @@ async function getVoteLockState(client, params) {
25880
26466
  ...prices[0] ? { underlyingPrice: prices[0].price } : {}
25881
26467
  };
25882
26468
  }
26469
+ async function readOptionalOptimisticVoteLockState(client, chainId, stToken, account) {
26470
+ try {
26471
+ const [delegateResult, votingPowerResult] = await client.viem.getPublicClient(chainId).multicall({
26472
+ allowFailure: true,
26473
+ contracts: [{
26474
+ address: stToken,
26475
+ abi: dtfIndexStakingVaultOptimisticAbi,
26476
+ functionName: "optimisticDelegates",
26477
+ args: [account]
26478
+ }, {
26479
+ address: stToken,
26480
+ abi: dtfIndexStakingVaultOptimisticAbi,
26481
+ functionName: "getOptimisticVotes",
26482
+ args: [account]
26483
+ }]
26484
+ });
26485
+ return [readOptionalOptimisticVoteLockResult(delegateResult), readOptionalOptimisticVoteLockResult(votingPowerResult)];
26486
+ } catch (error) {
26487
+ if (isUnsupportedVoteLockOptimisticReadError(error)) return [null, null];
26488
+ throw error;
26489
+ }
26490
+ }
26491
+ function readOptionalOptimisticVoteLockResult(result) {
26492
+ if (result.status === "success") return result.result;
26493
+ if (isUnsupportedVoteLockOptimisticReadError(result.error)) return null;
26494
+ throw result.error;
26495
+ }
25883
26496
  function mapVoteLockDao(dao) {
25884
26497
  return {
25885
26498
  ...dao,
@@ -26522,4 +27135,4 @@ async function getDiscoverDtfs(client, { chainId, limit, offset, sort } = {}) {
26522
27135
  }));
26523
27136
  }
26524
27137
  //#endregion
26525
- export { CANCELLER_ROLE, DEFAULT_API_BASE_URL, DEFAULT_INDEX_DTF_DEPLOY_FLAGS, DEFAULT_RPC_URLS, INDEX_DTF_DEPLOYER_ADDRESS, INDEX_DTF_GOVERNANCE_DEPLOYER_ADDRESS, INDEX_DTF_SUBGRAPH_URL, OPTIMISTIC_PROPOSER_ROLE, SUPPORTED_CHAINS, SdkError, YIELD_DTF_SUBGRAPH_URL, buildIndexDtfBasketProposal, buildIndexDtfBasketSettingsProposal, buildIndexDtfDaoSettingsProposal, buildIndexDtfDeployFeeRecipients, buildInitialBasket as buildIndexDtfInitialBasket, buildIndexDtfSettingsProposal, buildIndexDtfStartRebalance, buildStartRebalanceArgs as buildIndexDtfStartRebalanceArgs, createDtfClient, createDtfSdk, createIndexDtfNamespace, createIndexDtfRef, createPortfolioNamespace, createWalletClient, discoverIndexDtfs, discoverIndexDtfsByChain, discoverIndexDtfsFromSubgraph, dtfCatalog, extractIndexDtfDeployedAddress, extractIndexDtfDeployedStakingTokenAddress, generateIndexDtfDeploymentNonce, getAccountPortfolio, getAccountPortfolioHistory, getAccountPortfolioTransactions, getAllProposals as getAllIndexDtfProposals, getDiscoverDtfs, getDtf, getFull as getFullIndexDtf, getFull as getIndexDtf, getActiveAuction as getIndexDtfActiveAuction, getIndexDtfApprovedRevenueTokens, getAssetList as getIndexDtfAssetList, getBasket as getIndexDtfBasket, getBasketSharesFromUnits as getIndexDtfBasketSharesFromUnits, getBasketSnapshot as getIndexDtfBasketSnapshot, getBasketUnitsFromShares as getIndexDtfBasketUnitsFromShares, getBasketWithPrice as getIndexDtfBasketWithPrice, getBidQuote as getIndexDtfBidQuote, getIndexDtfBidsEnabled, getBrand as getIndexDtfBrand, getIndexDtfCatalogEntries, getCompletedRebalance as getIndexDtfCompletedRebalance, getCompletedRebalances as getIndexDtfCompletedRebalances, getIndexDtfCurrentRebalance, getDelegates as getIndexDtfDelegates, getIndexDtfDeployApprovalAmount, getEffectiveRevenueDistribution as getIndexDtfEffectiveRevenueDistribution, getIndexDtfExposure, getGuardians as getIndexDtfGuardians, getIndexDtfHolders, getIndexDtfIssuanceState, getLatestAuction as getIndexDtfLatestAuction, getLegacyVoteLocks as getIndexDtfLegacyVoteLocks, getMandate as getIndexDtfMandate, getOptimisticGovernance as getIndexDtfOptimisticGovernance, getOptimisticProposalContext as getIndexDtfOptimisticProposalContext, getOptimisticProposalVoterState as getIndexDtfOptimisticProposalVoterState, getOptimisticTimelockRoles as getIndexDtfOptimisticTimelockRoles, getOptimisticVotes as getIndexDtfOptimisticVotes, getPastOptimisticVotes as getIndexDtfPastOptimisticVotes, getIndexDtfPendingFeeShares, getIndexDtfPlatformFee, getPrice as getIndexDtfPrice, getDtfPriceFromBalances as getIndexDtfPriceFromBalances, getPriceHistory as getIndexDtfPriceHistory, getPrices as getIndexDtfPrices, getProposal as getIndexDtfProposal, getProposalGovernanceAddresses as getIndexDtfProposalGovernanceAddresses, getProposalThrottleCharges as getIndexDtfProposalThrottleCharges, getProposalVoterState as getIndexDtfProposalVoterState, getProposalVotes as getIndexDtfProposalVotes, getProposals as getIndexDtfProposals, getProposerState as getIndexDtfProposerState, getRebalance as getIndexDtfRebalance, getRebalanceAuctions as getIndexDtfRebalanceAuctions, getIndexDtfRebalanceControl, getRebalances as getIndexDtfRebalances, getIndexDtfRedeemMinAmounts, getIndexDtfRevenue, getSelectorRegistryAllowedSelectors as getIndexDtfSelectorRegistryAllowedSelectors, getSelectorRegistryIsAllowed as getIndexDtfSelectorRegistryIsAllowed, getSelectorRegistryTargets as getIndexDtfSelectorRegistryTargets, getIndexDtfStatus, getIndexDtfStatuses, getTotalAssets as getIndexDtfTotalAssets, getTotalSupply as getIndexDtfTotalSupply, getIndexDtfTransactions, getVersion as getIndexDtfVersion, getVoteLockDao as getIndexDtfVoteLockDao, getVoteLockDaos as getIndexDtfVoteLockDaos, getVoteLockState as getIndexDtfVoteLockState, getVoterState as getIndexDtfVoterState, getTokenData, getTokenPrices, getTokenVolatilities, getTokensData, hashIndexDtfProposalDescription, indexDtfBasketSchema as indexDtfBasketProposalSchema, indexDtfBasketSchema, indexDtfBasketTokenSchema as indexDtfBasketProposalTokenSchema, indexDtfBasketTokenSchema, indexDtfBasketSettingsProposalSchema, indexDtfBasketSharesSchema as indexDtfBasketSharesProposalSchema, indexDtfBasketSharesSchema, indexDtfBasketUnitsSchema as indexDtfBasketUnitsProposalSchema, indexDtfBasketUnitsSchema, indexDtfCatalog, indexDtfDaoSettingsProposalSchema, indexDtfGovernanceChangesSchema, indexDtfSettingsProposalSchema, indexDtfV5WriteAbi, indexDtfV6WriteAbi, isSdkError, listIndexDtfs, prepareContractCall, prepareErc20Approval, prepareIndexDtfAddToAllowlist, prepareIndexDtfAddToBasket, prepareIndexDtfBasketApproval, prepareIndexDtfBid, prepareIndexDtfCancelProposal, prepareIndexDtfCloseAuction, prepareIndexDtfDeploy, prepareIndexDtfDeployAssetApproval, prepareIndexDtfDeployAssetApprovals, prepareIndexDtfDeployGoverned, prepareIndexDtfDeployGovernedPlan, prepareIndexDtfDeployPlan, prepareIndexDtfDeployStakingToken, prepareIndexDtfDeprecate, prepareIndexDtfDistributeFees, prepareIndexDtfEndRebalance, prepareIndexDtfExecuteProposal, prepareIndexDtfGovernorCancelProposal, prepareIndexDtfMint, prepareIndexDtfMintPlan, prepareIndexDtfOpenAuction, prepareIndexDtfOpenAuctionArgs, prepareIndexDtfOpenAuctionUnrestricted, prepareIndexDtfQueueProposal, prepareIndexDtfRedeem, prepareIndexDtfRelay, prepareIndexDtfRemoveFromAllowlist, prepareIndexDtfRemoveFromBasket, prepareIndexDtfRevokeOptimisticProposer, prepareIndexDtfSetAuctionLength, prepareIndexDtfSetBidsEnabled, prepareIndexDtfSetFeeRecipients, prepareIndexDtfSetLateQuorumVoteExtension, prepareIndexDtfSetMandate, prepareIndexDtfSetMintFee, prepareIndexDtfSetName, prepareIndexDtfSetOptimisticParams, prepareIndexDtfSetProposalThrottle, prepareIndexDtfSetRebalanceControl, prepareIndexDtfSetSelfFee, prepareIndexDtfSetTradeAllowlistEnabled, prepareIndexDtfSetTrustedFillerRegistry, prepareIndexDtfSetTvlFee, prepareIndexDtfSubmitOptimisticProposal, prepareIndexDtfSubmitProposal, prepareIndexDtfTimelockDelay, prepareIndexDtfTimelockExecuteBatch, prepareIndexDtfTimelockGrantRole, prepareIndexDtfTimelockRevokeRole, prepareIndexDtfUpdateTimelock, prepareIndexDtfVote, prepareIndexDtfVoteWithReason, prepareIndexDtfVoteWithReasonAndParams, prepareSelectorRegistryRegisterSelectors, prepareSelectorRegistryUnregisterSelectors, prepareVoteLockAddRewardToken, prepareVoteLockCancelLock, prepareVoteLockClaimLock, prepareVoteLockClaimRewards, prepareVoteLockDelegate, prepareVoteLockDelegateOptimistic, prepareVoteLockDeposit, prepareVoteLockDepositPlan, prepareVoteLockPoke, prepareVoteLockRemoveRewardToken, prepareVoteLockSetRewardRatio, prepareVoteLockSetUnstakingDelay, prepareVoteLockWithdraw, readVoteLockAllRewardTokens, readVoteLockAsset, readVoteLockBalanceOf, readVoteLockCheckpoint, readVoteLockClock, readVoteLockClockMode, readVoteLockConvertToAssets, readVoteLockConvertToShares, readVoteLockDelegates, readVoteLockDisallowedRewardToken, readVoteLockGetPastTotalSupply, readVoteLockGetPastVotes, readVoteLockGetVotes, readVoteLockLock, readVoteLockMaxDeposit, readVoteLockMaxMint, readVoteLockMaxRedeem, readVoteLockMaxWithdraw, readVoteLockNumCheckpoints, readVoteLockOptimisticDelegates, readVoteLockOptimisticVotes, readVoteLockPastOptimisticVotes, readVoteLockPreviewDeposit, readVoteLockPreviewMint, readVoteLockPreviewRedeem, readVoteLockPreviewWithdraw, readVoteLockRewardRatio, readVoteLockRewardTracker, readVoteLockTotalAssets, readVoteLockTotalSupply, readVoteLockUnderlyingAllowance, readVoteLockUnderlyingBalance, readVoteLockUnstakingDelay, readVoteLockUnstakingManager, readVoteLockUnstakingTargetToken, readVoteLockUnstakingVault, readVoteLockUserRewardTracker, resolveIndexDtfAlias, supportedChainIds, yieldDtfCatalog };
27138
+ export { CANCELLER_ROLE, DEFAULT_API_BASE_URL, DEFAULT_INDEX_DTF_DEPLOY_FLAGS, DEFAULT_RPC_URLS, INDEX_DTF_DEPLOYER_ADDRESS, INDEX_DTF_GOVERNANCE_DEPLOYER_ADDRESS, INDEX_DTF_SUBGRAPH_URL, OPTIMISTIC_PROPOSER_ROLE, SUPPORTED_CHAINS, SdkError, YIELD_DTF_SUBGRAPH_URL, buildIndexDtfBasketProposal, buildIndexDtfBasketSettingsProposal, buildIndexDtfDaoSettingsProposal, buildIndexDtfDeployFeeRecipients, buildInitialBasket as buildIndexDtfInitialBasket, buildIndexDtfSettingsProposal, buildIndexDtfStartRebalance, buildStartRebalanceArgs as buildIndexDtfStartRebalanceArgs, createDtfClient, createDtfSdk, createIndexDtfNamespace, createIndexDtfRef, createPortfolioNamespace, createWalletClient, decodeIndexDtfProposal, decodeIndexDtfProposalCalldatas, discoverIndexDtfs, discoverIndexDtfsByChain, discoverIndexDtfsFromSubgraph, dtfCatalog, dtfIndexAbi, dtfIndexGovernanceAbi, dtfIndexGovernanceOptimisticAbi, dtfIndexGovernanceProposalAbi, dtfIndexStakingVaultAbi, dtfIndexStakingVaultOptimisticAbi, extractIndexDtfDeployedAddress, extractIndexDtfDeployedStakingTokenAddress, generateIndexDtfDeploymentNonce, getAccountPortfolio, getAccountPortfolioHistory, getAccountPortfolioTransactions, getAllProposals as getAllIndexDtfProposals, getDiscoverDtfs, getDtf, getFull as getFullIndexDtf, getFull as getIndexDtf, getActiveAuction as getIndexDtfActiveAuction, getIndexDtfApprovedRevenueTokens, getAssetList as getIndexDtfAssetList, getBasket as getIndexDtfBasket, getBasketSharesFromUnits as getIndexDtfBasketSharesFromUnits, getBasketSnapshot as getIndexDtfBasketSnapshot, getBasketUnitsFromShares as getIndexDtfBasketUnitsFromShares, getBasketWithPrice as getIndexDtfBasketWithPrice, getBidQuote as getIndexDtfBidQuote, getIndexDtfBidsEnabled, getBrand as getIndexDtfBrand, getIndexDtfCatalogEntries, getCompletedRebalance as getIndexDtfCompletedRebalance, getCompletedRebalances as getIndexDtfCompletedRebalances, getIndexDtfCurrentRebalance, getDelegates as getIndexDtfDelegates, getIndexDtfDeployApprovalAmount, getEffectiveRevenueDistribution as getIndexDtfEffectiveRevenueDistribution, getIndexDtfExposure, getGuardians as getIndexDtfGuardians, getIndexDtfHolders, getIndexDtfIssuanceState, getLatestAuction as getIndexDtfLatestAuction, getLegacyVoteLocks as getIndexDtfLegacyVoteLocks, getMandate as getIndexDtfMandate, getOptimisticGovernance as getIndexDtfOptimisticGovernance, getOptimisticProposalContext as getIndexDtfOptimisticProposalContext, getOptimisticProposalVoterState as getIndexDtfOptimisticProposalVoterState, getOptimisticSelectors as getIndexDtfOptimisticSelectors, getOptimisticTimelockRoles as getIndexDtfOptimisticTimelockRoles, getOptimisticVotes as getIndexDtfOptimisticVotes, getPastOptimisticVotes as getIndexDtfPastOptimisticVotes, getIndexDtfPendingFeeShares, getIndexDtfPlatformFee, getPrice as getIndexDtfPrice, getDtfPriceFromBalances as getIndexDtfPriceFromBalances, getPriceHistory as getIndexDtfPriceHistory, getPrices as getIndexDtfPrices, getProposal as getIndexDtfProposal, getProposalGovernanceAddresses as getIndexDtfProposalGovernanceAddresses, getProposalList as getIndexDtfProposalList, getProposalState as getIndexDtfProposalState, getProposalState, getProposalThrottleCharges as getIndexDtfProposalThrottleCharges, getProposalVoterState as getIndexDtfProposalVoterState, getProposalVotes as getIndexDtfProposalVotes, getProposalVotingSnapshot as getIndexDtfProposalVotingSnapshot, getProposals as getIndexDtfProposals, getProposerState as getIndexDtfProposerState, getRebalance as getIndexDtfRebalance, getRebalanceAuctions as getIndexDtfRebalanceAuctions, getIndexDtfRebalanceControl, getRebalances as getIndexDtfRebalances, getIndexDtfRedeemMinAmounts, getIndexDtfRevenue, getSelectorRegistryAllowedSelectors as getIndexDtfSelectorRegistryAllowedSelectors, getSelectorRegistryIsAllowed as getIndexDtfSelectorRegistryIsAllowed, getSelectorRegistryTargets as getIndexDtfSelectorRegistryTargets, getIndexDtfStatus, getIndexDtfStatuses, getTotalAssets as getIndexDtfTotalAssets, getTotalSupply as getIndexDtfTotalSupply, getIndexDtfTransactions, getVersion as getIndexDtfVersion, getVoteLockDao as getIndexDtfVoteLockDao, getVoteLockDaos as getIndexDtfVoteLockDaos, getVoteLockState as getIndexDtfVoteLockState, getVoterState as getIndexDtfVoterState, getTokenData, getTokenPrices, getTokenVolatilities, getTokensData, hashIndexDtfProposalDescription, indexDtfBasketSchema as indexDtfBasketProposalSchema, indexDtfBasketSchema, indexDtfBasketTokenSchema as indexDtfBasketProposalTokenSchema, indexDtfBasketTokenSchema, indexDtfBasketSettingsProposalSchema, indexDtfBasketSharesSchema as indexDtfBasketSharesProposalSchema, indexDtfBasketSharesSchema, indexDtfBasketUnitsSchema as indexDtfBasketUnitsProposalSchema, indexDtfBasketUnitsSchema, indexDtfCatalog, indexDtfDaoSettingsProposalSchema, indexDtfGovernanceChangesSchema, indexDtfSettingsProposalSchema, indexDtfV5WriteAbi, indexDtfV6WriteAbi, isSdkError, listIndexDtfs, prepareContractCall, prepareErc20Approval, prepareIndexDtfAddToAllowlist, prepareIndexDtfAddToBasket, prepareIndexDtfBasketApproval, prepareIndexDtfBid, prepareIndexDtfCancelProposal, prepareIndexDtfCloseAuction, prepareIndexDtfDeploy, prepareIndexDtfDeployAssetApproval, prepareIndexDtfDeployAssetApprovals, prepareIndexDtfDeployGoverned, prepareIndexDtfDeployGovernedPlan, prepareIndexDtfDeployPlan, prepareIndexDtfDeployStakingToken, prepareIndexDtfDeprecate, prepareIndexDtfDistributeFees, prepareIndexDtfEndRebalance, prepareIndexDtfExecuteProposal, prepareIndexDtfGovernorCancelProposal, prepareIndexDtfMint, prepareIndexDtfMintPlan, prepareIndexDtfOpenAuction, prepareIndexDtfOpenAuctionArgs, prepareIndexDtfOpenAuctionUnrestricted, prepareIndexDtfQueueProposal, prepareIndexDtfRedeem, prepareIndexDtfRelay, prepareIndexDtfRemoveFromAllowlist, prepareIndexDtfRemoveFromBasket, prepareIndexDtfRevokeOptimisticProposer, prepareIndexDtfSetAuctionLength, prepareIndexDtfSetBidsEnabled, prepareIndexDtfSetFeeRecipients, prepareIndexDtfSetLateQuorumVoteExtension, prepareIndexDtfSetMandate, prepareIndexDtfSetMintFee, prepareIndexDtfSetName, prepareIndexDtfSetOptimisticParams, prepareIndexDtfSetProposalThrottle, prepareIndexDtfSetRebalanceControl, prepareIndexDtfSetSelfFee, prepareIndexDtfSetTradeAllowlistEnabled, prepareIndexDtfSetTrustedFillerRegistry, prepareIndexDtfSetTvlFee, prepareIndexDtfSubmitOptimisticProposal, prepareIndexDtfSubmitProposal, prepareIndexDtfTimelockDelay, prepareIndexDtfTimelockExecuteBatch, prepareIndexDtfTimelockGrantRole, prepareIndexDtfTimelockRevokeRole, prepareIndexDtfUpdateTimelock, prepareIndexDtfVote, prepareIndexDtfVoteWithReason, prepareIndexDtfVoteWithReasonAndParams, prepareSelectorRegistryRegisterSelectors, prepareSelectorRegistryUnregisterSelectors, prepareVoteLockAddRewardToken, prepareVoteLockCancelLock, prepareVoteLockClaimLock, prepareVoteLockClaimRewards, prepareVoteLockDelegate, prepareVoteLockDelegateOptimistic, prepareVoteLockDeposit, prepareVoteLockDepositPlan, prepareVoteLockPoke, prepareVoteLockRemoveRewardToken, prepareVoteLockSetRewardRatio, prepareVoteLockSetUnstakingDelay, prepareVoteLockWithdraw, readVoteLockAllRewardTokens, readVoteLockAsset, readVoteLockBalanceOf, readVoteLockCheckpoint, readVoteLockClock, readVoteLockClockMode, readVoteLockConvertToAssets, readVoteLockConvertToShares, readVoteLockDelegates, readVoteLockDisallowedRewardToken, readVoteLockGetPastTotalSupply, readVoteLockGetPastVotes, readVoteLockGetVotes, readVoteLockLock, readVoteLockMaxDeposit, readVoteLockMaxMint, readVoteLockMaxRedeem, readVoteLockMaxWithdraw, readVoteLockNumCheckpoints, readVoteLockOptimisticDelegates, readVoteLockOptimisticVotes, readVoteLockPastOptimisticVotes, readVoteLockPreviewDeposit, readVoteLockPreviewMint, readVoteLockPreviewRedeem, readVoteLockPreviewWithdraw, readVoteLockRewardRatio, readVoteLockRewardTracker, readVoteLockTotalAssets, readVoteLockTotalSupply, readVoteLockUnderlyingAllowance, readVoteLockUnderlyingBalance, readVoteLockUnstakingDelay, readVoteLockUnstakingManager, readVoteLockUnstakingTargetToken, readVoteLockUnstakingVault, readVoteLockUserRewardTracker, resolveIndexDtfAlias, supportedChainIds, yieldDtfCatalog };