@reserve-protocol/sdk 0.0.3 → 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.
- package/README.md +15 -9
- package/dist/index.d.mts +152 -10
- package/dist/index.mjs +2483 -1870
- 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
|
|
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
|
|
10381
|
-
else if (
|
|
10382
|
-
else if (
|
|
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
|
|
10386
|
-
else state.state = "
|
|
10387
|
-
else if (
|
|
10388
|
-
else if (
|
|
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 <
|
|
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 >=
|
|
10395
|
-
state.forVotesReachedQuorum = state.quorum;
|
|
10396
|
-
state.participationQuorumReached = proposal.forWeightedVotes.raw + proposal.abstainWeightedVotes.raw >=
|
|
10397
|
-
state.vetoReached =
|
|
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 =
|
|
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
|
|
10427
|
-
|
|
10428
|
-
|
|
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
|
|
10431
|
-
if (
|
|
10432
|
-
|
|
10433
|
-
return
|
|
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
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
|
|
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
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
|
|
15669
|
-
|
|
15670
|
-
|
|
15671
|
-
|
|
15672
|
-
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
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
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
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
|
|
15735
|
-
|
|
15736
|
-
return
|
|
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/
|
|
15740
|
-
const
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
}
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
|
|
15775
|
-
|
|
15776
|
-
|
|
15777
|
-
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
|
|
15783
|
-
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
}
|
|
15791
|
-
|
|
15792
|
-
function
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
}
|
|
15806
|
-
|
|
15807
|
-
function
|
|
15808
|
-
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
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/
|
|
23694
|
-
|
|
23695
|
-
|
|
23696
|
-
|
|
23697
|
-
|
|
23698
|
-
|
|
23699
|
-
|
|
23700
|
-
|
|
23701
|
-
}
|
|
23702
|
-
|
|
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/
|
|
23780
|
-
|
|
23781
|
-
{
|
|
23782
|
-
|
|
23783
|
-
|
|
23784
|
-
|
|
23785
|
-
|
|
23786
|
-
|
|
23787
|
-
|
|
23788
|
-
|
|
23789
|
-
|
|
23790
|
-
|
|
23791
|
-
|
|
23792
|
-
|
|
23793
|
-
|
|
23794
|
-
|
|
23795
|
-
}
|
|
23796
|
-
}
|
|
23797
|
-
|
|
23798
|
-
|
|
23799
|
-
|
|
23800
|
-
|
|
23801
|
-
|
|
23802
|
-
|
|
23803
|
-
|
|
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
|
-
|
|
23808
|
-
|
|
23809
|
-
|
|
23810
|
-
|
|
23811
|
-
|
|
23812
|
-
|
|
23813
|
-
|
|
23814
|
-
|
|
23815
|
-
|
|
23816
|
-
|
|
23817
|
-
|
|
23818
|
-
|
|
23819
|
-
|
|
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
|
-
|
|
23822
|
-
|
|
23823
|
-
|
|
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
|
-
|
|
23826
|
-
|
|
23827
|
-
|
|
23828
|
-
|
|
23829
|
-
|
|
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
|
-
|
|
23832
|
-
|
|
23833
|
-
|
|
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
|
-
|
|
23836
|
-
|
|
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
|
|
23839
|
-
const
|
|
23840
|
-
|
|
23841
|
-
|
|
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
|
|
23844
|
-
if (
|
|
23845
|
-
|
|
23846
|
-
|
|
23847
|
-
|
|
23848
|
-
|
|
23849
|
-
|
|
23850
|
-
|
|
23851
|
-
|
|
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
|
|
23855
|
-
|
|
23856
|
-
|
|
23857
|
-
|
|
23858
|
-
|
|
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
|
|
23861
|
-
|
|
23862
|
-
|
|
23863
|
-
if (
|
|
23864
|
-
|
|
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/
|
|
23868
|
-
|
|
23869
|
-
|
|
23870
|
-
|
|
23871
|
-
|
|
23872
|
-
|
|
23873
|
-
|
|
23874
|
-
|
|
23875
|
-
|
|
23876
|
-
|
|
23877
|
-
|
|
23878
|
-
|
|
23879
|
-
|
|
23880
|
-
|
|
23881
|
-
|
|
23882
|
-
|
|
23883
|
-
|
|
23884
|
-
|
|
23885
|
-
|
|
23886
|
-
|
|
23887
|
-
|
|
23888
|
-
|
|
23889
|
-
|
|
23890
|
-
|
|
23891
|
-
|
|
23892
|
-
|
|
23893
|
-
|
|
23894
|
-
|
|
23895
|
-
|
|
23896
|
-
|
|
23897
|
-
|
|
23898
|
-
|
|
23899
|
-
|
|
23900
|
-
|
|
23901
|
-
|
|
23902
|
-
|
|
23903
|
-
|
|
23904
|
-
|
|
23905
|
-
|
|
23906
|
-
|
|
23907
|
-
|
|
23908
|
-
|
|
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/
|
|
23968
|
-
const
|
|
23969
|
-
const
|
|
23970
|
-
|
|
23971
|
-
|
|
23972
|
-
}
|
|
23973
|
-
|
|
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
|
|
23976
|
-
const
|
|
23977
|
-
|
|
23978
|
-
|
|
23979
|
-
|
|
23980
|
-
|
|
23981
|
-
|
|
23982
|
-
|
|
23983
|
-
|
|
23984
|
-
|
|
23985
|
-
|
|
23986
|
-
|
|
23987
|
-
|
|
23988
|
-
|
|
23989
|
-
|
|
23990
|
-
|
|
23991
|
-
|
|
23992
|
-
|
|
23993
|
-
|
|
23994
|
-
|
|
23995
|
-
|
|
23996
|
-
|
|
23997
|
-
|
|
23998
|
-
|
|
23999
|
-
|
|
24000
|
-
|
|
24001
|
-
|
|
24002
|
-
|
|
24003
|
-
|
|
24004
|
-
|
|
24005
|
-
|
|
24006
|
-
|
|
24007
|
-
|
|
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
|
-
|
|
24020
|
-
|
|
24021
|
-
|
|
24022
|
-
|
|
24023
|
-
|
|
24104
|
+
governance: getProposalGovernance(governance),
|
|
24105
|
+
timelock: getProposalTimelock(timelock),
|
|
24106
|
+
targets,
|
|
24107
|
+
calldatas,
|
|
24108
|
+
description: description ?? ""
|
|
24024
24109
|
};
|
|
24025
24110
|
}
|
|
24026
|
-
function
|
|
24027
|
-
const decoded = tryDecodeCalldata(contractDecoder.abi, callData);
|
|
24028
|
-
if (!decoded) return;
|
|
24111
|
+
function buildCallPayload({ calls, governance, timelock }) {
|
|
24029
24112
|
return {
|
|
24030
|
-
|
|
24031
|
-
|
|
24032
|
-
|
|
24033
|
-
|
|
24034
|
-
|
|
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
|
|
24041
|
-
|
|
24042
|
-
|
|
24043
|
-
|
|
24044
|
-
|
|
24045
|
-
|
|
24046
|
-
|
|
24047
|
-
|
|
24048
|
-
|
|
24049
|
-
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
24054
|
-
|
|
24055
|
-
|
|
24056
|
-
|
|
24057
|
-
|
|
24058
|
-
|
|
24059
|
-
|
|
24060
|
-
|
|
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
|
|
24064
|
-
|
|
24065
|
-
|
|
24066
|
-
|
|
24067
|
-
|
|
24068
|
-
|
|
24069
|
-
|
|
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
|
-
|
|
24073
|
-
|
|
24074
|
-
|
|
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
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
|
|
24083
|
-
|
|
24084
|
-
|
|
24085
|
-
|
|
24086
|
-
|
|
24087
|
-
|
|
24088
|
-
|
|
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
|
|
24091
|
-
const
|
|
24092
|
-
|
|
24093
|
-
|
|
24094
|
-
|
|
24095
|
-
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24119
|
-
...
|
|
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
|
|
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
|
|
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
|
|
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
|
|
24648
|
+
limit,
|
|
24243
24649
|
offset: params.offset ?? 0,
|
|
24244
24650
|
...where ? { where } : {}
|
|
24245
24651
|
}
|
|
24246
24652
|
});
|
|
24247
|
-
return
|
|
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
|
|
24270
|
-
const
|
|
24271
|
-
const
|
|
24272
|
-
|
|
24273
|
-
|
|
24274
|
-
|
|
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
|
|
24287
|
-
if (
|
|
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
|
|
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
|
-
|
|
24314
|
-
|
|
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
|
|
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 [
|
|
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
|
|
24969
|
+
const publicClient = client.viem.getPublicClient(params.chainId);
|
|
24470
24970
|
const baseCall = {
|
|
24471
24971
|
address: governance,
|
|
24472
24972
|
abi: dtfIndexGovernanceAbi
|
|
24473
24973
|
};
|
|
24474
|
-
|
|
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: "
|
|
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.
|
|
24495
|
-
|
|
24496
|
-
|
|
24497
|
-
|
|
24498
|
-
|
|
24499
|
-
|
|
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
|
|
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
|
|
24557
|
-
|
|
24558
|
-
return client.
|
|
24559
|
-
|
|
24560
|
-
|
|
24561
|
-
|
|
24562
|
-
|
|
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
|
-
|
|
24567
|
-
|
|
24568
|
-
|
|
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
|
-
}
|
|
24574
|
-
}
|
|
24575
|
-
|
|
24576
|
-
|
|
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
|
|
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, 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, 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 };
|